Automatic Initialisation at Runtime with Easy Maintenance!


Often when working with Unity I have the need to automatically initialise “controller” objects which live across scenes. In the past I have typically created an initialisation scene and used DontDestroyOnLoad. Whilst this works it makes debugging scenes a lot tricky since you cannot just hit the “Play” button.

It would be really great if Unity provided a runtime equivalent of InitializeOnLoad or better still a way to define scriptable objects which automatically spring into life when a certain runtime criteria is met (please vote here!).

I have been thinking of ways to circumvent this limitation and feel that I have come up with a pretty good solution. I would like to tip my hat to @Superpig for suggesting use of a ScriptableObject for game configuration.

So, in a nutshell… Each scene must contain a simple “InitGame” behaviour which is associated with a game configuration asset. Upon awaking this object can initialise the game using the configuration asset, otherwise it can immediately self-destruct. This allows the game controller to properly initialise from any stage; be it the main menu screen or level 3.

First let’s take a look at the configuration asset. In my case I want to automatically instantiate a game controller prefab upon loading the game. Since I may want to experiment with different game controllers throughout development it is imperative that I can quickly switch to and fro and the game configuration asset seems like an ideal place to do this. This is way nicer than manually loading and adjusting every scene in my game!!

// An asset which contains game configuration data.
public sealed class GameConfiguration : ScriptableObject {
    // The one-and-only game configuration instance.
    public static GameConfiguration Instance { get; private set; }

    // Prefab for game controller which will be automatically
    // instantiated upon loading game.
    public GameController controllerPrefab;

    private void OnEnable() {
        Instance = this;
    }
}

There should only ever be one game controller at any given time and this should be easily accessed, therefore the singleton design pattern is a good fit:

public class GameController : MonoBehaviour {
    // Gets the current game controller.
    public static GameController Instance { get; private set; }

    // Initialise game - should only occur once during lifetime of game!!
    public static void Init(GameConfiguration configuration) {
        if (configuration == null)
            throw new ArgumentNullException("Game configuration required.");
        if (!Application.isPlaying)
            throw new InvalidOperationException("Cannot initialise in edit mode.");
        if (Instance != null)
            throw new InvalidOperationException("Game has already been initialised.");

        Instance = Instantiate(configuration.controllerPrefab) as GameController;
        DontDestroyOnLoad(Instance.gameObject);

        Instance.StartNewGame();
    }

    // Can be called to start/restart game as needed.
    public void StartNewGame() {
        // Game initialisation logic...
    }
}

Finally we need a behaviour class which must be attached to an “Init Game” object for each scene within our game. It is a good idea to save this object as a prefab so that its configuration reference can be easily updated if necessary.

public sealed class InitGameBehaviour : MonoBehaviour {
    // The associated configuration asset.
    public GameConfiguration configuration;

    private void Awake() {
        if (GameController.Instance == null)
            GameController.Init(configuration);

        // This game object is no lonegr needed since the game should
        // now be properly initialised.
        DestroyObject(gameObject);
    }
}

A simple editor utility class can be created to create our game configuration asset:

public static class MyGameTools {
    private const string ConfigurationAssetPath = "Assets/GameConfiguration.asset";

    [MenuItem("Tools/Create/Game Configuration")]
    private static void CreateGameConfiguration() {
        var configuration = ScriptableObject.CreateInstance<GameConfiguration>();
        AssetDatabase.CreateAsset(configuration, ConfigurationAssetPath);
    }
}
Advertisements

2 thoughts on “Automatic Initialisation at Runtime with Easy Maintenance!

  1. This is a nice approach! One further step you could take is to preprocess scenes to ensure that the component exists – that way there’s no manual process. This can be done using AssetModificationProcessor, here’s a little script I wrote that adds a callback before the current scene is saved: https://gist.github.com/becksebenius/9593857
    Then you can use [InitializeOnLoad] to add an event which checks the scene for the object before the save – if it doesn’t exist, add it first!

    Could even be further streamlined by using HideFlags so that a designer doesn’t even know it’s happening. That way it “just works”. This could be too far though, since hidden objects are hard to track down.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s