Game Settings with Scriptable Objects
in Unity3D


I’m going to describe how I’m handling storage and access to game settings in my Unity3D projects at the moment. Please leave comments if you have questions or comments about how to improve things.

I used to do the following: Create a Game Object that was set to persist through scene changes, call it ‘Settings’. Attach a Settings.cs monobehaviour to that Game Object. The Settings.cs monobehaviour declared all my game settings variables as public fields. In the inspector I’d select the Settings object in my hierarchy, and fill in values for the settings variables.

There are a bunch of disadvantages to this approach.

  • Changes you make to settings values while your game is running are forgotten when you switch back to edit mode.
  • You can’t easily swap in and out different sets of settings values. You have to re-type values back in to go back to a previous set of values.
  • Any script that you want to access your settings values from has to find the Settings Game Object. This dependency feels brittle and inelegant.

The approach I take now doesn’t have these problems. If you’re doing what I used to do, I think you’ll like this alternative. I’ll describe how to set it up.

A Scriptable Object instance containing a list of other Scriptable Object instances

The setup depends on Unity’s Scriptable Objects. Here’s a good talk by @Superpig about Scriptable Objects, and why you might want to use them. These are special objects that act like data containers. You create instances of them from Classes that you write. The instances are Unity assets, files that live in your project. If you select a Scriptable Object instance in the project view, you can edit the values of its fields in the inspector—as if it were a MonoBehaviour attached to a game object in your scene.

To make the creation of Scriptable Object instances more convenient (and add functionality that should be included in Unity3D by default), install Lior Tal’s Scriptable Object Factory in your project. This is really just two unobtrusive scripts that live in your Assets > Editor folder.

Next, create a script defining a class called GameSettings somewhere in your project. I’ve found it helpful to put in in a folder somewhere called ScriptableObjectClasses. The class you write will derive from the ScriptableObject Class, which means we can use it to create Scriptable Object instances later.

Here’s how the GameSettings.cs file from my current project looks. You could copy-paste and edit this as the basis for yours.

using UnityEngine;
using System.Collections;
using System;
[Serializable]
public class GameSettings : ScriptableObject {
[Header(“Debug”)]
public bool debugMode;

[Header(“Wheel positions”)]
public float nearZPosition;
public float middleZPosition;
public float distantZPosition;
[Header("Colors")]
public Color buttonBgColor;
public Color hudForegroundColor;
// etc

}

Once you’ve added all the fields you think you need (there’s no penalty if you need to add more later), use the menus in Unity to go: Assets > Create >ScriptableObject. Select GameSettings in the Scriptable Object Class dropdown, and click the Create button.

Give a name to your GameSettings instance. I prefer to include the class name in the instance names I choose. ‘GameSettings_Default’ might be a sensible name for instance. Move the instance to anywhere in your project file hierarchy that you think makes sense. Once GameSettings_Default exists, use the inspector to populate the fields with sensible values.

Next, we create a Settings.cs MonoBehaviour. This won’t be directly responsible for storing any of the values we’ll depend on in our game, but will instead act as a gateway to the GameSettings instance we set up.

Here’s how my Settings.cs looks:

using UnityEngine;
using System.Collections;
// Attach this to a gameobject that exists in the initial scene
public class Settings : MonoBehaviour {
    [Tooltip(“Choose which GameSettings asset to use”)]
public GameSettings _settings; // drag GameSettings asset here in inspector
    [SerializeField]
public static GameSettings s;
public static Settings instance;
    void Awake(){
DontDestroyOnLoad(gameObject);
if(Settings.instance==null){
Settings.instance=this;
} else {
Debug.LogWarning(“A previously awakened Settings MonoBehaviour exists!”, gameObject);
}
if(Settings.s==null){
Settings.s=_settings;
}
}
}

Once Settings.cs exists, create a game object in your initial scene and attach Settings.cs to it. ‘Settings’ would be an appropriate name for the game object. In the inspector, drag GameSettings_Default to the Settings field.

Now, from any code in your project you can access the settings values you created like this, through the static ‘s’ field of the Settings class:

Color myColor = Settings.s.hudForegroundColor

You can create as many GameSettings instances as you like (GameSettings_Hardcore, GameSettings_ShortSessions, etc) and swap them to quickly experiment with different feels for your game. If you’re collaborating on a project you can create a new GameSettings instance to safely try things out without worrying about wiping the carefully balanced values your colleague took hours to fine-tune.

You can edit your GameSettings instances while your game is running to quickly see how different values affect it. Unlike changing values in MonoBehaviour fields, your changes are not forgotten when you go back to authoring mode.

Show your support

Clapping shows how much you appreciated Tomasz Kaye’s story.