Suppose I have a button, and for its OnClick event I choose some object A with a method B that has one argument of type GameObject. I now choose the argument (I do all of this in the inspector). What is actually happening?
I only have basic knowledge of c# - I understand that OnClick is an event, and I’m effectively storing a function pointer to the chosen method B here, as an event handler. But what about the chosen argument? How do you store a fixed argument for each chosen event handler - how does unity implement this?
Essentially, I can subscribe to the OnClick even with “various” B methods with different arguments. I don’t understand how this works, and I don’t see how you can even do this with events.
Button.onClick is a property of type ButtonClickedEvent which extends UnityEvent.
UnityEvents function similarly to delegates, but they can be serialized by Unity’s serialization system. UnityEvents however are not actually delegates, but wrapper classes for them.
The UnityEvent class probably contains the method name and type parameter info, so that when the UnityEvent is deserialized, it can use that information to generate a MethodInfo utilizing reflection. It can then generate a delegate using the MethodInfo and the Object reference, which is also just stored inside the UnityEvent class.
The arguments too are likely just stored inside the UnityEvent class as properties, and used whenever the delegate wrapped by the UnityEvent is invoked.
Thanks for the reply. I think I understand the general idea to some extent, but I don’t really understand the following details:
1, When you say that UnityEvents can be serialized - what’s the point of serializing them? Why not just store them as normal objects, like everything else? Perhaps I’m missing the bigger picture here - serialization is needed for pretty much everything in Unity as part of saving data, allowing you to load scenes (otherwise you would need to have all scenes loaded at the same time?).
2, You say UnityEvents are wrapper classes - I’m not completely sure what a wrapper class is. I thought that’s what you call it when you “wrap” a primitive data type in some very simple object (boxing/unboxing). I suppose a wrapper class can also be a general name for a class that extends some other class?
3, So because we will possibly need to serialize/deserialize the event, we don’t just store the method/function address (that is how events in c# work, right?), but we store additional data like parameter info and perhaps other things. This way, we can recreate the method. I don’t really understand the description you’ve written though - why do we need to recreate MethodInfo? Can’t we just use the method name, parameter, object class name etc. directly to look/find the method we’re looking for/or to directly create the delegate? Why do we need reflection, if we’ve already saved all the information about the method?
4, When you say we generate a delegate - how does this happen/when does this happen? I don’t really know how unity compiles in the first place - does it work like C# and compile to some sort of intermediate code like C# CIL? If that’s the case does the delegate get generated during the C# compilation, or during the second JIT-like compilation?
Sorry for the long questions. If these are basic questions, please feel free to reference me to some document that maybe describes how unity works. Like I said, I’m a beginner and I don’t really know how it all works, but I’d really like to find out.
When I say that UnityEvents can be serialized by Unity, I mean that their state can be saved and reconstructed automatically for things like scenes and prefabs by Unity’s internal script serialization processes. So being serializable is what makes them act like “normal objects, like everything else” in Unity, instead of their state being lost every time you close a scene that contains them. It also means that you can manually serialize/deserialize them using the JsonUtillity.
You can read more about Unity serialization here and here, if you’re interested.
I believe that what you are talking about are primitive wrapper classes used in the Java language, which are one example of the more general idea of wrapper classes. Wrapper classes basically encapsulate the functionality of another class for one reason or another. This article contains some examples.
In the case of UnityEvents, I think of them as wrappers for delegates, with the added functionality of making them serializable by Unity.
Unity also has a thing called PropertyDrawers, that makes it possible to change how an instance of a specific class looks like when viewed in the inspector. Unity has created a special PropertyDrawer for UnityEvents that makes them easily viewable and editable in the inspector. This is another major benefit to using UnityEvents instead of delegates in your own scripts besides serialization, as the default inspector can not show you the invocation list of a delegate (by default).
From the C# Programming Guide on delegates: Delegates are similar to C++ function pointers, but delegates are fully object-oriented, and unlike C++ pointers to member functions, delegates encapsulate both an object instance and a method.
You’re probably right about UnityEvents not needing to use reflection after all. I didn’t realize that you could use Delegate.CreateDelegate without providing a MethodInfo.
A delegate can be created using the aforementioned Delegate.CreateDelegate.
This takes place inside the UnityEvent class during Unity’s internal script deserialization process. So when you load a scene, load a prefab, use JsonUtility.FromJson etc. This all takes place before any of the event functions in Unity like Awake or OnEnable are called.
You can implement the ISerializationCallbackReceiver interface in your classes to get a callback right after an instance of said class has been deserialized by Unity. This can be useful if you need to manually serialize/deserialize some data that Unity can’t handle internally (like Dictionaries).
Thanks a ton. Just one last question - do you know of any documents/books concerning questions like these, that describe what happens from a high level view? I’m not really looking for a detailed technical explanation - just a high level explanation of the concepts that are used for certain things that unity does, etc. It doesn’t have to be detailed, but it should be correct.
As an example, I remember that when I started and my c# knowledge was even worse than now, I didn’t really know what happens when the game starts and what happens to the scripts attached to the objects - unity documentation generally consists of descriptions of things like game objects and components and what they do, separately. But all I would have liked to hear is something like “when the game starts, all the objects in the scene are instantiated, and the attached scripts/classes are also instantiated as objects”, but in more detail and maybe with an example on a sample scene.
One way I could learn more about this would be to just improve my general c# knowledge and maybe learn some common game engine practices. That would give me some intuition and let me figure out a general idea of how it could/probably is done in unity. But that’s a pretty long journey, and ideally I’d like a book that would describe these things in unity specifically.
I haven’t read any books about Unity myself, so I’m afraid I don’t have any recommendations on that front.
In my experience all the useful in-depth pieces of information available in the internet tend to be very scattered about.
There are some useful tidbits to be found in the Unity Scripting Reference, hidden away in the description texts of certain pages.
There are all kinds of tips and tricks that can be learned from random pages in the Unity forums.
I think that best way to accumulate knowledge about Unity is to just start doing something in practice. Do a simple project from start to finish, and as you run into new questions, search for answers to those specific things. You will naturally learn more and more as you go on. Unity has a very active community, and you will usually find there are good answers out there to pretty much all questions you can just think to ask.
So learning the nuts and bolts of Unity, in my experience, tends to work more like the Socratic method, than reading a book linearly. But that could also just be because I never picked up a literal book on the subject