Wednesday, July 17, 2013

Unity3D: Change a script's execution order dynamically (from script)

So the other day I wanted to make sure one of my scripts always ran first, to check in it's init if certain conditions have been met, and if not, do some actions.

I didn't want to rely on manually setting each scene's execution order, and if it's the first level, OnLevelWasLoaded won't get called (no idea why).

So my solution - Create an editor class that made sure that my script's execution order is always before everything else:

using UnityEditor;

[InitializeOnLoad]
public class ExecutionOrderManager : Editor
{
    static ExecutionOrderManager()
    {
        // Get the name of the script we want to change it's execution order
        string scriptName = typeof(MyMonoBehaviourClass).Name;

        // Iterate through all scripts (Might be a better way to do this?)
        foreach (MonoScript monoScript in MonoImporter.GetAllRuntimeMonoScripts())
        {
            // If found our script
            if (monoScript.name == scriptName)
            {
                // And it's not at the execution time we want already
                // (Without this we will get stuck in an infinite loop)
                if (MonoImporter.GetExecutionOrder(monoScript) != -100)
                {
                    MonoImporter.SetExecutionOrder(monoScript, -100);
                }
                break;
            }
        }
    }
}

Note: In order for this script to work it must reside in the Editor folder.

Sunday, July 7, 2013

Unity and the Singleton design pattern

Singletons are very powerful when used for managers in game, or anything in general which you know you will have exactly one of (Game manager, audio manager, for a pure singleplayer game - the player, etc)

If you are unfamiliar with the singleton design pattern take a moment to read about it (it's quite useful):
http://en.wikipedia.org/wiki/Singleton_pattern

I wanted to share my modified version of a singleton implementation I found for Unity (found here: http://wiki.unity3d.com/index.php/Singleton).

Since Unity expects MonoBehaviour class inheritance, static classes are out of the question, so a more Unity tailored solution was needed. This class ensures that when you check for it's instance, it will be there no matter what. You can later mark any class inheriting from this one as "Game static" and it will also live through all of your scenes.

using UnityEngine;
public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
    public bool IsGameStatic;
    private static T _instance = null;

    public static T Instance
    {
        get
        {
            // Instance required for the first time, we look for it
            if( _instance == null )
            {
                _instance = GameObject.FindObjectOfType(typeof(T)) as T;
 
                // Object not found, we create a temporary one
                if( _instance == null )
                {
                    Debug.LogWarning("No instance of " + typeof(T).ToString() + ", a temporary one is created.");
                    _instance = new GameObject("Temp Instance of " + typeof(T).ToString(), typeof(T)).GetComponent<T>();
 
                    // Problem during the creation, this should not happen
                    if( _instance == null )
                    {
                        Debug.LogError("Problem during the creation of " + typeof(T).ToString());
                    }
                }
                _instance.Init();
            }
            return _instance;
        }
    }

    // If no other monobehaviour request the instance in an awake function
    // executing before this one, no need to search the object.
    private void Awake()
    {
        if( _instance == null )
        {
            _instance = this as T;
            _instance.Init();

            if (IsGameStatic)
            {
                DontDestroyOnLoad(gameObject);
            }
        }
        else (_instance != this)
        {
            Destroy(this);
        }
    }
 
    // This function is called when the instance is used the first time
    // Put all the initializations you need here, as you would do in Awake
    public virtual void Init(){}
 
    // Make sure the instance isn't referenced anymore when the user quit, just in case.
    private void OnApplicationQuit()
    {
        _instance = null;
    }
}
And later simply create the class you want to to make a singleton:
public class MySingletonClass : MonoSingleton<MySingletonClass>
{
    public void Foo() { ... }
}

Add the newly created component (MySingletonClass) to a gameobject in your scene and then you can safely call it from anywhere in your code, and assume that it was succesfully initialized.

MySingletonClass.Instance.Foo();

Notice: If you want to implement a custom Awake function for anything that inherits from MonoSingleton, you must override Init. If you create a new Awake function it will block MonoSingleton's awake function.