Search
Twitter Feed
Navigation
« A genuine passion for C# .Net development | Main | Maze Rover Prototype »
Saturday
Jun182011

MonoBehaviour Magic – using C# Namespaces and Inheritance in Unity

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.

PrintView Printer Friendly Version

EmailEmail Article to Friend

References (2)

References allow you to track sources for this article, as well as articles that were written in response to this article.
  • Response
    Response: website
    Welcome to Friction Point Studios - Friction Point Blog - MonoBehaviour Magic – using C# Namespaces and Inheritance in Unity
  • Response
    Welcome to Friction Point Studios - Friction Point Blog - MonoBehaviour Magic – using C# Namespaces and Inheritance in Unity

Reader Comments (12)

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

June 22, 2011 | Unregistered CommenterMatt Diamond

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

June 22, 2011 | Registered CommenterSam Cox

Greate post! I use none MonoBehaviour classes when I want to show own objects in the inspector.

June 23, 2011 | Unregistered CommenterCarsten

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.

September 24, 2011 | Unregistered CommenterSemaphore

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

September 29, 2011 | Registered CommenterSam Cox

I assume they use reflection based on evidence in the UnityEditor assembly. There's a HostView class which has an Invoke method which uses reflection to invoke a specified method on a specified object. But, looking at the UnityEditor assembly doesn't reveal everything as most of the engine is not managed.

April 20, 2012 | Unregistered CommenterJordan Pickwell

That is very good comment you shared.Thank you so much that for you shared those things with us.All the best.

June 14, 2012 | Unregistered Commenterc# developer austin

I'm a developer with a little bit of enterprise development under my belt, and I'm taking a game programming class. In the first class MonoBehaviour was introduced to us, three people spent 10 minutes debugging errors that were simply void OnUpdate() vs void Update(), OnGui vs OnGUI, etc.

What I'd like to do is put this stuff back in a more traditional space: static types, so that we can derrive and properly override functions to avoid this problem, but if it is all done cleverly through reflection (or, even more disgustingly as Semaphore suggests, via some precompiler nightmare --bring on C#++!... or... please don't) I'm a little worried about performance.

What I'd like to do is this:

public abstract class StaticMonoBehavior : MonoBehaviour
{
public virtual void Update(){}
public virtual void LateUpdate(){}
public virtual void Awake(){}
public virtual void Start(){}
public virtual void Reset(){}
//...
public virtual void OnReallyObscureEventButThanksForSupplyingItUnity(){}
}

Assuming a big-bang Unity pub/sub when we launch the game, I'm worried that said clever reflection is looking at the method, determining if a body exists, and then subscribing it or not subscribing it. If this is the case, then any subclass of my static type is going to get notified for every single event no matter what. Now, my implementation is simply public virtual void Update(){}, meaning if Unity is indeed registering each "found" Update method in some sort of Update-subscriber queue, every subclass of my nice static class is going to get called, but for the vast majority of the classes they're simply going to return.

Will this cause performance problems? Can I whisper something to either the compiler or the jitter to say "hey, if anybody asks for this method dynamically and the body's empty, go ahead and return false"?

October 25, 2012 | Unregistered CommenterGeoff Groos

Not a bad idea there, using the StaticMonoBehavior class. Pretty sure everyone has had a frustrating debugging session or two only to discover they named it ONGui() or whatever.

For performance, I have no idea. All I would say is that even if the compiler didn't optimise the empty methods out and they were called, the cost of that would be a few orders of magnitude lower than having messy models with too many polygons.

Scripts runs stupidly fast so I'd forget about the performance hit and focus on the fact that this approach will potentially save you time each time you create a new MonoBehaviour. I forget who said it but don't prematurely optimise. If you finish the project and find that your need to save that Xms each frame, consider re-converting everything back to not use StaticMonoBehavior, but I bet you never do. :-)

October 25, 2012 | Registered CommenterSam Cox

Geoff your thinking is spot on. Unity does register all event methods it finds, even if they're empty. But, Sam is also right, script execution is fast, so don't worry about the performance hit. On the other hand, you should worry about possible side-effects an empty event method may cause (you'll have to experiment).

October 26, 2012 | Unregistered CommenterJordan Pickwell

Interesting discussion going on here. I like this idea of replacing Unity's "loose" override behavior with something stricter.

Not that anyone has mentioned OnGUI as an event of interest, but be aware that the usual assumptions don't apply. OnGUI has some kind of setup overhead so even if your OnGUI method does nothing but return, you will take a performance hit. More information on my blog: http://www.mindthecube.com/blog/2010/09/avoiding-performance-cost-of-ongui

October 26, 2012 | Unregistered CommenterMatt Diamond

I really liked Geoff's idea, and started thinking about how to have a reference for the unity methods in the code, without the performance hit mentioned above.

So, to cut it short, I reached sort of a solution, with MonoDevelop's code templates. Basically, I created a code template for each of the overridable functions, with its parameters and the description of the method found on the official documentation.

This way, the user only has to write "Mono", and the autocompletion kicks in with a list of all the templates, showing the user all the methods MonoBehaviour has. Then you just have to pick one, press "tab" (that's how you activate code templates in monodevelop), and the editor creates the method for you, with the proper parameters.

Here's a link to download the templates if anyone's interested:
UnityCodeTemplates.zip

The templates are in C#.
Decompress them to "/Users/<user>/Library/MonoDevelop-Unity-<version>/Snippets" if you're on a Mac, or "%APPDATA%/MonoDevelop-Unity-<version>/Snippets" if you're on Windows. If the folder "Snippets" doesn't exist, create it.

Thanks for the idea!

March 5, 2013 | Unregistered CommenterKyu

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>