How to use Events in Unity 5

I wrote about Events a few years back. While the post is alright at covering the functionality behind the scenes, a much more straightforward approach is better most of the time.

pexels-photo (1)

Action!

.NET has the Action delegate built-in that will be enough for 90% of Event use cases and looks very neat. Actions can have 0 or more parameters so they’re very flexible.
MSDN documentation for Action<T>

A code example illuminates this the best so here’s one tha that shows all the basic operations of an Event; adding, removing, firing and receiving events.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    // Events are declared as generic Action delegates. They can have 0 or more parameters.
    public Action<int, Vector3> OnEnemyHit;
 
    // Mock-function to add a new listener. Usually you would add this on Start() for example
    public void AddListener(){
        OnEnemyHit += EnemyHit;
    }
    
    // Mock-function to remove a listener.
    public void RemoveListener(){
        OnEnemyHit -= EnemyHit;
    }
 
    // Triggering the event
    public void Update(){
        if(enemy.wasHit) {
            if(OnEnemyHit != null){
                OnEnemyHit(enemy.id, enemy.position);
            }
        }
    }
 
    // Listener
    public void EnemyHit(int enemyID, Vector3 hitPosition){
        Debug.Log("Hit enemy: " + enemyID);
        Debug.Log(hitPosition.ToString());
    }
	// Events are declared as generic Action delegates. They can have 0 or more parameters.
	public Action<int, Vector3> OnEnemyHit;

	// Mock-function to add a new listener. Usually you would add this on Start() for example
	public void AddListener(){
		OnEnemyHit += EnemyHit;
	}
	
	// Mock-function to remove a listener.
	public void RemoveListener(){
		OnEnemyHit -= EnemyHit;
	}

	// Triggering the event
	public void Update(){
		if(enemy.wasHit) {
			if(OnEnemyHit != null){
				OnEnemyHit(enemy.id, enemy.position);
			}
		}
	}

	// Listener
	public void EnemyHit(int enemyID, Vector3 hitPosition){
		Debug.Log("Hit enemy: " + enemyID);
		Debug.Log(hitPosition.ToString());
	}

As you can see it’s a very simple system so there’s not much to say. Other than use it!

Using Stopwatch to benchmark your heavy performance code

Stopwatch is a accurate and super simple utility class included in .NET that can be used for benchmarking your heavy performance code, like sorting a big list or some large calculations.

1
2
3
4
5
6
7
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();
 
// Run heavy duty code...
 
stopwatch.Stop();
Debug.Log(stopwatch.ElapsedMilliseconds + " ms elapsed in running heavy duty code.");
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start();

// Run heavy duty code...

stopwatch.Stop();
Debug.Log(stopwatch.ElapsedMilliseconds + " ms elapsed in running heavy duty code.");

Use C# Object Initializers

They make code much more readable than constructors. Use empty constructors and public getters/setters or public properties when you have a lot of properties you want to initialize. Compare edge2 where we insert all the variables in the constructor with the object initializer below it. Once you have more than three parameters passed in, keeping the constructor in order becomes a pain. For example changing some parameters to be optional means you have to move them so that they’re after non-optional parameters. With object initializers you can do them in any order and define yourself any time which properties should get initialized.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        // Lame old constructor
        Edge edge2 = new Edge(new Center(), new Center(), 5, 0, "edge_01", "edge_02", 7, false);
 
        // Cool and attractive object initializer
        Edge edge = new Edge()
        {
            leftCorner = new Center(),
            rightCorner = new Center(),
            name = "edge_01",
            neighborName = "edge_02",
            index = 5,
            river = 0,
            height = 7,
            isVisible = false
        };
        // Lame old constructor
        Edge edge2 = new Edge(new Center(), new Center(), 5, 0, "edge_01", "edge_02", 7, false);

        // Cool and attractive object initializer
        Edge edge = new Edge()
        {
            leftCorner = new Center(),
            rightCorner = new Center(),
            name = "edge_01",
            neighborName = "edge_02",
            index = 5,
            river = 0,
            height = 7,
            isVisible = false
        };

Unity Bitmap Drawing API for textures – open source

I just released one of my side-side-projects as open source, Bitmap Drawing API extension methods for Unity 3D’s Texture2D class. This is also coming to the Asset Store early next week.

Get it from GitHub: https://github.com/ProtoTurtle/UnityBitmapDrawing

Get it from the Asset Store: (coming in a few days)
What is it?
By default, Texture2D only provides the methods SetPixel and GetPixel (and SetPixels and GetPixels). This library extends that functionality with useful basic drawing operations. It outputs pixel perfect and not anti-aliased bitmaps.

1
texture.DrawLine(new Vector2(0,0), new Vector2(100,200), Color.red);
texture.DrawLine(new Vector2(0,0), new Vector2(100,200), Color.red);

x = 0, y = 0 is the top left corner
This library uses the convention of having the left top corner of the bitmap be the 0, 0 position. By default, Texture2D uses the bottom left corner convention which can be confusing for bitmap operations.

Extension Methods
ScreenShot
C# Extension Methods work in a way that adds methods to a existing class. To start using this, you only need to include the namespace:

1
using ProtoTurtle.BitmapDrawing;
using ProtoTurtle.BitmapDrawing;

Your Texture2D instances will then have all the new methods available.

Features

  • DrawPixel(position, color) – Draws a pixel but with the top left corner being position (x = 0, y = 0)
  • DrawLine(start, end, color) – Draws a line between two points
  • DrawCircle(position, radius, color) – Draws a circle
  • DrawFilledCircle(position, radius, color) – Draws a circle filled with a color
  • DrawRectangle(rectangle, color) – Draws a rectangle or a square
  • DrawFilledRectangle(rectangle, color) – Draws a rectangle or a square filled with a color
  • FloodFill(position, color) – Starts a flood fill of a certaing at the point

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using ProtoTurtle.BitmapDrawing;
 
// ...
 
Texture2D texture = new Texture2D(1024, 1024, TextureFormat.RGB24, false, true);
texture.filterMode = FilterMode.Point;
texture.wrapMode = TextureWrapMode.Clamp;
texture.DrawFilledRectangle(new Rect(0, 0, TEXTURE_SIZE, TEXTURE_SIZE), Color.grey);
 
texture.DrawCircle(100, 100, 20, Color.green);
texture.DrawCircle(80, 150, 5, Color.blue);
texture.DrawCircle(300, 300, 200, Color.black);
texture.FloodFill(100, 100, Color.green);
texture.FloodFill(300, 300, Color.white);
texture.DrawLine(new Vector2(10, 10), new Vector2(400, 200), Color.magenta);
texture.DrawLine(new Vector2(400, 200), new Vector2(100, 200), Color.magenta);
texture.Apply();
using ProtoTurtle.BitmapDrawing;

// ...

Texture2D texture = new Texture2D(1024, 1024, TextureFormat.RGB24, false, true);
texture.filterMode = FilterMode.Point;
texture.wrapMode = TextureWrapMode.Clamp;
texture.DrawFilledRectangle(new Rect(0, 0, TEXTURE_SIZE, TEXTURE_SIZE), Color.grey);

texture.DrawCircle(100, 100, 20, Color.green);
texture.DrawCircle(80, 150, 5, Color.blue);
texture.DrawCircle(300, 300, 200, Color.black);
texture.FloodFill(100, 100, Color.green);
texture.FloodFill(300, 300, Color.white);
texture.DrawLine(new Vector2(10, 10), new Vector2(400, 200), Color.magenta);
texture.DrawLine(new Vector2(400, 200), new Vector2(100, 200), Color.magenta);
texture.Apply();

Output from this example (cropped the image to fit):
ScreenShot

Example project
Here is a ready-to-go Unity project for easy testing.
https://github.com/ProtoTurtle/BitmapDrawingExampleProject

Getting started with C# events in Unity (delegate + event)

Update: I have a more recent article about Events and the Action delegate. Read that before or after this one.

This is a simplified version of using C# / .NET events in Unity. Unity API provides a way to send messages between GameObjects, it’s called SendMessage(string methodName) but it is pretty clunky. It uses reflection to try to find a method with that name on the target GameObject. It’s not clear what parameters are accepted when you’re listening, typos aren’t noticed except at runtime when it fails, there’s no code-completion, you have to implement your own method of adding and removing listeners etc. Writing your own Observer pattern is fun once but as C# already provides the functionality, it makes sense to use the built-in version.

Using events allows you to easily communicate things from n objects to n listeners. It scales without any effort and decouples the reaction from the action. When an enemy dies, the score counter wants to know so it can add one point, nearby enemies want to know so they can come help, the sound system wants to know so it can play a new sound, the particle system wants to know so it can create some blood splatter particles on the spot and so on. All the interested parties can subscribe to the events and get notified when they happen. The enemy doesn’t have to keep track of who to inform since anyone can subscribe or unsubscribe as they please.

The C# way is to use delegates and events. Delegates have many uses and are worth reading more about but you can think of them as a single method interface. Any method with the same signature can be used as the type defined by the delegate. When you declare a delegate you’re not declaring a reference to a instance but a type (just like a class or interface).

Here we can see two different methods (Addition and Substraction) morph into the MathMagic type.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    public delegate int MathMagic(int value1, int value2);
    
    public int Addition(int value1, int value2)
    {
        return value1 + value2; 
    }
 
    public int Substraction(int value1, int value2)
    {
        return value1 - value2;
    }
 
    private void Start () {
        MathMagic method1 = Addition;
        MathMagic method2 = Substraction;
 
        Debug.Log(method1(1, 5));
        Debug.Log(method2(1, 5));
    }
 
 
// ... prints out:
//    6 
//   -4
	public delegate int MathMagic(int value1, int value2);
	
	public int Addition(int value1, int value2)
	{
		return value1 + value2;	
	}

	public int Substraction(int value1, int value2)
	{
		return value1 - value2;
	}

	private void Start () {
		MathMagic method1 = Addition;
		MathMagic method2 = Substraction;

		Debug.Log(method1(1, 5));
		Debug.Log(method2(1, 5));
	}


// ... prints out:
//    6 
//   -4

Here’s a concrete example of Unity code. I tried to make this as simple and readable to as many skill-levels of programmers as possible. Once you understand this, you can create your own Generic implementation or use the built-in .NET/Mono libraries. The Action<T> delegate is popular for example.

You can copy these two classes into Unity and play around with them. Just create two gameobjects, one with the ExplosiveBehavior and one with the ListenerBehavior.

The listening objects have a behavior called ListenerBehavior.

ListenerBehavior.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using UnityEngine;
using System.Collections;
 
public class ListenerBehavior : MonoBehaviour {
 
    private void Start () {
        // Find all the exploders in the scene and add listeners to each
        ExplosiveBehavior[] exploders = FindObjectsOfType<ExplosiveBehavior>();
        foreach(ExplosiveBehavior exploder in exploders)
        {
            AddListener(exploder);
        }
    }
 
    private void AddListener(ExplosiveBehavior exploder)
    {
        // For the "event" type, + and - operators have been overloaded. "+" adds
        // a method reference to the list of methods to call when the event is invoked.
        // "-" removes the reference from the list.
        exploder.OnUnitExploded += HandleOnUnitExploded;
    }
 
    private void RemoveListener(ExplosiveBehavior exploder)
    {
        exploder.OnUnitExploded -= HandleOnUnitExploded;
    }
 
    private void HandleOnUnitExploded (GameObject unit, Vector3 explodedPosition)
    {
        // Do something useful here
        Debug.Log(unit.name + " exploded at: " + explodedPosition);
    }
 
}
using UnityEngine;
using System.Collections;

public class ListenerBehavior : MonoBehaviour {

	private void Start () {
		// Find all the exploders in the scene and add listeners to each
		ExplosiveBehavior[] exploders = FindObjectsOfType<ExplosiveBehavior>();
		foreach(ExplosiveBehavior exploder in exploders)
		{
			AddListener(exploder);
		}
	}

	private void AddListener(ExplosiveBehavior exploder)
	{
		// For the "event" type, + and - operators have been overloaded. "+" adds
		// a method reference to the list of methods to call when the event is invoked.
		// "-" removes the reference from the list.
		exploder.OnUnitExploded += HandleOnUnitExploded;
	}

	private void RemoveListener(ExplosiveBehavior exploder)
	{
		exploder.OnUnitExploded -= HandleOnUnitExploded;
	}

	private void HandleOnUnitExploded (GameObject unit, Vector3 explodedPosition)
	{
		// Do something useful here
		Debug.Log(unit.name + " exploded at: " + explodedPosition);
	}

}

The units that are sending the events have a component called ExplosiveBehavior.

ExplosiveBehavior.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using UnityEngine;
 
// A delegate should be declared outside of the class since it is its own type
// and you most likely want to use it from elsewhere and not just in this class
public delegate void UnitExploded(GameObject unit, Vector3 explodedPosition);
 
public class ExplosiveBehavior : MonoBehaviour {
 
    public event UnitExploded OnUnitExploded;
 
    public void Explode(GameObject unit, Vector3 position)
    {
        // Check if there are any listeners. This throws an exception if OnUnitExploded is null.
        if(OnUnitExploded != null)
        {
            OnUnitExploded(unit, position);
        }
    }
 
    private void Update()
    {
        Explode(gameObject, transform.position);
    }
 
}
using UnityEngine;

// A delegate should be declared outside of the class since it is its own type
// and you most likely want to use it from elsewhere and not just in this class
public delegate void UnitExploded(GameObject unit, Vector3 explodedPosition);

public class ExplosiveBehavior : MonoBehaviour {

	public event UnitExploded OnUnitExploded;

	public void Explode(GameObject unit, Vector3 position)
	{
		// Check if there are any listeners. This throws an exception if OnUnitExploded is null.
		if(OnUnitExploded != null)
		{
			OnUnitExploded(unit, position);
		}
	}

	private void Update()
	{
		Explode(gameObject, transform.position);
	}

}

The delegate for this OnUnitExploded-event is defined on line 5 of ExplosiveBehavior. Remember that any method that has the same signature IS a UnitExploded. So when the event is of type UnitExploded, we can write out nice custom listener methods.

1
public delegate void UnitExploded(GameObject unit, Vector3 explodedPosition);
public delegate void UnitExploded(GameObject unit, Vector3 explodedPosition);

In the listener we define a method with the same signature but with a body that has some functionality. Every class that listens to this event can have it’s own method as long as the signature is the same as the delegates. It must return void and take in two parameters; GameObject unit and Vector3 explodedPosition.

1
2
3
4
5
private void HandleOnUnitExploded(GameObject unit, Vector3 explodedPosition)
    {
        // Do something useful here
        Debug.Log(unit.name + " exploded at: " + explodedPosition);
    }
private void HandleOnUnitExploded(GameObject unit, Vector3 explodedPosition)
	{
		// Do something useful here
		Debug.Log(unit.name + " exploded at: " + explodedPosition);
	}

Development blindness

When you develop a game for long enough, you become blind to how difficult or how much fun the game really is. This happens because you learn the game inside out and could play it with your eyes closed. It becomes very difficult to tell how difficult or logical the game is to the average player. This can easily cause you to waste time iterating when you can’t actually tell if the game is improving or not.

You are the Steve Wiebe of your game
You are the Steve Wiebe of your game

This mostly applies to the first quarter of the development when you’re still working out whether the idea works or not and when you add new major gameplay features. I think most of it also applies to web or business applications too. Anything where you have a customer who you want to experience the product as smoothly as possible.

Ways to fight it:
1) Show your game(or app)- and have other people play it. Do not interfere or give them pointers or explain things! Try not to get involved with explaining and pointing things out because you won’t be there to explain what to do to the people who buy the game so the feedback won’t be authentic. You don’t want the first time you hear about the controls being confusing to be when the game is out and you start getting bad reviews. Take notes and try to see where people get stuck or what they liked. The second best option is to release a alpha version or a one level demo and ask for feedback online. People of the internet are known for being blunt.

1b) If you had a great idea but you’re seeing that no-one you show it to gets it without you explaining it – you have to either make it clearer or cut it out. Try to differentiate between one persons opinion and real problems. If it seems well thought out and well-reasoned or if a lot of people have the same complaint – it’s definitely something that needs addressing.

2) Take time away from playing your game. At least a week – preferably longer. It’s good if you have another side project going or maybe you can focus on building tools or prepare some marketing plans or one of the other 100 things you have to do after the game is “ready”. You are the best player in the world of your game right now, the closer you get to the beginner level every now and then the better you understand new players (literally everyone who will buy your game). You usually don’t have to make the decision to go ahead with a game so quickly that you can’t put it away and look at the idea again with a fresh pair of eyes. You can keep doing this every time a new major features is added.

3) Use different levels or maps when iterating. If you iterate on the same level for too long, it will start to feel dull and you’ll lose your intuitive feel for whether the mechanics are improving or not. Again you’re learning the level like the back of your hand so you start losing judgement on how the game is shaping. I recommend building “obstacle course” levels, which are just collections of different “edge-case”-obstacles etc. Like the highest possible jump in a platformer game. If you are tweaking gameplay values and can’t jump over the highest platform anymore, something went wrong. Also creating fun dumb levels where you for example test out your effects and particles by adding hundreds of explosive barrels can help see how much fun the game can be during the most intense moments.

4) Compare to other games in the same genre or with the kind of feel you’re looking for. Pay attention to the details. Like for controls, does the action happen when you press down the button or when you release it. Switching between the reference and your game brings out the differences and weaknesses in both. This was the most surprising one to me, when I opened my game after playing another game in the same genre, I could tell some parts were too sluggish in mine and some parts were already better. Don’t copy but try to learn from classics like Super Mario. It’s all physics and motion – once you know what feels and looks good to the player, you can start making it your own. In 1989 the developers of Prince of Persia for example used a primitive “motion-capture” technique (rotoscoping on top of video footage of one of the staff members) to get the feeling right.

Unity 2D Tools: 2D Toolkit by Unikron

If I had to choose just one 2D tool from the Asset Store, it would definitely be  2D Toolkit by Unikron. It offers a simple and efficient way to render 2D graphics – sprites, tiles and animations in Unity.

It’s very easy to get started with the toolkit and offers good documentation on their site and the API is clear. It takes out most of the pain points in Unity’s lack of native 2D development support. It’s easily worth the price.

Some feature highlights I’ve noticed so far:

  • Good frame-by-frame animation support. You can define a independent FPS for each animation or even individual frames
  • Tiled sprites, and tilemaps for old-school tile-based games
  • Texture atlases built in and easy to manage – reduces draw calls and makes your game run faster
  • Renders pixel-perfect and no need to mess with mipmaps etc.
  • Great in-editor tools
  • Easy to draw your own polygon colliders on top of the sprites in the editor

The only minus point is that Unity 4.3 seems to come with a lot of these features built-in so it is unclear how useful 2d toolkit will be when it launches. In the meantime if you want to get 2D games done, it’s definitely the way to go.

Rating: 5/5

Get 2D Toolkit

One of the 2D toolkit demo scenes (c) Unikron
One of the 2D toolkit demo scenes (c) Unikron