For all Unity developers and developers-to-be, both beginners and professionals!

Report article RSS Feed Delegates, Events and Singletons with Unity3D – C#

Here I demonstrate how to create delegates, events and singletons to work in conjunction. This tutorial is written for Unity3D, However, similar code can be used for any C# or .NET application.

Posted by vicestudios on Dec 10th, 2012
Intermediate Client Side Coding.

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…

csharp 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…

csharp 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 and Event?
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…

csharp 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…

csharp 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’.

csharp 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().


You can download the complete project for your reference HERE. Enjoy! :)

Post comment Comments
TwisterK
TwisterK Dec 11 2012, 5:14am says:

Thanks for the tutorial, appreciate it!

+3 votes     reply to comment
vicestudios Author
vicestudios Dec 11 2012, 9:24am replied:

Welcome :)

+1 vote   reply to comment
Reactorcore
Reactorcore Dec 11 2012, 6:12pm says:

"I found most tutorials to be over complicated and lush with convoluted code not pertinent to the core concept."

Oh man, you and me both.
Trying to learn this through those is agonizing to say the least. And the worst part is that this problem is not limited to the particular topic of delegates, events and singletons, but pretty much every goddamn programming tool. ******* hell.

I am eternally grateful for this tutorial.

+2 votes     reply to comment
vicestudios Author
vicestudios Dec 11 2012, 6:48pm replied:

@Reactorcore
I'm glad you found this useful!

Like you, I can't stand how SDK Documentation is overblown and hard as hell to figure out. I hope to keep bringing new tutorials like this to the DB Community.

@"******* hell."
A-men brother

+2 votes   reply to comment
AlexM.
AlexM. Dec 30 2012, 3:09pm says:

The overall professional opinion over singletons is bad. And from most standpoints, they're right :) An Inventory does not necessarily call for a singleton implementation. An Inventory should be a component of a parent Player or Character class. The only thing that could call for a singleton implementation is some sort of manager/controller that needs to be accessed from a lot of places. But that's a design flaw on its own.
Also, is there really a need for you to make sure you only have one instance of a class? :) How many times did you accidentally declare random variables when doing a conditional check?

Other than that, great article. I appreciate the points on events and delegates.

+1 vote     reply to comment
Neobits
Neobits Oct 29 2013, 5:58pm says:

Thanks for the tutorial!!

+1 vote     reply to comment
promosquare
promosquare Dec 11 2013, 7:22pm says:

Nice tutorial. Thanks a lot for the great explanation. I used that approach in my Game State Machine example @ Blog.i-evaluation.com"
Singleton is perfect way to persist object and delegates are most elegant solution for handling events I have seen so far.

The only question I would have is about destroying it. According to Unity spec Garbage Collector doesn't destroy object if there is an reference to it and so shouldn't we be subtracting handler while destroying an object?

+1 vote     reply to comment
codysnider
codysnider Jan 9 2014, 2:02am says:

Whoa, buddy. You're misleading people here with that understanding of a singleton. It absolutely IS an instance, but the creation of it limits it to build certain properties of itself only once, setting them statically on the first pass. It's commonly used for things like database connections, third-party services, sockets, etc.... The idea is that you create the connection itself on the first use of the object and on subsequent instantiations, it reuses that static property.

+1 vote     reply to comment
Enzx
Enzx Jan 31 2014, 11:46am says:

Thank you for tutorial. helped me a lot. By the way, do we need remove event listener on destroying or disabling object?
Something like:

void OnDisable
{
Clicker.Instance.OnClick -= OnClick;
}

+1 vote     reply to comment
Symyon
Symyon Feb 3 2014, 5:18am replied:

Yes, best way is to use OnEnable/OnDisable:

void OnEnable
{
Clicker.Instance.OnClick += OnClick;
}

void OnDisable
{
Clicker.Instance.OnClick -= OnClick;
}

+1 vote     reply to comment
Chemec
Chemec Feb 11 2014, 4:41am says:

Hi, I really like how your tutorial and how it made me think how to do similiar stuff in my Perliner game. I especially like the way you explain singletons and delegates. I'm not sure however if the example for delegates is the best one.

If you have a 1000 gold piles in your level, each time a player clicks something, all 1000 gold piles will be notified. Why, if you already know which gold pile should be notified, that is the one stored in hit? you could just do hit.onClick() or something similar...

This way there is only one call and not a thousand.

Beside that, great thanks. I started thinking about refactoring my Perliner code and how to handle similar stuff. I would think I could have a ObjectClick on any clickable (or otherwise actionable) object, and use a Delegate pattern to attach any other component of the object to it.

For example let's have an object enemy with ObjectClick component attached. I could also have an Enemy component attached to it, that would do:

GetComponent<ObjectClick>().OnClick+=OnClick;

The camera's Clicker class would do similar stuff to yours, but when a hit is found, it would do instead:

hit.transform.gameObject.GetComponent<ObjectClick>.OnClick();

This way OnClick() of ObjectClick would call onClick of component Enemy.

What do you think? Or am I doing something strange?

+2 votes     reply to comment
Guest
Guest Apr 6 2014, 7:51am says:

This comment is currently awaiting admin approval, join now to view.

Guest
Guest Jun 13 2014, 7:02pm says:

This comment is currently awaiting admin approval, join now to view.

Guest
Guest Jul 3 2014, 10:33am says:

This comment is currently awaiting admin approval, join now to view.

Guest
Guest Jul 11 2014, 2:50am says:

This comment is currently awaiting admin approval, join now to view.

Guest
Guest Sep 6 2014, 8:45am says:

This comment is currently awaiting admin approval, join now to view.

epixcode
epixcode Sep 18 2014, 7:21pm says:

Hey! Good job on your article! Very informative and not enough people understand the advantage of using events to create clean code struture.

I would be glad if you take the time to take a look at EpixEvents, a library I developed while working on several video games. I think it's the best library to use all the power of events without the drawback it could occure.

You can get it here: Assetstore.unity3d.com

Or get more info here: Epixeventspro.com

Cheers buddy!

+1 vote     reply to comment
lionroot
lionroot Sep 30 2014, 12:46pm says:

Great article! Really helped me out, thanks!

+1 vote     reply to comment
germancr
germancr Oct 29 2014, 2:21pm says:

A good tutorial! Thanks a lot, these article can help me to improve my event manager Action Box ( Athagon.com )

+1 vote     reply to comment
Post a Comment
click to sign in

You are not logged in, your comment will be anonymous unless you join the community today (totally free - or sign in with your social account on the right) which we encourage all contributors to do.

2000 characters limit; HTML formatting and smileys are not supported - text only

Established
Oct 31, 2010
Privacy
Public
Subscription
Open to all members
Homepage
Unity3d.com
Contact
Send Message
Email
Members Only
Membership
Join this group
Group Watch
Track this group
Tutorial
Browse
Tutorials
Report Abuse
Report article
Related Games
Coco Blast
Coco Blast Single Player Arcade
Related Engines
Unity
Unity Commercial Released May 30, 2005
Related Groups
Unity devs
Unity devs Hobbies & Interests group with 1,243 members
Vice Studios
Vice Studios Developer