If you followed along from the first part of this series you should be up to speed on how the Unity IDE works. In this post we will dig deeper into the code side of things. I am a big fan of C#, and while Unity Script is useful, eventually you will need a little more flexibility in your code. So, to help you along, I thought it would be valuable to write a quick primer on working with C# in Unity, as well as some of the most common APIs you will be using when we build our game.
In order to code in Unity you will need to pick an external editor since Unity doesn’t have one built in. By default, Unity ships with MonoBuilder, but you can just as easily switch it out for something a little more robust, such as Visual Studio if you are doing your development on Windows. Simply go into the Edit > Preferences menu and change the path to the external editor.
Once you have picked an editor you like, you are ready to start coding. In this post, I will be showing the code from Visual Studio, but MonoDeveloper will work similarly to Visual Studio but on Windows and Mac.
C# is a strongly typed language and is very similar to Java or ActionScript 3. If you have some background in JavaScript, it should feel familiar as well. Let’s take a look at the basics of the language. To start with, we will look at variables and lists, which are the building blocks of any language. To make a variable, simply declare it, like so:
var name = “Jesse Freeman”;
While C# is a typed language, it supports type inference, meaning that when you declare a variable you don’t always have to define the type. There are a few primitive types you should know about:
string name = “Jesse Freeman”; int age = 34; bool alive = true;
When it comes to numbers, you should also understand more complex types, such as Float:
float speed = 4f;
Notice that we use the f suffix for our float. Floats are numbers that contain decimals and are used for more granular positioning within the game world, as well as in the built-in physics engine. Ints are useful for whole numbers where you don’t need to perform calculations that would generate fractions, such as a player’s health. You should always be aware when using Int, Float, or other number types because you may be forced to cast it to a specific type in order to perform the calculation and you may incur a performance penalty. Here is an example:
float example = (float)age * speed;
You can learn more about the different types in the C# reference docs at http://bit.ly/1bwLAKW. The next set of building blocks is Array and List. An Array is collection of multiple variables, usually of the same type.
var stringArray = new string[2];
In C#, Array are fixed meaning you can’t alter their length. You can modify its contents via their position in the Array itself. The position is an id, which represents a unique number for each location in the Array. In C#, arrays start at 0.:
stringArray[0] = “Jesse”; stringArray[1] = “Freeman”;
You can access values in an Array by their index just like we modified it. Here is how I would create a string with my full name from the above Array:
var name = stringArray[0]+” “+stringArray[1];
Unity also supports Lists as part of the C# library. In order to use this, you will have to import its package (System.Collections.Generic) at the top of your script, which I will show you how to do later on. For now, here is an example of a list:
List<int> listOfInts;
This is what we would call a generic List. The term generic refers to a dynamic type we can assign at runtime. Generics are a core part of the language, and something you should get familiar with as you gain more experience coding in C#. In this example, we can create a list with a type of Int. Now this generic list can contain whole numbers. For performance, you will want to use lists over arrays when you don’t know the exact size of the data and expect to be adding or removing values at runtime. An Array by contrast has a set number of items you can have in it and shouldn’t attempt to modify the length at runtime.
The last data object I want to talk about is a vector. Unity makes use of a Vector3, but now with the addition of the 2D workflow, they now rely on Vector2D a lot more. Here are examples of both:
var v3 = new Vector3(0,0,0); var v2 = new Vector2(0,0);
Vectors allow you to store 3D or, in this case, 2D points in space so you can access the value of x, y, and z from the vector. Here is an example:
Debug.Log(v3.x); // will output 0
One quick note is that you see I am calling Debug.Log. This will output the value to the console window.
This is similar to most other languages, such as JavaScript’s console.log and ActionScript’s trace. It’s also the first step in debugging your apps if you ever need to see the value of an object or property.
C# takes full advantage of classes, interfaces, and a host of other ways of packaging up code for reusability. Unity itself is built on a very easy-to-grasp composition system, which it favors over inheritance. Let’s look at how to make a simple class. Go to the Create menu and select a new script.
As you begin to create a new script, you will notice you can select from the three built-in languages. Select C# and call the script HelloWorld.
Unity will stub out the code you need for your class for you. Here is what it will look like:
using UnityEngine; using System.Collections; public class HelloWorld : MonoBehaviour { // Use this for initialization void Start () { } // Update is called once per frame void Update () { } }
As you can see, you won’t need to memorize how to create a class from scratch, so I will simply focus on two main parts of the script: the import block and the methods. By default, each new class extends from MonoBehavior. There are numerous methods you can take advantage of, but we’ll start with the first two: Start and Update.
Let’s go back to our previous example of a generic list. While this isn’t the traditional way of doing a Hello World example, I’ll be able to show off in a little more detail what it is like to import external libraries, create properties on a class, and output that to the console window. To start, look at the top of the class at the import statement and add the following:
using System.Collections.Generic;
Now, just before the Start method, we are going to add a property. Properties are variables that are scoped to the instance of the class itself. That is a fancy way of saying that anything inside a block of code will have access to its contents. Depending on how we declare the property, other classes will have access to it as well. C# supports private and public variable denotations. If you don’t declare one, it will automatically default to private. Add the following property above our Start method:
public List displayText;
Now, in our Start method, add the following:
displayText.Add("Hello"); displayText.Add("World");
Now we need a way to display this text. Add the following to the Update method:
Debug.Log(displayText[0] + “ “ + displayText[1]);
Here you can see we are using the Debug.Log method again, and we are accessing the first and second values of our list. It’s important to note that arrays and lists are 0 based in C# just like Java, AS3, and JS. Now we have a script that will output Hello World to the console tab on each frame, but we don’t have a place to put it. Go back to the Scene and select our camera. From here, scroll down to the bottom of the Inspector panel and select Add Component. Now select our HelloWorld script and it will attach itself to the camera.
Now, if you run the game and look at the Console tab, you will see Hello World outputted on each frame.
While this is a simple example, let’s do something a bit more interesting. Go back into your script and let’s have the camera scroll to the right. The camera is a GameObject just like any other primitive you add to the Scene via the Create menu. All of these GameObjects share some common properties, with position, size, and scale being just a few of them. Also, all of these GameObjects share the same API we are taking advantage of right now, which are the Start and Update methods. Let’s look at how we can programmatically move the camera. To get started, let’s add a new property called:
public float speed = 2f;
Next we’ll want to replace our Hello World Debug.Log call with the following:
transform.Translate(new Vector3(speed, 0, 0) * Time.deltaTime);
As you can see, we have taken the transform position property and are modifying it with a new Vector3 that contains our speed value and is multiplied by the Time.deltaTime. If you simply increased the x position by speed, you are not taking into account any slowdowns in the game itself. By using the delta between each frame, you are able to keep your movement consistent from frame to frame, regardless of dips in the frame rate. This isn’t a magical formula; all it means is that your GameObject will move at the desired distance over time. So if the frame rate drops, movement will look jerky but won’t slow down or speed up as the FPS naturally fluctuates based on other things going on in the game.
If you run the game, you will see the camera move. It will appear like the box that we created earlier is simply scrolling off the left side of the screen. Stop the game and take a look at the camera’s Inspector panel. If you scroll down to the script area, you will see we now have a new input field called Speed we can alter.
This is an important concept in Unity. Basically, any public property on a script can be edited from the IDE in the Inspector window. So, while it’s important to create default values for your properties, just know that you can alter those values on an instance-by-instance basis, and even temporarily at runtime when you are debugging. This is incredibly powerful and something we will be taking advantage of later on. Not only does this work with simple properties, such as Strings, Numbers, and Booleans, but it also works with collections, such as Arrays and Lists.
If you remember back to our first example, we had a list called displayText, which we also made public. You should see it in the Inspector panel as well, but the value is hidden. Simply click on the arrow next to its property name. You can even add new items to it by changing the Size value.
So, at this point, you should have a basic concept of how scripting works in Unity. Everything we covered here will be re-introduced in the following chapter. There is just one last thing I want to cover, which is how to think through scripts for GameObjects.
If you come from a traditional computer science background or have worked with other object-oriented programming languages before, you may be familiar with the argument on composition over inheritance. One of the cornerstones of OOP languages is the concept of polymorphism. While inheritance plays a large role in game development, Unity strives for the use of composition as much as possible. I consider scripting in Unity to follow the decorator and component design pattern. Each script adds additional functionality to your GameObject, but they are mostly self-contained. While some scripts rely on others to function, as we will see in the game we end up building, we really strive to create small, reusable blocks of code that can be applied to multiple GameObjects. When put together, each of these smaller scripts build up to a greater set of logic that builds up the functionality of each GameObject. While inheritance is possible, I strongly recommend thinking through composition as a means to not only create more modular, self-contained code but to also separate and encapsulate independent game logic. This kind of thinking is critical when it comes to grasping the true power of creating scripts in Unity.
By now I am sure you are itching to get into more coding, so start playing around with some of the great tutorials out there on Unity. We’ll continue to add new posts about Unity, especially with working with the new 2D workflow, over the next few months so make sure you keep checking back.
Also, don’t forget that to checkout Amazon’s GameCircle plug-in for Unity to help you integrate cross-platform leaderboards, achievements, and game data synchronization. The plug-in works on iOS, Android, and Fire OS plus with the built-in Whispersync for Games component you can back up all of your user’s game data to the cloud across all three platforms. You can now download it from the Scripting/Integration section of the Unity Asset Store.
Additional Resources
-Jesse Freeman (@JesseFreeman)