Unity3D: Making singletons from ScriptableObjects automatically

(Para a versão em português, clique aqui)

Howdy! Just wanted to share a small class that I'm using to make my life easier on Unity3D: a singleton based on ScriptableObject that will survive game and editor reloads, which can be very useful for data that must be shared across all scenes such as player/enemy parameters or global game state.

This is based on this great talk about ScriptableObjects at Unite '16 Europe, shown below; it's not a short video, but if you want to become a serious Unity3D developer it's incredible useful information. Also, if you can, go to the Unite conferences, lots of good stuff for developers and designers alike (I went to Unite '16 São Paulo and my mind exploded!)

So, without further ado, let's take a look at the code:

using System.Linq;  
using UnityEngine;

/// <summary>
/// Abstract class for making reload-proof singletons out of ScriptableObjects
/// Returns the asset created on the editor, or null if there is none
/// Based on https://www.youtube.com/watch?v=VBA1QCoEAX4
/// </summary>
/// <typeparam name="T">Singleton type</typeparam>

public abstract class SingletonScriptableObject<T> : ScriptableObject where T : ScriptableObject {  
    static T _instance = null;
    public static T Instance
    {
        get
        {
            if (!_instance)
                _instance = Resources.FindObjectsOfTypeAll<T>().FirstOrDefault();
            return _instance;
        }
    }
}

Also available as a GitHub gist. Note that this class will only return already existing assets, created via Assets menu or created and saved via scripting; it will not automatically create one on demand.

As an example, let's say you have a PlayerData ScriptableObject which holds some basic information about the player; for turning it into a Singleton, just make it inherit from SingletonScriptableObject:

using UnityEngine;

// Add an entry to the Assets menu for creating an asset of this type
[CreateAssetMenu(menuName = "ScriptableObjects/PlayerData")]
public class PlayerData: SingletonScriptableObject<PlayerData> {  
    public int maximumPlayerHealth;
    public int startingLives;
}

This is important: before using the asset you must have a public variable in any script being used on the scene and associate manually the ScriptableObject to this variable; if you don't do that, it will work only inside the editor. This is necessary because of how Unity deals with assets on runtime, ignoring the ones with no references. We could also create a GameObject which only function is hold a script full of public variables, each one with a ScriptableObject associated, and save it as a prefab for reuse in other scenes.

So, for using the singleton, just retrieve the instance directly or put a reference to it on some variable:

public void SomeFunction() {  
    // Directly
    Debug.Log("Maximum health: " + PlayerData.Instance.maximumPlayerHealth);

    // Storing a reference, e.g. on Start()
    PlayerData playerData = PlayerData.Instance;
    Debug.Log("Starting lives: " + playerData.startingLives);
}

Well, that's it. ScriptableObjects are a powerful feature that may be a bit difficult to understand, but can potentially improve your workflow as lot - not just for the developers but for game designers as well.