How does Unity's built in event system work behind the scenes, as opposed to C# events?

This is one of those questions I’m getting by without knowing the answer to, but would like to fully understand.

I’m only just getting my head round events in C# and trying to reconcile them with Unity’s built in events. So I understand OnMouseOver is an event, and Update, Awake, OnGUI etc are events too. In C#, if I create a custom event, a listening method must be added with code to an event handler in order to become subscribed to that event:

myEventHandler += myListeningMethod;

However, in Unity simply adding for instance the Update method to a Monobehaviour script attached to a game object is enough.

Am I right in thinking that this is just a particular function of Unity (or Mono) - that upon compiling scripts, Unity automatically subscribes any Update methods it finds in a MonoBehaviour attached to a game object to Unity’s built in Update event handler (and same for other events)?

Usually i would totally agree with Flynn since inheritance and method overriding are fundamental things in OOP. However Unity works a bit different. All those so called “events” are NOT methods of the MonoBehaviour class. If you have a C# reflector you can just view the class implementation by opening the UnityEngine.dll

Unity is mainly written in c++ and therefore most magic happens in native code. Unity uses reflection to determine, after your scripts have been compiled, what of those “events” you’ve implemented and remember that for this class. Unity only calls Update / LateUpdate / OnGUI when it has been implemented.

Another point where you can notice that is when you create a MonoBehaviour class and don’t implement any of those methods/events Unity will remove the enabled checkbox from your script instance because it doesn’t contain any events that are affected by enabled.

Some events are dispatched with their SendMessage function (like OnCollisionEnter and such events).

The documentation calls all events “Overridable Functions” but that’s not really true. If they were implemented as virtual function you would have to use the override keyword or it wouldn’t work.

Here’s the whole implementation of MonoBehaviour:

public class MonoBehaviour : Behaviour
{
    public extern bool useGUILayout
    {
        get;
        set;
    }
    public extern MonoBehaviour();
    private extern void Internal_CancelInvokeAll();
    private extern bool Internal_IsInvokingAll();
    public extern void Invoke(string methodName, float time);
    public extern void InvokeRepeating(string methodName, float time, float repeatRate);
    public void CancelInvoke();
    public extern void CancelInvoke(string methodName);
    public extern bool IsInvoking(string methodName);
    public bool IsInvoking();
    public Coroutine StartCoroutine(IEnumerator routine);
    public extern Coroutine StartCoroutine_Auto(IEnumerator routine);
    public extern Coroutine StartCoroutine(string methodName, object value);
    public Coroutine StartCoroutine(string methodName);
    public extern void StopCoroutine(string methodName);
    public extern void StopAllCoroutines();
    public static void print(object message);
}

I removed all the external attributes since nearly every method/property is mapped to a native function.

btw. the mentioned C# events are delegates which are just some kind of function pointers but a bit more complex :wink:

Additionally to that what Bunny83 already said, there is an important notice on the C# event/delegates, which people new to C# maybe don’t know.

If you use event/delegates, you also have to be careful and unsubscribe when the objects who subscribed to an event is being destroyed.

i.e.

GameController.OnPause += new PauseEventHandler(OnPausedMethod);

when you destroy this object, in C# you have to unsubscribe the event, otherwise it may not be collected by the garbage collection, because the element still holds a reference to the event and may cause a memory leak. So you should always unsubscribe, in MonoBehaviour you don’t have a Dispose method to override, but you can use OnDestroy method to do the same

void OnDestroy() {
    // Unsubscribe, so this object can be collected by the garbage collection
    GameController.OnPause -= new PauseEventHandler(OnPauseMethod);
}

Unity “Events” (or rather Messages, since they are same in functionality as SendMessage and Broadcast) don’t require this

Event listening in programming is very interesting, and there are many different approaches. The way Unity does it is less event listening, and MORE event describing.

The class MonoBehaviour all ready HAS An Update() function for example, which it calls over and over and over again. When you define Update() in your script, (Which is a MonoBehaviour subclass), YOUR Update() starts getting called by the MonoBehaviour class, through the concept of method overriding. If you have ever dabbled in Java, then this is very similar to the run() method associated with the Runnable interface!

