Structs

Structs are like Classes, but completely different. Sorry 🙂 If you don’t know what a struct is or when you would use it, or if you don’t know the difference between passing by reference and passing by value, this lesson is for you.

Structs in Unity

Since this series is based on learning C# for Unity, let’s start by pointing out some places where you may have already been using Structs:

  • Vector2, Vector3 and Vector4
  • Rect
  • Color and Color32
  • Bounds
  • Touch

In particular, the various forms of Vector(2-4) are used all over. You will see them used to store everything from the position, rotation, and scale of a transform to the velocity of a Rigidbody, or the location of a touch or mouse click on the screen.

What is a Struct?

A struct is sort of like a compound data type. It looks very similar to a class, because you can define fields and methods in very much the same way. The following example defines a struct and class which are nearly identical:

public struct PointA
{
	public int x;
	public int y;
}

public class PointB
{
	public int x;
	public int y;
}

In this example, the only noticeable difference is in the keywords – “struct” instead of “class”. Some other differences between the two include:

  • A struct cannot inherit from a base type like a class can
  • Structs cannot have parameterless constructors
  • All of a structs fields must be assigned before leaving a constructor
  • structs are passed by value, whereas an instance of a class is passed by reference

The last point, to me, is the most important. There are many significant differences between “value” types and “reference” types that impact when, and how, you should use them.

Reference Types

When we say that an instance of a class is passed by reference, what is actually happening is that we get a “pointer” to the address in memory of the object and then pass “that” value around. This is important because an instance of a class can actually be very large, containing many fields and even other objects. In that sort of scenario, to copy and pass along the entire thing could negatively affect performance, and is why you only pass the address instead.

Reference types are allocated on the “heap” and are cleaned up by something called “garbage collection”. Garbage collection is a process that happens automatically but is slow and usually accounts for hitches in your game’s frame-rate. For this reason, you don’t want to frequently create objects and allow them to go out of scope. The following example is a big no-no:

// YOU SHOULD NOT DO THIS
void Update ()
{
	// Create an instanace of a class with local scope in the Update loop (called every frame)
	List<GameObject> objects = new List<GameObject>();

	// Imagine stuff is done with this list of objects (it is populated and iterated over etc)
	for (int i = 0; i < objects.Count; ++i) 
	{

	}

	// When the method ends the objects list goes out of scope and will at some point need
	// to be garbage collected
}

Value Types

When we say that something is passed by value, what is actually happening is that the variable is fully cloned / copied, and the copy is passed along while the original is left intact. Structs are value types and are passed by value. This means that structs are ideally small data structures.

Value types are allocated on the “stack” which means that their memory is easy to reclaim and they do not have an affect on “garbage collection”. Unlike the Update loop example with reference types, it is totally acceptable to create value types and allow them to go out of scope without fear of an impending slow-down or memory problem. For example, the following is totally acceptable:

// This is OK
void Update ()
{
	// Create a local variable to a value type - struct 
	Vector3 offset = new Vector3 (UnityEngine.Random.Range (-1, 1), 0, 0);

	// Do stuff with it
	Vector3 pos = transform.localPosition;
	pos += offset * Time.deltaTime;
	transform.localPosition = pos;

	// Your structs memory will be easily reclaimed as it goes out of scope here
}

Gotchas

It is tempting to try to use a struct like an instance of a class, but because it is passed by value, there are several gotchas that are often encountered. Consider the following example:

using UnityEngine;
using System.Collections;

public class Demo : MonoBehaviour
{
	public Vector3 v1;
	public Vector3 v2 { get; private set; }
	
	void Start ()
	{
		v1.Set(1,2,3);
		v1.x = 4;
		v2.Set(1,2,3);      // ** (Note 2)
		v2.x = 4;           // * (Note 1)
		Debug.Log(v1.ToString());
		Debug.Log(v2.ToString());
	}
}

