MonoBehaviour Magic – using C# Namespaces and Inheritance in Unity
Saturday, June 18, 2011 at 2:55PM A discussion on Unity's workhorse class, MonoBehaviour and ways to use it in C#.
What is MonoBehaviour?
MonoBehaviour is the class from which all scripts attached to objects that exist in a scene derive from. What seems strange to many seasoned (non-Unity) programmers when they first encounter this beast is that all its methods seem to be missing. MonoBehaviour inherits from Behaviour which inherits from Component then from Object. None of these have the methods we're used to seeing, namely Awake(), Start() and OnGUI().
These are magic methods, summoned directly from the dark Unity overlord. Or, more likely, via reflection. Unity checks if your class contains any of these methods and will call them when appropriate. In the interests of clarity, from now on I'll call these methods 'Overridable Methods' as the Unity documentation does.
So back to the thing that irks purist programmers; Unity is using reflection here, so it skips the usual processes used to allow or exclude other classes from accessing methods. As you can see on the default class created by Unity.
void Awake()
{
}
This methods is private, so nothing outside the class should be able to call it. But obviously stuff can otherwise nothing would work.
One way to think of it is the following.
public class MonoBehaviour
{
public virtual void Awake()
{
}
}
public class MyMonoBehaviour : MonoBehaviour
{
public override void Awake()
{
}
}
Then imagine the Unity Engine doing something like this
foreach (MonoBehaviour baseClass in listOfAllMonobahaviours)
{
baseClass.Awake();
}
If you start of just using the default Unity created classes, it may take you a while to realise how many MonoBehaviour overrideable methods there actually are. At latest count there are 49 'Overridable Functions' that Unity uses. A full list of them is here.
Now, don't let the fact that Unity magics up these methods for you discourage you from programming in a traditional manner. That is, you can still utilise inheritance in the manner that you might like to. The thing to remember is that the Unity engine is the only thing that will call these methods in an improper way, everything we do manually will work as expected.
For example, the classic 'new' vs 'override' issue.
public class BaseClass
{
public void DoSomething()
{
}
}
public class DerivedClass : BaseClass
{
public new void DoSomething()
{
}
}
Which method gets called depends on what the type is when we call it. I.e.
DerivedClass newClass = new DerivedClass();
newClass.DoSomething();
(newClass as BaseClass).DoSomething();
...will call different methods. But in Unity, it doesn't matter what modifiers you add to your MonoBehaviour overridable methods, Unity will treat them as if you used
public override void Awake()
{
}
...and call the Awake() method of the highest derived class.
Manually though, it all works as expected. You can hide and override to your heart's content for these overridable methods, but just accept that whatever you do, Unity doesn't care and will still treat method as having been declared as an override (even if it's private). And note that you can manually call all these methods, and if you do they will be treated exactly as you would expect in non-Unity programming. But it's probably best not to for the sake of clarity.
An exception to that rule however might be if you have a derived class and you want to call an overridable method in the base class. I.e. In the Awake() method of the derived class you manually call base.Awake(). Since the base class's implementation of Awake will never be call by Unity (since it will always be overridden) this seems ok.
Execution Order
However, it's worth noting that the execution order of the overridable methods is random. You cannot guarantee the order in which they are called. If this is a problem for you, I'd recommend just creating your own update method, MyUpdate() and then have a controlling class call them manually.
public class MyMonoBehaviour : MonoBehaviour
{
public void MyUpdate()
{
}
}
public class MyController : MonoBehaviour
{
void Update()
{
foreach (MyMonoBehaviour myMonoBehaviour in this.listOfAllMyMonobehaviour)
{
myMonoBehaviour.MyUpdate();
}
}
}
Namespaces and Inheritance
One of the other things that traditional programmers might notice is the lack of namespaces. Well, that's because Unity likes to pretend that it doesn't use namespaces, but it can.
The basic rule is that you can't put any MonoBehaviour derived class inside an explicit namespace, but that shouldn't stop you from using them completely.
Now if you do put a MonoBehaviour script inside a namespace you'll get this compiler warning. “The class defined in script file named 'MyScript' does not match the file name!” And none of the MonoBehaviour overridable methods (Start, Update) will be called because Unity will treat it as a normal class.
So what, you still shouldn't use namespaces right? Well, the documentation say no, but they are just so useful that I reckon you should anyway.
Having to give everything a unique class name for a project of any size is annoying to say the least. Now, for the MonoBehaviour classes we're screwed, but for everything else, go nuts. Now I tend to section off as much common code as I can into static libraries or helper classes, on top of using inheritance to concentrate common code in base classes.
For a simple example.
Create separate Constant classes for each level. Note: You can stick all these into the one file if you want. The requirements for Class name to match File name is only for MonoBehaviour classes.
namespace Level01
{
public class Constants
{
public const float Speed = 0.1f;
}
}
namespace Level02
{
public class Constants
{
public const float Speed = 0.3f;
}
}
Create a Player base class and an abstract member (so it can be used within the class).
public abstract class PlayerBase : MonoBehaviour
{
// Common code for Player
public abstract float Speed {get;}
void Update()
{
this.transform.position += new Vector3(0.0f, 0.0f, this.Speed * Time.deltaTime);
}
}
Then we create separate Player classes specific to each level. Each will import the required namespace and thus get access to the Constants for that level..
using Level01;
public class Level01Player : PlayerBase
{
// Level 01 specific code for Player
public override float Speed
{
get {return Constants.Speed;}
}
}
using Level02;
public class Level02Player : PlayerBase
{
// Level 01 specific code for Player
public override float Speed
{
get { return Constants.Speed; }
}
}
Note: Each of these is in a separate file.
Maybe a bit of a contrived example, but I'm just trying to show that you shouldn't throw away the traditional programming tools when you start working with Unity.
Note that I didn't have to make the base class abstract. Another option would have been to make the Speed property virtual and have the derived classes override it. But since we have no intention of actually using PlayerBase on a Unity object directly it makes sense to ensure it can never be used (Unity will spit it if you attach an abstract class to an object).
Performance
Finally a little word on performance. After I realised that I didn't have to use MonoBehaviours for everything, I started wondering about their performance overhead. Perhaps I should be avoiding them at all cost? Well it turns out that whatever overhead there is is almost negligible, at least according to my quick and dirty testing.
I created a scene with 1000 objects with a MonoBehaviour script on them and a task to be performed in their Update() methods, then another scene with only one MonoBehaviour class and an Update() method that did the same task 1000 time. I ran them both and measure how many times Update was called. The result? Pretty much the same. Now I'm not conclusively saying that there is no performance gain to be had by minimising MonoBehaviours, but in my opinion there are hundreds of performance tweaks you should look at first before considering it.
Sam Cox |
5 Comments | 

Reader Comments (5)
Good stuff; thanks! A comment about execution order: according to the roadmap they just published, Unity 3.4 will allow the order of script execution to be controlled. Specifically, Awake, OnEnable, and Update calls will obey the specified script execution order. (That's all we know at the moment.)
Cheers.
Yeah, I saw that stuff about being able to specify execution order in the next version of Unity. That would be quite handy, and I'm curious how they would actually implement it. Possibly with a 'layer' type system where you could tag scripts with a layer/script number and they would be executed in that order. Wait and see...
Greate post! I use none MonoBehaviour classes when I want to show own objects in the inspector.
Well I dont belive in that Unity does reflection. They do not. They are using just generic function pointers and I belive that they just parse the C#, JS and boo code and register all the classes in a dictionary using variable pointers and generic function pointers as (Stack/Heap) a memory does. And for letting easy to code they just generated MonoBehaviour class that helps to reach the true architecture which lets execution correctly.
That's very interesting Semaphore, thanks. How is it that you know that if you don't mind me asking?
I would have thought that compiling -> reflection would have been the logical way to do what they do, just because that is what it is designed for, and they could take advantage of the existing libraries. But I admit, I was just guessing :-)