All of the functions that are available to MonoBehaviour in that form, are in fact allready defined as empty methods. They still get called as usual, but they just don’t do anything in response :slight_smile: By putting it in your code, you are basically, “filling in the blanks”. You make those functions actually do something, rather than doing nothing.

This differs from event handling, where you assign one (or more) callbacks to an event, and the event server iterates though those and calls them. IN Unity, Unity is iterating through all monobehaviours and calling their all ready defined methods. You jsut overload those methods.

(If you want to learn more about this concept, this page is all about it: http://www.akadia.com/services/dotnet_polymorphism.html)

In regards to the comment Bunny83 made about messages requiring virtual to work is incorrect.

Making a function that is soley based off messages virtual is wasteful unless you plan on invoking it without SendMessage – (which should be avoided anyways as its hard to keep up/maintain code that can be invoked multiple ways).

Heres a example of how to override without using virtual.

Entity.cs:

public class Entity : MonoBehaviour {
   protected void OnKilled() { print("Entity Has Died"); }
}

Human.cs:

public class Human : Entity {
    protected new void OnKilled() { print("Human Has Died"); }
}

Notice the new keyword. The new keyword is basically like a anti-virtual override and makes no expensive virtual call.

So what happens if you were to manually call OnKilled?

static void KillEntity( Entity entity ) { entity.OnKilled(); }
static void KillHuman( Human human ) { human.OnKilled(); }

If you were to pass a instance of Human to KillEntity it would print “Entity Has Died” and if you were to pass that same Human instance to KillHuman it would print “Human Has Died”.

The invocation of methods using the new keyword is entirely dependent on the reference type, not the instance where as virtual and override are instance based.

It’s a bit hard to grasp admittedly but heres where unity messages come in.

Unity messages are invoked through reflection by member name off the type (class) .GetType would return off the instance. So ultimately its completely un-needed to use virtual when you have a function that will only get invoked through send message.

When it comes to using virtual for messages the rules are similar to the new keyword. you can use .base just like you would with a virtual, you need to have the function public, protected, or internal to use .base just as you would as well.

To be clear however, a non virtual method call takes much much less time than a virtual call but we are talking about nano seconds. The reason you should care though is once you get used to using the new keyword for messages you’ll find there is absolutely no reason to use virtual (when dealing with messages ).

So while SendMessage, SendMessageUpwards, BroadcastMessage are VERY VERY slow to use; at least you’ll be able to keep stuff fast once the call stack actually reaches your methods. And it somewhat justifies using SendMessage over C# events when you start talking about very large virtual tables and targeting many game objects at once.

But the most important time to use the new keyword when it comes to OO in unity is in the built-in messages such as Awake, Update, OnDestroy. where you would normally need to mark virtual / override and spend time every frame just invoking off the virtual table, theres no need to. You just use the new keyword.

Another example:

public class Weapon : MonoBehaviour {
    protected Renderer[] renderers;
    protected void Awake() { renderers = GetComponentsInChildren<Renderer>(); }
    public void Hide() { foreach( var r in renderers ) r.enabled = false; }
    public void Show() { foreach( var r in renderers ) r.enabled = false; }
    //protected void Shoot() { } <-- does nothing. don't need it.
}
public class Launcher : Weapon {
    protected ProjectileGenerator projectileGenerator;
    protected new void Awake() { 
        base.Awake();
        projectileGenerator = GetComponent<ProjectileGenerator>(); 
    }
    protected void Shoot() { 
       if( projectileGenerator ) 
           projectileGenerator.Eject( transform.position, transform.forward );
    }
}
public class Player : MonoBehaviour {
    public Weapon weapon;

    public void Attack() { 
        if( weapon )
            weapon.SendMessage("Shoot"); 
    }
}

It’s good to understand where you can benefit from the way unity does use messages as it does. things like Awake, Update, Start, OnDestroy should really never be marked as virtual. Personally i avoid using SendMessage at all costs, but there are times when if your sending messages very infrequently it can really simplify code ( as long as you take in mind the possibility for overlaps, and void parameter versus null parameters and your sending messages past Awake or Start where it can be a grab bag of uninitialized badness ).