* (Note 1) This sample won’t compile due to this line. You will get the error, “error CS1612: Cannot modify a value type return value of `Demo.v2′. Consider storing the value in a temporary variable”. The compiler is trying to protect you from a logical error (which I will explain in a minute), and is suggesting that you first get a new struct, modify that new struct, and assign it back.

** (Note 2) This line is far more dangerous because it will compile and run but does not appear to have worked.

If this code were to compile and run, you would see the following output:

(4.0, 2.0, 3.0)
(0.0, 0.0, 0.0)

This is NOT what you might have expected. So what’s going on? C# automatically creates a hidden backer property for ‘v2’. When you use the getter (by simply referencing ‘v2’) C# provides a copy of the backer, not the actual backer – remember that this is because structs are passed by value not by reference. In the line marked by Note 2, what is happening is that you get a copy of the backer, modify the copy in place, and then the information is immediately lost because it is not assigned back to anything.

The following example is similar – it illustrates how the concept of a reference type vs a value type is often overlooked and causes problems. Here we hold a reference to a list, which holds references to Vector3’s:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Demo : MonoBehaviour
{
	void Start ()
	{
		List<Vector3> coords = new List<Vector3>();
		coords.Add( new Vector3(0, 0, 0) );
		coords[0].Set(1, 2, 3);
		coords[0].x = 4; // error CS1612 (see above example and comment out this line to compile)
		Debug.Log(coords[0].ToString());  // Will be (0.0, 0.0, 0.0) - Not what you expected!
	}
}

In contrast, the following example will work as you expect (or at least as you would have expected before I started scaring / confusing you with the previous examples)

using UnityEngine;
using System.Collections;

public class Foo
{
	public Vector3 pos;
}

public class Demo : MonoBehaviour
{
	void Start ()
	{
		Foo myFoo = new Foo();
		myFoo.pos.Set(1, 2, 3);
		myFoo.pos.x = 4; // no compilation error
		Debug.Log(myFoo.pos.ToString()); // Will be (4.0, 2.0, 3.0) - As you expect!
	}
}

Why does this example work when the others don’t? The answer is because we have a reference to the ‘myFoo’ object – not a reference to the object’s field. The object holds the struct’s values directly (as a Field) and modifies it directly without a problem.

Had the Foo implemented its Vector3 as a property instead of as a field (even with a specified backing field), it would have been a problem – see the following example:

using UnityEngine;
using System.Collections;

public class Foo
{
	public Vector3 pos { get { return _pos; } set { _pos = value; } }
	private Vector3 _pos;
}

public class Demo : MonoBehaviour
{
	void Start ()
	{
		Foo myFoo = new Foo();
		myFoo.pos.Set(1, 2, 3);
		myFoo.pos.x = 4; // error CS1612 (see above example and comment out this line to compile)
		Debug.Log(myFoo.pos.ToString()); // Will be (0.0, 0.0, 0.0) - Not what you expected!
	}
}

Many of these problems are alleviated if you can get into the mindset of treating your structs as “immutable” (this means you never change the values of any fields), or actually make them immutable (if it is your struct).

Summary

In this lesson, we introduced the struct and compared when, where and why you would use one over a class. We showed some of the limitations and gotchas of structs, but also their benefits. Used correctly, structs are a very valuable and efficient tool to add to your programming arsenal.

Enums and Flags

We briefly mentioned the enum in our last lesson, so I felt like now would be a great time to cover it in greater depth. At the same time, we can expand on the topic and introduce Flags (bit masks). Some of this gets a bit deeper into the nerdy side of programming, but I will try to keep everything easy to understand. Continue reading

Saving Data

Let’s suppose you’re making a “complete” game. You want a title screen and everything. Your user can select the number of players or a difficulty setting, etc, and then… how do you pass the information on to the next scene? Or more importantly (and somewhat tricker) how can you save a game session and load it again later? Read along and I will show some of the options I like.

Static Persistance

To persist data from one scene to another can be as simple as saving data to a static variable. To demonstrate, we will need a bit of setup. Create two scenes, one called “Title” and one called “Game”. From the menu bar choose “File->Build Settings” and in the dialog you will need to use the “Add Current” button or drag and drop both scenes from the Project pane into the “Scenes In Build” list.

The following Data Manager class is a static class with a static variable, so it doesn’t need to be added to your scene, it will just “work” automatically. I make use of something called an “enum” which I haven’t talked about before. For now, you can think of an enum as an integer (because it can be cast to or from an integer – although it is actually its own ‘type’) where each entry is named to make your code more readable. “Easy” is like the integer value of ‘0’ and it counts up from there.

using UnityEngine;
using System.Collections;

public enum Difficulties
{
	Easy,
	Medium,
	Hard,
	Count
}

public static class DataManager
{
	public static Difficulties difficulty;
}

Add the following “TitleController” script as a component to the camera in the “Title” scene. This script is very simple – I used the legacy GUI to reduce setup time even further. All this script does is show buttons for each difficulty option, and one to begin playing the game. Whenever you select one of the buttons, a difficulty setting is set to a static variable in the DataManager class.

using UnityEngine;
using System.Collections;

public class TitleController : MonoBehaviour 
{
	void OnGUI ()
	{
		int yPos = 10;
		GUI.Label(new Rect(10, yPos, 200, 30), "Choose Difficulty");

		for (int i = 0; i < (int)Difficulties.Count; ++i)
		{
			yPos += 40;
			Difficulties type = (Difficulties)i;
			if (DataManager.difficulty == type)
				GUI.Label(new Rect(10, yPos, 200, 30), type.ToString());
			else if (GUI.Button(new Rect(10, yPos, 100, 30), type.ToString()))
				DataManager.difficulty = type;
		}

		yPos += 40;
		if (GUI.Button(new Rect(10, yPos, 100, 30), "Play"))
			Application.LoadLevel("Game");
	}
}

Add the following “GameController” script as a component to the camera in the “Game” scene. This script is also very simple. This time all I do is show which difficulty had been selected in the Title scene, and provide an option to Quit back to that scene.

using UnityEngine;
using System.Collections;

public class GameController : MonoBehaviour 
{
	void OnGUI ()
	{
		GUI.Label(new Rect(10, 10, 200, 30), DataManager.difficulty.ToString());
		if (GUI.Button(new Rect(10, 50, 100, 30), "Quit"))
			Application.LoadLevel("Title");
	}
}

With the Title scene open, press Play and note that the selection you make on the first screen is saved and is still available in the next scene. This works because static variables never go out of scope for as long as the program is running.

Singleton Pattern

Although a static class worked fine for the previous sample, it doesn’t offer as many architectural options as an object would (namely inheritance and polymorphism). A singleton is a slightly different variation, where by design you still only want a single instance of a class to ever exist, but you can have more control over the creation and lifespan of the object, can use subclasses, etc.

public class DataManager
{
	public static readonly DataManager instance = new DataManager();
	private DataManager() {}

	public Difficulties difficulty;
}

Here I have modified the DataManager class so that it is no longer static. I create a static readonly instance of the class (so that no other class can destroy or reassign it) and make the constructor private (so no other class can instantiate another object). This forces the singleton pattern to be used as I intended.

Reading and writing the difficulty setting would now need to be routed through the singleton instance. The following line shows an example of writing the value:

DataManager.instance.difficulty = type;

Unity “Singleton”

Sometimes you may find it convenient to use a MonoBehaviour based class for your persistence (in case you want to take advantage of Coroutines, etc.) In that case you can make GameObjects “survive” a scene change by using the method “DontDestroyOnLoad”. Note that this is also a handy way to make music play between scene changes.

public class DataManager : MonoBehaviour
{
	public static DataManager instance
	{
		get
		{
			if (_instance == null)
			{
				GameObject obj = new GameObject("Data Manager");
				_instance = obj.AddComponent<DataManager>();
				DontDestroyOnLoad(obj);
			}
			return _instance;
		}
	}
	static DataManager _instance;

	public Difficulties difficulty;
}

This version of the DataManager inherits from MonoBehaviour. The “Singleton” is created by something called “Lazy Loading” which means that as soon as any script calls the “instance” property, the class will look at its “getter” and determine whether or not it has created one. If not, it will create a new GameObject, assign the correct component, and make sure that the GameObject is marked properly so it won’t be destroyed when changing scenes.

This version is not as “safe” as the previous version, because there are ways that other scripts could cause your script’s GameObject to be destroyed, and even though your script itself would “survive” due to the static reference, the comparison to null will still return true because the equals operator is overridden by Unity (to take into account the GameObject), therefore another GameObject/Singleton would be created.

Furthermore, nothing stops another script from adding additional copies of this component to other GameObjects, although because I provided no setter, only one component at a time will ever be recognized as the main instance.

Player Prefs

All of the examples so far are good ways of taking data from one scene to another, however not a single one of them can persist data across multiple play sessions. In order to accomplish this task, you need to save data to “disk” in one way or another. Unity provides a convenient solution without even needing to understand how to create, read and write to files. This solution is called PlayerPrefs – see the docs here http://docs.unity3d.com/ScriptReference/PlayerPrefs.html

You can think of the PlayerPrefs as a Dictionary which only knows how to work with a “string” for the key and either an “int”, “float”, or “string” for the value. Unlike a generic dictionary, you can mix and match any combination of those values.

Here are some use cases:

// Store an integer value
PlayerPrefs.SetInt("Difficulty", 0);

// Retrieve an integer value (if it exists, or use a default of '0' otherwise)
DataManager.instance.difficulty = (Difficulties)PlayerPrefs.GetInt("Difficulty", 0);

Serialization

I mentioned serialization once early on – Unity utilizes serialization to store values of your components while in the editor. Unfortunately, a lot of the convenient options you might like to make use of such as a Binary or XML Serializer would require you to be able to use a Constructor – not an option with MonoBehaviour. Furthermore, object hierarchy, object references, and a desire to persist values in native Unity components all greatly complicate this process.

The method I prefer is manual serialization into JSON strings. Although it requires a bit more setup than some of the other routes, I feel that I have a lot more options and maintain full control over the process. I also don’t have to worry about “versioning” my data. I can remove data, add data, change data types, etc and it won’t cause the serializer to crash, because I can control the process of what and how I persist data. For example, I can check for the presence of keys and try casting data types where necessary. Additionally, because I am serializing to a JSON string I can very easily persist the result to PlayerPrefs, submit it to a server, or write it to a local file as desired.

I decided not to re-invent the wheel this time around, and used a public script for the JSON serialization instead. Grab a copy here, https://gist.github.com/darktable/1411710 and add it to your project.

Create a new scene called “Demo”. Create a Cube (from the menu bar choose “GameObject->3D Object->Cube”) and then create and attach the following “Monster” script (because aren’t monsters more fun to work with?)

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

public class Monster : MonoBehaviour
{
	public int HP;
	
	public virtual Dictionary<string, object> Save ()
	{
		Dictionary<string, object> data = new Dictionary<string, object>();
		data.Add("HP", HP);
		data.Add("X", transform.localPosition.x);
		data.Add("Y", transform.localPosition.y);
		data.Add("Z", transform.localPosition.z);
		data.Add("Prefab", gameObject.name);
		return data;
	}
	
	public virtual void Load (Dictionary<string, object> data)
	{
		HP = Convert.ToInt32( data["HP"] );
		float x = Convert.ToSingle( data["X"] );
		float y = Convert.ToSingle( data["Y"] );
		float z = Convert.ToSingle( data["Z"] );
		transform.localPosition = new Vector3(x, y, z);
	}
}

This script has a single field for “HP” – hit points. It doesn’t really do anything, but I want to show that we will be able to save both a local variable as well as values from the transform component. The Save and Load methods serve (hopefully) obvious purposes. They wrap the object’s data into a generic dictionary which the MiniJSON script knows how to serialize into a JSON string.

Create and attach the following script to the camera, and then connect the Cube as the reference for the monster field:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using MiniJSON;

public class Demo : MonoBehaviour 
{	
	public Monster monster;

	void Start ()
	{
		Load ();
	}

	void OnGUI ()
	{
		if (GUI.Button(new Rect(10, 10, 100, 30), "Randomize"))
			Randomize ();

		if (GUI.Button(new Rect(10, 50, 100, 30), "Save"))
			Save ();
		
		if (GUI.Button(new Rect(10, 90, 100, 30), "Load"))
			Load ();
	}

	void Randomize ()
	{
		monster.HP = UnityEngine.Random.Range(10, 100);
		float x = UnityEngine.Random.Range(-10f, 10f);
		float y = UnityEngine.Random.Range(-10f, 10f);
		float z = UnityEngine.Random.Range(-10f, 10f);
		monster.transform.localPosition = new Vector3(x, y, z);
	}
	
	void Save ()
	{
		string json = Json.Serialize( monster.Save() );
		Debug.Log(json);
		PlayerPrefs.SetString( "Monster", json );
	}
	
	void Load ()
	{
		string json = PlayerPrefs.GetString( "Monster", string.Empty );
		if (!string.IsNullOrEmpty(json))
		{
			var dict = Json.Deserialize(json) as Dictionary<string,object>;
			monster.Load(dict);
		}
	}
}

This script uses the legacy GUI like before, to either move the monster around, Save its data, or Load its data. I use the MiniJSON script we downloaded for serialization, and then save the result to PlayerPrefs for persistence sake.

Run the scene. Click Randomize to your heart’s content. At some point click Save and then randomize a few more times. Now click Load and see that the monster is moved back to the location it was in when you clicked Save. Stop the scene and then run it again. The monster should still be in the place where you saved it!

Although you technically know everything you need at this point, a few more issues may not be obvious. For example, what if you have a list of objects you want to save? Do you need to create a new player pref for each one? What if you want to use polymorphism or dynamically create and persist objects? These are each very normal architectural requirements so let’s handle them next.

For our first step, we will need to modify the Monster script so that the Save and Load methods are marked as “virtual”. This way we don’t have to completely re-write the Persistence code in every sub-class, instead, we only have to override the base method and append whatever new data the sub class provides.

I decided to create three subclasses of Monster: “BlueMonster”, “RedMonster”, and “GreenMonster” – I know, very imaginative class names right? The blue monster is listed below:

using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;

public class BlueMonster : Monster 
{
	public int water;

	void Awake ()
	{
		water = UnityEngine.Random.Range(10, 100);
	}

	public override Dictionary<string, object> Save ()
	{
		Dictionary<string, object> data = base.Save ();
		data.Add("Water", water);
		return data;
	}

	public override void Load (Dictionary<string, object> data)
	{
		base.Load (data);
		water = Convert.ToInt32( data["Water"] );
	}
}

The red and green monsters have identical implementations, except that I named the local variable “fire” and “earth” in the red and green monster scripts respectively. The goal here is to illustrate that you can’t use the same serialization across all three because they have “different” data sets. However, because they share a common base class, I can treat them all the same and will be able to save and load them without concern of their differences.

To help emphasize the differences between our monsters, Create three different prefabs in your project, one for each monster. You might make one with a sphere and one with a cube, but at a minimum color them all based on their name to help show that there is in fact a difference. Make sure and assign the specific sub class script to each type of monster and not the base class version of itself.

Now we need to modify the Demo script for our new functionality:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using MiniJSON;

public class Demo : MonoBehaviour 
{
	[SerializeField] GameObject[] prefabs;
	Dictionary<string, GameObject> mapping = new Dictionary<string, GameObject>();
	List<Monster> monsters = new List<Monster>();

	void Start ()
	{
		for (int i = 0; i < prefabs.Length; ++i)
			mapping.Add(prefabs[i].name, prefabs[i]);
		Load ();
	}
	
	void OnGUI ()
	{
		if (GUI.Button(new Rect(10, 10, 100, 30), "Add"))
			AddRandom ();
		
		if (GUI.Button(new Rect(10, 50, 100, 30), "Save"))
			Save ();
		
		if (GUI.Button(new Rect(10, 90, 100, 30), "Load"))
			Load ();
	}
	
	void Randomize (Monster monster)
	{
		monster.HP = UnityEngine.Random.Range(10, 100);
		float x = UnityEngine.Random.Range(-10f, 10f);
		float y = UnityEngine.Random.Range(-10f, 10f);
		float z = UnityEngine.Random.Range(-10f, 10f);
		monster.transform.localPosition = new Vector3(x, y, z);
	}
	
	void AddRandom ()
	{
		GameObject prefab = prefabs[ UnityEngine.Random.Range(0, prefabs.Length) ];
		Monster monster = Add(prefab);
		Randomize(monster);
	}
	
	Monster Add (GameObject prefab)
	{
		GameObject instance = Instantiate(prefab) as GameObject;
		Monster monster = instance.GetComponent<Monster>();
		monster.name = prefab.name;
		monsters.Add(monster);
		return monster;
	}
	
	void Save ()
	{
		var monsterData = new List<Dictionary<string, object>>( monsters.Count );
		for (int i = 0; i < monsters.Count; ++i)
			monsterData.Add( monsters[i].Save() );
		
		string json = Json.Serialize(monsterData);
		Debug.Log(json);
		PlayerPrefs.SetString( "Monsters", json );
	}
	
	void Load ()
	{
		Clear();
		string json = PlayerPrefs.GetString( "Monsters", string.Empty );
		if (!string.IsNullOrEmpty(json))
		{
			var monsterData = Json.Deserialize(json) as List<object>;
			for (int i = 0; i < monsterData.Count; ++i)
			{
				Dictionary<string, object> data = monsterData[i] as Dictionary<string, object>;
				string prefab = (string)(data["Prefab"]);
				Monster monster = Add ( mapping[prefab] );
				monster.Load( data );
			}
		}
	}
	
	void Clear ()
	{
		for (int i = monsters.Count - 1; i >= 0; --i)
			Destroy(monsters[i].gameObject);
		monsters.Clear();
	}
}

In this version, I no longer need the reference to the single Monster object. Since we are creating from a variety of monster types dynamically, I need references to the prefabs which we can Instantiate (line 8). These could have been obtained through Resources.Load, but this version is acceptable for now. Don’t forget to assign them in the editor.

Next I created a dictionary to map from a prefab name to the prefab itself (line 9) – that setup occurs in the Start method (lines 14-15). This step may seem a bit redundant, but I find the code a bit more readable (not to mention more efficient) than code which needs to search the array for a match (lots of string comparisons = SLOW).

I only slightly modified the OnGUI code – I replaced the button which moved the original Monster around, with a button to create new dynamic monsters which will already be moved around.

The “Randomize” method now requires a Monster parameter to be passed to it, since we want to be able to move any of our monsters with the same code.

The “AddRandom” method is new and picks one of the prefabs at random to create. It then makes sure the newly created monster is Randomized with the previously mentioned method.

The “Add” method takes a prefab as a parameter, from which it will instantiate a new monster. The monster script stores a reference to the name of the prefab which was used, so that we can use the same prefab again later when we need to actually persist the object. After instantiating the monster, we get a reference to the monster script (note that the GetComponent will work because our subclass versions of Monster are still Monster components) and add the component to a list so we can easily keep track of and manage everything we have created.

The Save method is similar to the previous version, but now we are creating a list of dictionary objects, instead of just a single dictionary. Our JSON serializer can serialize the whole thing as one string, so we can easily stick it in a PlayerPref as we did before. Note that I used a pluralized key this time for clarity.

The Load method changed a bit more, but not too bad. First I destroy any existing monsters before creating new ones according to the Save data. Note that this is easier than a Queue system, but a queue of reusable objects is more ideal in production code. The other big difference (besides working with a list of dictionaries) is that I get a reference to the prefab name within each entry and Instantiate a new object accordingly. Then I load the corresponding data on the spawned object. This is important because a Red Monster would fail to load correctly if it were passed a Blue Monster’s data and vice-versa.

Feel free to run the scene and give everything a try. Add a bunch of monsters, save the data (note that I also log a version of the JSON output to the console in case you want to inspect it) and then try stopping and starting a new session. All of your dynamically created monsters load back just fine!

Files

If you are saving lots of data, or if it makes sense to break your data up into smaller chunks which can be loaded at different times, then it may make sense to write to files instead of putting too much into PlayerPrefs.

Using the same example from before you can modify just the Save and Load methods as follows:

void Save ()
{
	var monsterData = new List<Dictionary<string, object>>( monsters.Count );
	for (int i = 0; i < monsters.Count; ++i)
		monsterData.Add( monsters[i].Save() );
	
	string json = Json.Serialize(monsterData);
	string filePath = Application.persistentDataPath + "/Monsters.txt";
	File.WriteAllText(filePath, json);
}

void Load ()
{
	Clear();
	string filePath = Application.persistentDataPath + "/Monsters.txt";
	if (File.Exists(filePath))
	{
		string json = File.ReadAllText(filePath);
		var monsterData = Json.Deserialize(json) as List<object>;
		for (int i = 0; i < monsterData.Count; ++i)
		{
			Dictionary<string, object> data = monsterData[i] as Dictionary<string, object>;
			string prefab = (string)(data["Prefab"]);
			Monster monster = Add ( mapping[prefab] );
			monster.Load( data );
		}
	}
}

Summary

In this lesson we covered a few methods of data persistence. First we covered temporary persistence through static classes, the Singleton design pattern, and Unity GameObjects which can survive scene changes. Then we explored how data can be persisted even across multiple play sessions via PlayerPrefs, JSON serialization and writing data to files. We even got a bit fancy by persisting a list of dynamically created polymorphic objects.

Physics

Physics aren’t a native language feature of C#, but Unity provides enough functionality for both 2D and 3D physics that the topic can easily justify its own lesson. In this post I will discuss methods of programmatically managing Rigidbodies, Colliders, and Triggers to name a few. Continue reading

Classes

Whether you remember or not, you’ve been creating classes all along in the previous lessons. I have commented briefly on various features of classes like inheritance and constructors, but there’s a lot more to cover. In this lesson, we will focus on those topics in greater depth and introduce a few more advanced topics like polymorphism, static constructors, abstract classes and static classes. Continue reading

Coroutines

A coroutine is a special way to make logic happen over time. I must admit, I never used coroutines until Unity, I had been using event-based programming in every other comparable scenario. However, coroutines are a quick and easy alternative which is definitely worth a look. In this lesson I will show how Unity works with coroutines, including various ways of yielding control and even linking coroutines together in order to have full control over time-based logic. In the end, I will also show how to work with coroutines natively for anyone curious about how they work.

The Unity Coroutine

A coroutine is really just a method with a return type of “IEnumerator”. One key difference is that you don’t simply “return” the data type like you would in a normal method. Instead, you “yield” a value which causes execution of the logic to pause in place – it can be resumed again later. Let’s take a look at a quick sample:

using UnityEngine;
using System.Collections;

public class Demo : MonoBehaviour 
{
	void OnEnable ()
	{
		StartCoroutine("DoStuff");
	}

	void OnDisable ()
	{
		StopCoroutine("DoStuff");
	}

	IEnumerator DoStuff ()
	{
		int value = 0;
		while (true)
		{
			yield return new WaitForSeconds(1);
			value++;
			Debug.Log("value:" + value);
		}
	}
}

Note that we must make sure that the “System.Collections” namespace is used, or you will get an error: “The type or namespace name ‘IEnumerator’ could not be found. Are you missing a using directive or an assembly reference?”

In order to use a coroutine with Unity, you use a method called “StartCoroutine”. We do this inside of the OnEnable method (line 8). StartCoroutine is overloaded to allow you to pass an “IEnumerator” or a string representing the name of the coroutine to start. In the example I used the later version, because only that version can be manually “stopped” using StopCoroutine. I show StopCoroutine in the OnDisable method (line 13) although its use in this example is unnecessary because all coroutines managed by unity would stop when the script was disabled regardless of how they are started. You should also keep in mind that you can “StartCoroutine” multiple times – even for the same method, which may often be unintentional behavior. You may want to set a flag letting you know when a coroutine is active, so you don’t start it multiple times, or alternatively use StopCoroutine before using StartCoroutine just to be safe.

Here are a few variations of calling StartCoroutine:

// Version 1, started by string (name of coroutine) - this version is compatible with StopCoroutine
StartCoroutine("DoStuff");

// Version 2, Same as Version 1 but with a parameter - note, the target method must be modified to accept a parameter
StartCoroutine("DoStuff", 5);

// Version 3, This version is started by passing the IEnumerator - you CANT use StopCoroutine
StartCoroutine(DoStuff());

// Version 4, Same as Version 3 but with parameter - note, the target method must be modified to accept a parameter
StartCoroutine(DoStuff(5));

The method “DoStuff” is our “Coroutine”. The first statement creates a local variable named “value” and initializes it to zero. Then we begin an “infinite loop” (a “while” loop which loops for as long as “true” is equal to “true” – which is always). Inside the loop we see our first “yield” statement (line 21) which instructs Unity that we wish to wait for one second. At this point execution of this method is suspended and will not continue until our wait condition is satisfied. After waiting for one second, Unity resumes the Coroutine right where it left off, even keeping in tact the values of your local variables (in this case “value”). We increment value by one, and print it to the console window.

If you attach this script to something in your scene, you will see a new value printed to the console once every second. Try it out.

Unity has provided several options for yielding your Coroutine including:

  • WaitForEndOfFrame
  • WaitForFixedUpdate
  • WaitForSeconds
  • WWW

Note that you can also use “yield return null;” to simply wait a frame or “yield break;” to abort a Coroutine early.

A More Fun Sample

Our first example was functional but pretty boring. Let’s make another version where we make an object move across a series of locations (waypoints). I could imagine this as a piece on a game board that moves from one tile to another along a specified path.

using UnityEngine;
using System.Collections;

public class Demo : MonoBehaviour 
{
	public Vector3[] waypoints;
	public float speed;

	void OnEnable ()
	{
		StartCoroutine(DoStuff());
	}

	IEnumerator DoStuff ()
	{
		for (int i = 0; i < waypoints.Length; ++i)
		{
			while (transform.position != waypoints[i])
			{
				yield return null;
				transform.position = Vector3.MoveTowards(transform.position, waypoints[i], speed * Time.deltaTime);
			}
		}
		Debug.Log("Complete!");
	}
}

In this version of the script I declared a public array of Vector3 which represents locations in world space that I want the object to move through. I also specified a speed variable which determines how fast the object will cover those distances.

I start the coroutine by passing the IEnumerator directly. Note that this is the preferred way to begin a coroutine unless you MUST be able to stop the coroutine using Unity’s StopCoroutine method (You could insert logic into the method to abort early as an alternative).

The Coroutine has two loops which are nested together. The outer “for” loop iterates over the array of Vector3 waypoints, and the inner “while” loop iterates for as long as it takes for the object to actually reach its desired location. Note that I wait a frame before updating the objects position. If there were no yield statement inside the while loop, the object would complete its path before showing any of the “steps” of its progress to the user. Once the path has been followed to its final point, a message prints to the console indicating that our job is complete.

Create a new scene, and add a Cube. Attach this demo script and make sure to assign values to each of our public properties via the inspector. For example your waypoints could be:
5,0,0
5,1,0
5,1,3
3,0,0
0,0,0

and your speed could be 1. Of course you can use any values you like, but your speed should at least be greater than zero.

Nested Coroutines

Sometimes you may find it convenient to nest coroutines so you can reuse bits of logic. Here is a sample which does that:

using UnityEngine;
using System.Collections;

public class Demo : MonoBehaviour 
{
	Vector3 m1 = new Vector3(-1, 0, 0);
	Vector3 m2 = new Vector3(1, 0, 0);
	Vector3 s1 = new Vector3(1, 1, 1);
	Vector3 s2 = new Vector3(0.5f, 0.5f, 0.5f);

	void Start ()
	{
		StartCoroutine(DoStuff());
	}

	IEnumerator DoStuff ()
	{
		while (true)
		{
			switch (UnityEngine.Random.Range(0, 2))
			{
			case 0:
				yield return StartCoroutine(Move ());
				break;
			case 1:
				yield return StartCoroutine(Scale ());
				break;
			}
		}
	}

	IEnumerator Move ()
	{
		Vector3 target = transform.position == m1 ? m2 : m1;
		while (transform.position != target)
		{
			yield return null;
			transform.position = Vector3.MoveTowards(transform.position, target, Time.deltaTime);
		}
	}

	IEnumerator Scale ()
	{
		Vector3 target = transform.localScale == s1 ? s2 : s1;
		while (transform.localScale != target)
		{
			yield return null;
			transform.localScale = Vector3.MoveTowards(transform.localScale, target, Time.deltaTime);
		}
	}
}

This sample created three Coroutines. The DoStuff coroutine is the “main” coroutine which is triggered by our Start method. The Move and Scale coroutines are triggered randomly within the loop and will play until they are completed before the original main coroutine continues.

If you used the scene from the previous demo and just updated the script, you would now see your cube move randomly back and forth as well as scale up and down.

The Native Coroutine

You may be curious about how to use Coroutine’s outside of Unity’s implementation. If so check out the following simple example:

using UnityEngine;
using System.Collections;

public class Demo : MonoBehaviour 
{
	IEnumerator trend;

	void Start ()
	{
		trend = TrendLine();
	}

	void Update ()
	{
		if (trend.MoveNext())
			Debug.Log((int)trend.Current);
	}

	IEnumerator TrendLine ()
	{
		int value = 0;
		while (true)
		{
			value += UnityEngine.Random.Range(-1, 2);
			yield return value;
			if (Mathf.Abs(value) >= 10)
				yield break;
		}
	}
}

On line 6 I created a variable to hold a reference to an IEnumerator called trend. I assign it to our coroutine method in Start (line 10).

I use Unity’s update loop to handle resuming the Coroutine from its yielded execution points, although you could have used any sort of event to do so. Resuming the coroutine occurs with the “MoveNext” method which returns a true or false based on whether or not execution was completed. If the coroutine was not complete, I print the return value of the coroutine which is accessed by the “Current” property (line 16).

In this Coroutine, I generate the value of an imaginary trend line and watch how it grows until it reaches a maximum value at which point the coroutine is complete. I achieved this effect by causing a value to either go up, down, or remain the same based on the result of the Random number which Unity generates.

Attach this sample to something in scene and run it and you will see a bunch of numbers generate in the console window. At some point the trend line should reach its maximum extent at either positive or negative 10 and the output will stop.

Summary

In this lesson we learned all about a language feature called a coroutine. We learned to start and stop coroutines managed by Unity. We covered coroutines with and without parameters, used different yield options, and nested coroutines together. Finally we explored how a coroutine works natively and handled stepping through a coroutine and retrieving its values manually.

Generics

Generics provide a way for you to make a kind of “template” out of your code that works the same across a variety of different data types. While it could be considered a more advanced topic, there are a few important benefits to using them early on. In this lesson I will introduce generic lists and dictionaries, and show how generics are used for specific Unity functionality like getting components and loading resources. If you’re feeling adventurous, feel free to check out some quick examples of custom generic methods and classes at the end. Continue reading

Loops

As a programmer you will frequently be working with a “group” of data (like an array which I presented in the previous lesson). Tic Tac Toe for example has a 3×3 board with nine total cells. If you were creating a method to operate on that group of data, such as to wipe a board clean for a new game, you wouldn’t want to have to manually apply the changes to each and every value in the array. Instead, you can write something called a loop, and let the computer handle the tedious work for you. In this lesson, we will create Tic Tac Toe, and show how loops can help make our code more elegant. Continue reading

Methods

The “action” part of programming comes from “calling” (also known as “invoking”) something called a “method” (also known as a “function”). In this lesson we will learn how to define and call our own methods, and then review a few more which are special to Unity. Finally, we will create our own “Magic 8 Ball” demo and cover how to link a method to the click of a button, and drive the output of a label. Continue reading