Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
14
Question by robinking · Oct 16, 2011 at 06:16 PM · c#events

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)?

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

4 Replies

· Add your reply
  • Sort: 
avatar image
13

Answer by Bunny83 · Oct 16, 2011 at 11:27 PM

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 ;)

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image robinking · Oct 17, 2011 at 01:21 PM 0
Share

Okay, interesting - so are you saying $$anonymous$$onobehaviour.Update is actually not entirely accurate - there is no such 'overridable' method? And as you say, Unity uses reflection used after compilation to check all scripts derived from $$anonymous$$onobehaviour for an Update function, and then add them to its internal Update event handler? I understand delegates and their role in events - I'm just beginning to understand that Unity's own event system either works a bit differently or hides some of the mechanics from us users.

avatar image
8

Answer by Tseng · Oct 17, 2011 at 09:39 PM

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

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image starabanaf · Mar 19, 2019 at 12:11 PM 0
Share

Technically each call of "new PauseEventHandler(OnPaused$$anonymous$$ethod)" creates a new delegate instance. So your code will not work. You should save delegate instance and use it to for unsubscribe

avatar image
3

Answer by Flynn · Oct 16, 2011 at 06:20 PM

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 :) 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)

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image robinking · Oct 17, 2011 at 01:09 PM 0
Share

I understand inheritance and polymorphism, and that $$anonymous$$onobehaviour has an overridable method called Update (although as Bunny83 has pointed out, you don't have to include the keyword override which still confuses me). The part that was eluding me more was the actual event that calls all the Update() methods - the event server as you've referred to it. For instance, if I create a custom event in class A, and a listening method in class B, I need to declare the event handler, instantiate it and then manually add the method in class B to it. Whereas the equivalent in Unity is simply creating the method in class B. What I'm grasping at is - where is the event handler that calls all the Update methods (and On$$anonymous$$ouseDown etc)? Is that internal to the Unity engine?

avatar image Tseng · Oct 17, 2011 at 09:31 PM 1
Share

I think, Unity more likely does some kind of reflection ins$$anonymous$$d, since the "Event" don't need to be called. Also with the "Send$$anonymous$$essage" you can call any functions. So it isn't something which can be explained with polymorphism.

And since we have the Broadcast and Send$$anonymous$$essage methods, reflections seems to be the better explanation on how the events works

avatar image bdev · Nov 12, 2012 at 06:55 PM 1
Share

yes Awake, Update, FixedUpdate, LateUpdate are invoked via reflection so if you have
void Update() { } in class A that private Update() function will get called by reflection, and having a Update() function in class B that inherits A, A's Update will not get called, only B's.

you have to declare the function as protected, public, or internal to be able to use .base and to do so you either use the new keyword or mark the base class as virtual and override later

avatar image
1

Answer by bdev · Nov 11, 2012 at 09:39 AM

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

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Tseng · Nov 11, 2012 at 02:33 PM 0
Share

Though that's a pretty wrong thing to do in an OOP approach, as there is no guarantee that Shoot will exist for a certain object, which is the one of the main points for Base classes like `Weapon`.

I really doubt that there is any situation where Send$$anonymous$$essage("Shoot") is faster than directly calling a method, virtual or not. Though you're welcome setting up a benchmark too proof your arguments.

Send$$anonymous$$essage is quite costly operation and it's call is likely much much more expensive than a virtual call. And one of the most important things is, you lose sanity checks.

If you for any reason rename your method, this can not happen through your IDEs reflection and you will have to find each and any usage of `Send$$anonymous$$essage("Shoot")` and replace it with the new name or new parameters, while the IDE will do the rename through reflection for you and will indicate compile errors on the parameters.

Please do not advocate using bad coding (and against OOP) style for questionable performance benefit.

avatar image bdev · Nov 12, 2012 at 06:34 PM 0
Share

Hey Tseng, You are correct. Though you should probably reread what i wrote. Notice that there is at least two paragraphs there saying to avoid use of sendmessage.

I am not advocating the use of Send$$anonymous$$essage. What I am saying is using virtual for functions that are ONLY invoked through send message or otherwise sent by unity ( ie. Awake ) is a huge mistake as they are invoked by name through reflection. These are examples just showing how one would go about it.

If unity utilized OOP it wouldnt do anything by reflection keep in $$anonymous$$d.

I could go on about all the design issues that Send$$anonymous$$essage introduces easily too. So once you get past that, there is a proper way to use it.

So while i too am a C# purist like it sounds you are as well, i know that unity is not and there's absolutely no way of getting past it.

$$anonymous$$aybe take a second and go over what i posted again because the point of all this is if your using Awake, or Send$$anonymous$$essage (which again, i do not recommend use of Send$$anonymous$$essage) imo you should NOT treat it like standard c# and you should understand how to utilize it as things like Update, Awake, Start with unity you have no choice not to.

Also theres nothing questionable about the performance benefit of using 'new' vs. override. Since Awake is called via reflection ( which is way more expensive than a normal virtual call to begin with ) theres --no-- sense in using the virtual code at all. the only reason you would is if you needed to call Awake manually ( which is bad design anyways ) OR if it comforts you to have it look like standard C# (which it is not)

avatar image dashesy · Jan 20, 2013 at 05:43 AM 0
Share

What does this have to to with being virtual?

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

8 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Multiple Cars not working 1 Answer

Distribute terrain in zones 3 Answers

Execute method from unknown script set as variable in inspector 1 Answer

Question about unsubscribing eventhandlers OnDisable and OnEnable 2 Answers

Offsetting RectTransform based on button state button 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges