Why OnCollisionEnter is a private function

Hi, I guess I am asking a silly question, but I really want to know the answer.
I was thinking it should be a public function, as I suppose it should allow others to access it, like some collision manager:

XCollisionManager
for (var g : gameObjects) {
if (isCollided(g)) {
g.OnCollisionEnter();
}
}

Does anyone know how it was called, and help me picture why private function works?

And I also have a question about which place declare such function. I search around through the inherit tree, I could not find it through Visual studio.

Unity has special access to this. It’s the one in the Monobehaviour that you define that’s actually called and it doesn’t matter if you define it private or not.

They’re your scripts, you can call whatever you like. Make them public if you like.

You won’t have the relevant arguments to pass though so it’s unclear what you’re trying to do here.

3 Likes

No, no, doesn’t work like that. These methods are NOT for you to call.

These methods are for Unity to call.

Your job is to make the method and put into it whatever you want to happen WHEN Unity calls it.

2 Likes

To clarify a little further, this is one example of what are known as ‘magic methods’. They aren’t public because Unity isn’t accessing them the way one typically would via a standard function call. Instead, it’s using something known as reflection to effectively scan any datatypes in your project that derive from MonoBehaviour for these specific methods so that it can invoke them indirectly. There are plenty of good arguments to be made about why this is not a great design but at the time Unity was created it probably made sense from an accessibility point of view so here we are twenty years later.

You can learn more about this type of thing on microsoft’s website.
The Type Class
Reflection

4 Likes

To be clear though, it’s not using C# reflection, it’s using something much lower-level in C++ that doesn’t incur the reflection costs.

4 Likes

I’m not sure what you expect this to do that would be constructive though? Why not just make your own function and call it? It’s not like calling OnCollisionEnter is going to cause a collision or something.

2 Likes

I think I can add a bit more to this question.

Usually when you want some kind of events / callbacks that can be called on your own class, you would define them in the base class as a virtual or abstract method and have your own class override those methods so whatever system (Unity) would simply call the method on the base class and your own implementation would be called. Of course an abstract method would require the derived class to implement this method while a virtual method doesn’t need to be overridded.

This is generally called polymorphism and as a design pattern related to the Strategy pattern. This is usually a great way to allow polymorphic code / behaviour in a system. Such methods are usually declared protected or public, depending on who / which system will call those methods.

However when you look at the MonoBehaviour class, it doesn’t implement any virtual or abstract methods. As it was already mentioned, Unity essentially uses “magic methods” that the engine will call directly.from the C++ core. One of the main reasons is optimisation. Calling the method directly from C++ has very little to no overhead compared to pure managed code reflection. Also Unity has additional optimisations as it analyses and checks the class which magic method are implemented and doesn’t even try to call methods that don’t exist in the class. Given the number of potential callbacks / “messages” this is a huge improvement as an empty MonoBehaviour class has almost no overhead. So always remove empty magic methods when you don’t need them. Just having an empty Update method in a class will subscribe every class instance of this class to the update cycle and causes overhead.

Since the methods are called from outside the managed C# environment, the access modifies are pretty irrelevant. It’s generally good practice to declare magic methods private or at least protected (never public) since those methods should never be called manually. They are invoked by Unity. You would declare them protected when you want to have further subclasses of that class and override the method.

5 Likes

Interesting, I always assumed it was just reflected at creation and then marshaled across to something the C+±side could store and access later. I guess if you are already doing the heavy lifting on the C+±side though that kinda makes sense. I’m probably thinking too much in terms of user-code rather than engine code due to my experience.