Programming Chapter 1

From Unify Community Wiki
Jump to: navigation, search

Contents

Getting Tooled

First we want to start a Unity project so we can test out all of our code. We're not going to explain all of the code yet, we just want to get familiar with Unity and C# scripts first. So go ahead and create a new Unity project named Tutorials or whatever you would like to call it (you don't need to include any assets). Next create a C# script by going to Assets -> Create -> C Sharp Script. Click on the newly create script and rename it to Script1. (For more information on creating assets see: Unity Manual "Creating Assets").

Once saved, you should notice an information icon down at the bottom of Unity saying that the script "Script1" could not be loaded because it's filename doesn't match. Open the file by double clicking it in Unity and change the name of the class on this line from:

public class NewBehaviourScript : MonoBehaviour {

to:

public class Script1 : MonoBehaviour {

Now save the file and you should notice the icon disappears. This is Unity building your scripts in the background when you save a code file. It compiles and then any errors or warnings are listed on the bottom. Now that the build is successful, go ahead and run the game (the play button). You should see a blue screen... and that's it. The script we created "Script1" doesn't do anything yet, so go ahead and add one line starting with "Debug.Log..." to the script right after void Start () {:

using UnityEngine;
using System.Collections;
 
public class Script1 : MonoBehaviour
{    
    void Start()
    {
        Debug.Log("Hello World!");
    }
}

Now Save the file (which should build without errors), and run again. Still nothing. This is because Unity doesn't execute scripts that are not attached to a game object (unless the script is called by some other script attached to a game object). So to see the script do something, click on GameObject -> Create Empty in the menu which creates an empty game object named... "GameObject". Click and drag the "Script1" that we created onto the "GameObject" and Run the program again. This time the screen is blue, but on the bottom panel you should see an information icon with the "Hello World!" text. If you click this icon and text it should bring up a Console window giving you more detail (like what script was called on what line). Don't worry about what all that code does at the moment, we'll get to that soon enough.

MonoDevelop

The sections with MonoDevelop are optional and will require the MonoDevelop application. We're going to use MonoDevelop in the examples to get some additional benefits to developing with C# as well as allowing us in the future to create our own libraries.

If you've downloaded and installed MonoDevelop go ahead and start it up as well. Go to File -> New Solution and select C# then Console Project, (you may need to type in a name for the solution), click Next then Finish. MonoDevelop does several things for us, it automatically creates a:

  • Solution - A container of related projects
  • Project - A library or executable that is to be created (our Console Project in this example)
  • References Folder - The libraries that a project uses/references
  • Resources Folder - Location to put resources for the proejct
  • Main.cs - The main file where program execution starts
  • AssemblyInfo.cs - The metadata about our assembly (application or library)

Now we want to add the file we just created in Unity to our MonoDevelop project. Right click on the project in the Solution Explorer on the left and select Add -> Add Files.... If you're using a one button mouse then you'll need to create a shortcut to this command as there is no menu item for it. You can do this by going to Edit -> Preferences then Preferences -> Key Bindings -> Project -> Add Files... and create a keyboard shortcut to it.

Once you've got the Add File dialog up, browse to the directory where you created your Unity project and go to Assets where you should see the file we created in Unity (Script1.cs). Click on the file and click Open. You should now be presented with a dialog of whether you want to copy the file, move the file, or create a link to it. To keep things simple just make a link to it (otherwise you would have to copy files back and forth to Unity and your MonoDevelop project).

Now we're ready to build. Click Project -> Build Tutorial1 (or click the icon with the building blocks). In the bottom section you should notice that you get an error stating that the type or namespace name UnityEngine could not be found. Why do we get this error in MonoDevelop but not in Unity? Because in Unity it already has references to a few DLL's that aren't in MonoDevelop by default. A DLL is a Dynamic Link Library, meaning it's a library that is linked in at runtime as opposed to a Static Library which is linked at build time. Build time happens when we build a project, while runtime happens when an executable starts running (it links in the library then). In .NET we only have dynamic libraries, so you don't need to worry about static libraries.

Anyways, back to our build error. To resolve it, we need to link (or add a reference) to the UnityEngine library to our project. To do this right click on References and select Edit References... (or add a Key binding for Preferences -> Project -> Edit References...). Next click on the .NET Assembly tab and browse to the directory where Unity is installed... Applications/Unity/Unity.app/Contents/Frameworks/Managed/. Next select the UnityEngine.dll and on the right click the button that says Add, now click OK and we're done. Go ahead and build again. The build should now be successful, but you will get some warnings. For now this is alright and we will deal later with the warnings.

Now that the build is successful, click Run (the icon with 2 gears), and you should get the output of "Hello World!" in the bottom console. Note that this Console is different from the Unity Console we output to earlier, this console is what you would see on the command line (Terminal.app on Mac). Alright, now that we basically know how to use the tools, Unity and MonoDevelop, it's time to jump into programming!

Nothing Doing

Comment Inside

A comment is a piece of text in code that does nothing:

// This is a comment

The '//' tells the compiler to ignore whatever follows it on the same line. There are also begin/end comments:

/*
  This comment extends
  over multiple lines.
*/
 
/* A begin/end comment on one line */

The '/*' is the start of the comment and the '*/' is the end. Everything in between is ignored by the compiler, so it will never execute any code if it is inside of a comment.

Make a Statement

A statement is basically a computer instruction. Semicolons in C# are for ending a statement, much like when we write sentences we end with a period. And just like you can have multiple sentences on one line, you can have multiple statements. For example:

;;;

That's three empty statements and legal code! An empty statement doesn't do anything, which is why it's called empty.

A block allows multiple statements to be written where one statement is allowed, using begin '{' block and '}' end block. Ready for some more do nothing code:

{ ;; }

That's valid code as well. You can also have a block inside a block (this is called nesting).

{ ; { ;; } { {} } }

Notice that for each starting '{' there is an ending '}' that matches it. This is required or else you will get an error from the compiler.

Code Break

OK, so lets try some of this out, fill in the Script1 so it looks like this:

using UnityEngine;
using System.Collections;
 
public class Script1 : MonoBehaviour
{    
    void Start()
    {
        /* This won't execute { ; but whatever is after the end comment will */ {
        { ;; }
    }
}

Test it out. Notice that Unity gives you an error about parsing. Parsing is a phase the compiler goes through to check grammar, see Parsing on Wikipedia for more. Go ahead an remove the "{" at the end of the comment line and save the file again, the error should disappear. Lets keep going.

Register Storage

What's your Type?

A data type is a way to tell the compiler what kind of information you want to store and how it should be analyzed. The most common types used in programming are numbers, letters and boolean (true/false). On top of this there are other predefined types in languages as well as user defined types (types that we can create). C# uses static typing, meaning that you always have to tell it what type you want your data to be. In contrast, UnityScript ("JavaScript") uses dynamic typing which means that you don't always have to tell it the type, it will dynamically try to figure out what type something is. Each has it's up and downsides, and you can find out more here (check out the Dynamic typing section).

Now I'm not going to list all the keywords and types, that's done in the references already, use them. But I'll try to explain enough so that when you look at those sites they will be useful. Here are some common types in C# (again, look at the references for all of them):

C# Size Range
bool N/A true or false
string N/A 0 to approximately 2 billion Unicode characters. Each character is 16 bits (two bytes).
int 4 bytes -2,147,483,648 to 2,147,483,647
float 4 bytes Approximate range is -1038 to 1038 with accuracy of about 7 digits. Can represent numbers as small as 10-44

OK, now what all is that saying. A boolean type (bool) can only store true or false (a 1 or 0 underneath). Why doesn't it have a size? Probably because the language designers decided to allow the implementors (C# is a standard and can be implemented by anyone), to be able to handle the type under the hood however they want for the sake of efficiency. Since this is a concise guide, ahem, I won't go into the gritty details and you don't need to worry about it. Now the string also doesn't have a size, but the reason for that is because it can grow and shrink as needed (for efficiencies sake). A string can store any text we want (must be a Unicode Character, but again a minor detail we don't need to worry about). The last two types are numbers, one for integers (-1, 0, 1, 2, ...), and one for decimals (-1.0, 0.0, 0.2, 1.445, ...). Why not just store everything as a decimal? Again, this is for efficiencies sake. A lot of choices made by languages have to have a balance between efficiency (sometimes caused by the underlying hardware) and usability. But don't sweat it, you don't need to remember all this. Just know there are different tools for the job... or rather different types for the job.

It's all Variable

A variable is a named location to store data. And much like the definition, the data at a location can be changed. Since the information can change it's good to think a little about how you name a variable. So lets get an example program going. Say we want to store a number, like the number of lives a player has.

// Bad name
int three;
 
// Good name
int playerLives;

When we declare a variable it's called a declaration statement, and declaration statements require a proper ending semicolon ';'.

The name 'three' can be bad in this instance because while it may be the value we want to store, this is just the name for programmers to use, not the value. And since later the value can change (thus variable), it doesn't make sense to have a name three storing a value of one when the player has lost two lives!

Now the above variables are all well and good, but what information are they storing since we didn't tell it what to store? The answer is whatever the language uses for the default. You can find the default storage for types in the language references. Now sometimes the default value isn't what we want, so we may want to initialize the value ourselves by telling the variable what to store. It's usually a good idea to initialize variables.

// Just use the good name, set the initial value to 3
int playerLives = 3;

In this example we store the integer 3 in our variable. The '=' is an assignment operator, it assigns the value on the right to the variable on the left. A variable in most languages usually has to start with an alpha character or an underscore (there are a few other characters allowed as well that vary by language), can only contain alpha characters, numbers, or underscores, can't contain spaces, and in the case of C# is case sensitive (languages like BASIC are not). So a variable named 'playerLives' is different from 'PlayerLives'.

Staying Constant

A constant is a fixed value. Unlike a variable it is constant (doesn't change). The '3' used for the player lives above is a constant. A constant cannot be assigned a value, it's constant so it can't be changed. We've only looked at numbers so far, so lets look at a string.

string playerName = "Super Player";

Here the string "Super Player" is a constant. The variable playerName (a string type), gets assigned the value of "Super Player". You can also make a variable constant. This is useful if you want to use the same value many places, but it should only be changed in one place:

const string defaultPlayerName = "New Player";
string playerName = defaultPlayerName;

The first line decalares a constant variable, if you try to assign another value to it you will get an error. Next the player name is set to the constant string, so playerName is now "New Player".

Code Break

Lets test out some types in Unity now. You can create a new script, or just edit Script1 we already created.

using UnityEngine;
using System.Collections;
 
public class Script1 : MonoBehaviour
{    
    void Start()
    {
        // Some game stuff
        bool isAlive = true;
        int numberOfLives = 3;
        float money = 10.0;
        string message = "Hello";
    }
}

Save an run and... oops, you get an error that the compiler can't implicitly convert a type of double to float and that we should add the suffix "f". What? Well C# is statically typed and type safe, meaning by default it won't automatically convert types without a cast. But where's the double? All decimal numbers are double by default (in case you didn't realize, double is a decimal type, but it's larger than float). Since we're using a constant number "10.0", it's type is a double, but we're setting our variable money which is a float to that value, this is an error. This can be fixed in two ways, one is casting:

float money = (float)10.0;

This is not the same thing as conversion. Casting just makes the compiler read the type differently, and it doesn't work for all types (you can't cast a constant number 10.0 to a string). The second way to fix the problem is to use what the compiler hinted at, add the suffix "f" to create a literal:

float money = 10.0f;

Save now and our error should disappear. A suffix is the best way to create a constant numeric of a type that is not the default.

What's the Scope?

Scope is the range that a variable exists in. Once a variable is declared, you can't declare it again in the same scope.

int playerLives = 3;
 
// Remember, this will never get executed since it's in a comment.
// But if you took off the comment below you'd get an error because you defined the variable twice.
// int playerLives = 2;
 
// Change the value like this
playerLives = 2;

Scope is defined in a block, remember those? Also remember that a block can be nested in another block. A nested block inherits all of the variables inside it's parent block, but the parent can't redefine a variable that's declared in a child. And when variables go out of scope they are no longer defined.

int playerLives = 3;
 
{
    // This is a nested block so we don't redefine the variable, we just use it
    playerLives = 2;
 
    // We can define the same name in separate blocks though
    int playerAge = 18;
}
 
{
    // Same variable name as above, but in a different scope
    int playerAge = 16;
}
 
{
    // Taking the comment off this will give an error,
    // since variables only exist in the scope they were defined
    // playerAge = 10;
}
 
// This will also error if uncommented since the variable is not in this scope (undefined)
// playerAge = 8;
 
// And this will error if uncommented because a child has already defined this variable
// int playerAge = 5;

Recap

These are the things that you should have learned:

  • An empty statement is just a semicolon ';', and does nothing.
  • A block '{ }' allows multiple statements to be written where one is allowed.
  • A comment is ignored by the compiler and never seen.
    • '//' comments everything after it on the same line.
    • '/*' and '*/' begin and end a comment.
  • A data type tells the compiler what type of information to store.
    • C# uses static typing, meaning a data type is always required.
  • A variable is a named location to store data.
    • A variable name:
      • Starts with a alpha character or underscore (possibly others depending on the language).
      • Can only contain alpha characters, numbers, or underscores (again possibly others).
      • Can't contain spaces.
      • Is case sensitive.
  • A declaration statement (declaring a variable) ends with a ';'
  • An assignment operator '=' assigns a value on the right to a variable on the left.
  • A constant is a fixed value.
  • A scope is the range that a variable exists in.
    • The same variable cannot be declared twice in the same scope.

Example-1 (Hello World)

In this section we are going to put what we have learned into practice. We will try to do a small game in every example, but for this example we will just get Unity to display a message to us. The message... Hello World!!!

We'll use our project we already created in Unity. To start off we are going to create a folder (a good habit) to put our files in. So create a folder asset named Example-1 Assets Next, create a script asset in this folder (C Sharp Script), and name it HelloWorld. Then open the file and put the following code in:

using UnityEngine;
using System.Collections;
 
public class HelloWorld : MonoBehaviour
{
    // Our message variable to display, initialize with "Hello World!"
    public string message = "Hello World!";
 
    // Unity specific, code in here is used to display GUI widgets
    void OnGUI()
    {
        GUILayout.Label(message);
    }
}

All we added was two comments, a variable named "message" (with a value of "Hello World!"), and an OnGUI function with a GUI label. Don't worry about how they work just yet, we'll get to that in another chapter. Now save the scene in your "Example-1 Assets" folder as "Example-1". OK, go ahead and run the example!

Hmm, nothing happened and all you see is a blue screen. Remember we need to attach our script to a game object, so do as before creating an empty game object and attaching our script to it. In the Inspector View you should see a new HelloWorld section added, having a property named "Script" and "Message". Yes, that's the message variable coming from our code with a default value of "Hello World!". You can change this later, but for now try running the program again.

Congratulations! You should now have a GUI Label in the upper left displaying "Hello World!". Now just for the fun of it, stop program, change the Message value in the inspector to Hello and then your name. Now run the program again. The default value we gave our variable in code is now overridden by the value we used in the editor, We're making progress...


Programming Index : Previous Chapter : Next Chapter

Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox