Game
Coco Blast
12 years ago

Delegates, Events and Singletons with Unity3D – C#


Why would I want to know this?

As a young self-taught programmer, I often found myself writing tons and tons of boolean statements to determine if some event or action has happened. I listen to those events through Coroutines and other methods to return values. If you find yourself doing this as well, STOP IT!

Welcome to Events…

Intro

Lately, I’ve been trying to improve on my C# programming skills and found myself lacking knowledge of the basic understand for Events. So, while looking through numerous tutorials on MSDN and other blogs, I found most tutorials to be over complicated and lush with convoluted code not pertinent to the core concept. I don’t want this to happen to you!

With that said I will try to explain the basics of Events and how they are used in a project…

Singleton?

If you don’t know what a Singleton is, you probably should. A Singleton is a script that cannot be an Instanced or ‘Duplicated’. It is, well… Single.

I recommend using Singletons for things that do not need to be copied multiple times during a game. Such as an Inventory System. Typically, the player only needs one Inventory, so we don’t want to call Instances of it, we only want one. And when we call it, we want to make sure it doesn’t get duplicated.

There are many ways to create Singletons, but this method is often used because it’s simple…

		
			<pre class="snippet-code">
// This class sits on my camera and handles all the clicks I send with a Raycast
public class Clicker : MonoBehaviour
{
    // Singleton
    private static Clicker instance;

    // Construct
    private Clicker() {}

    // Instance
    public static Clicker Instance
    {
        get
        {
            if (instance == null)
            instance = GameObject.FindObjectOfType(typeof(Clicker)) as Clicker;
            return instance;
        }

    // Do something here, make sure this is public so we can access it through our Instance.
    public void DoSomething()
    {
    }
    ...
		
	

Here, I have a class ‘Clicker’ that is attached to my Camera. This class handles all clicks that I send into 3D Space with a Raycast.

To access my ‘DoSomething’ method from another script, I simply call…

		
			<pre class="snippet-code">
Clicker.Instance.DoSomething();
		
	

This eliminates the need to use a bunch of Static Method and Variable calls, plus gives us one instance only!

Delegate?

A Delegate can be thought of as a reference pointer to an object/method. When it gets called, it notifies all methods that reference the delegate.

So, first things first…

Define a Delegate and the method that gets called when it fires…

		
			<pre class="snippet-code">
public class Clicker : MonoBehaviour
{
    // Event Handler
    public delegate void OnClickEvent(GameObject g);
    public event OnClickEvent OnClick;
    ...
		
	

The delgate called ‘OnClickEvent’ passes a ‘GameObject’ that we can use to define what game object it came from. Then, we defined an ‘event’ OnClick that gets called when the delegate is called.

Now, in the same script, we need to call the delegate and pass it our GameObject. I’ve done this through a Raycast…

		
			<pre class="snippet-code">
public class Clicker : MonoBehaviour
{
    // Event Handler
    public delegate void OnClickEvent(GameObject g);
    public event OnClickEvent OnClick;

    // Handle our Ray and Hit
    void Update ()
    {
        // Ray
        Ray ray = Camera.mainCamera.ScreenPointToRay(Input.mousePosition);

        // Raycast Hit
        RaycastHit hit;

        if (Physics.Raycast(ray, out hit, 100))
        {
            // If we click it
            if (Input.GetMouseButtonUp(0))
            {
                // Notify of the event!
                OnClick(hit.transform.gameObject);
            }
        }
    }
}
		
	

As you can see, if the Ray has contact an Object in the scene and we Left-Mouse-Click, we call the event and pass the GameObject.

The last thing we must do is reference the delegate from our other scripts that are listening to the call. For this I’ve created a class called ‘GoldPile’.

		
			<pre class="snippet-code">
public class GoldPile : MonoBehaviour
{
    // Awake
    void Awake ()
    {
        // Start the event listener
        Clicker.Instance.OnClick += OnClick;
    }

    // The event that gets called
    void OnClick(GameObject g)
    {
        // If g is THIS gameObject
        if (g == gameObject)
        {
            Debug.Log("Hide and give us money!");

            // Hide
            gameObject.active = false;
        }
    }
}
		
	

In our Awake() method, we’ve defined our listening Event and assigned a local method that gets called ‘OnClick’. ‘OnClick’ does not need to be the same as our delegate method, but it can be.

Note: In our previous post we added a Singleton to our Clicker class. This allows us to use Clicker.Instance

As you can see, we’ve also created the OnClick() method that passes our GameObject we clicked on.

Note: You must use if (g == gameObject), otherwise it will hide other instances of that method in the scene as well… This is why we pass the GameObject for reference!

Now you are free to add this method to any other script in your game if needed. Don’t forget to define the method and delegate in your Awake().

I’ve attached the complete project for your reference. Enjoy! :)

<div class=”attachments”><dl class=”attachments attachments-large”><dt class=”icon”></dt><dd class=”caption”>Document label : Gold-Picker.rar
Title : Gold Picker
Size : 149 kB</dd></dl></div>



0 comments

Loading...

Next up

Updated the chest in the maze, adding sound, particles and better animation. But what's in the chest?

The whole squad is here!

Interested? Follow me!

I-Buki

Mio-Da!

Ibuki Mioda!

Demonstration of the spells and their effects :)!

Update 2.627

New challenges & new effects!

Terraria

Showing off player 2 😎

What do you think?

Why walk when you can jump?

it happens

OK, this starts to be too tricky puzzle already :D

#platformer #indiegame #puzzle