EditorWindow and play mode

If you’re trying to write custom editors in Unity you may run into a snag. I just spent several hours hitting my head against a wall trying to solve this issue.

When you enter play mode, Unity will reload all mono assemblies. This means that your EditorWindow object is recreated, and you will need to explicitly handle serialising and deserialising any settings that you want to persist between edit mode and play mode. This is detailed on the Unity blog but unfortunately is not really covered in the documentation.

This is all well and good but Texture2D instances don’t seem to be serialised, even if you use the Serializable attribute. In my case, I am using small 1×1 instances of Texture2D when drawing a horizontal group of controls in order to draw highlighted selections. These textures are initialised in my EditorWindow’s constructor every time. However, when entering play mode, although the constructor and OnEnable are called, at the next OnGUI call the textures are again null!

I am not sure if this is by design, but it certainly isn’t documented except in various forum posts. My workaround for this is to re-create the textures in OnGUI if they are null. It’s ugly but it works!

Unity performance and empty functions

We’re busy here at Horse Drawn HQ working on our first mobile and tablet game. We’ve still got a bit of a way to go, but I thought I’d do some profiling of our game on my iPhone 4 using Unity’s built-in profiler to see where we were at. I was surprised to see an update function showing up for each of the main playable game objects and taking anywhere from 4ms to 9ms! This was the function:

void Update()
{
    Vector4 campos = Camera.main.transform.position;
    campos = renderer.worldToLocalMatrix.MultiplyPoint(campos);
    renderer.material.SetVector("_modelSpaceCameraPos", campos);
}

This code transforms the camera position into model space and then sets the result as a shader constant. Okay, so maybe it’s just that slow – it’s being done for up to 125 objects every frame. I’m not too worried about it at the moment though, because that shader constant is only used by a particular material which we’re currently not planning on shipping with. However, we want to be able to switch materials, so I changed the code to the following:

void Update()
{
    if (m_updateCamPos)
    {
        Vector4 campos = Camera.main.transform.position;
        campos = renderer.worldToLocalMatrix.MultiplyPoint(campos);
        renderer.material.SetVector("_modelSpaceCameraPos", campos);
    }
}

m_updateCamPos is usually false, and true only when we use the material that needs it. At the moment the game isn’t using those materials so this is always false. This helped a lot; the function still shows up but now only at around 0.1ms or 0.2ms. Unfortunately it still spikes at 2ms or 3ms (once even at 33ms)! This still isn’t good enough. I don’t want an empty function to show up at all (note that it is possible that the empty function will be optimised out in a final build, but you can’t profile a final build in Unity).

It turns out that Unity actually calls the MonoBehaviour methods that you ‘override’ using reflection; Update, Start, et al are not actually virtual methods. You can tell because you never have to use the ‘override’ or ‘new’ keywords when defining those functions, which C# requires if you are introducing a new implementation of an inherited method, and also Start and Awake can have a return type of void OR IEnumerator but C# doesn’t support covariant return types. To be a bit more concrete about it, if we bust open MonoBehaviour in Visual Studio or ILDasm we see this (note: attributes and comments removed for brevity):

namespace UnityEngine
{
    public class MonoBehaviour : Behaviour
    {
        public MonoBehaviour();
        public bool useGUILayout { get; set; }
        public void CancelInvoke();
        public void CancelInvoke(string methodName);
        public void Invoke(string methodName, float time);
        public void InvokeRepeating(string methodName, float time, float repeatRate);
        public bool IsInvoking();
        public bool IsInvoking(string methodName);
        public static void print(object message);
        public Coroutine StartCoroutine(IEnumerator routine);
        public Coroutine StartCoroutine(string methodName);
        public Coroutine StartCoroutine(string methodName, object value);
        public Coroutine StartCoroutine_Auto(IEnumerator routine);
        public void StopAllCoroutines();
        public void StopCoroutine(string methodName);
    }
}

If you dig deeper down the inheritance hierarchy (MonoBehaviour -> Behaviour -> Component -> Object) you can see that there are no virtual functions at all. So Unity is using reflection to call these functions, and reflection is not cheap! I would imagine that Unity are doing things like caching the MethodInfo objects, or even converting to delegates which are apparently faster. But I think the best thing to do is to write your code in such a way that empty update functions don’t exist. This is commonly mentioned in relation to the OnGUI function but it seems that it applies to all the common MonoBehaviour functions. In our case, I will be removing the method entirely for now, but if and when we need this functionality I will create a derived class that implements update, so that the common case is not penalised.

Merry Christmas!

Merry Christmas from Horse Drawn Games! We’re a new team of indie game developers in Australia and are doing a soft launch of our new studio. Exciting things are happening, including our first project and a new website. We can’t wait to show you but in the meanwhile, we’ve baked you a delicious Christmas treat!

We also had some fun recently making a little New Year’s Eve greeting!