Scriptable Objects: A Guide for Unity Developers

Scriptable Objects are a powerful and versatile feature in Unity that many developers frequently fail to take use of. In this guide, we’ll explore what Scriptable Objects are, why they are beneficial, and how to use them to improve your Unity game development process.

Understanding Scriptable Objects

At its core, a Scriptable Object is a data container that allows you to store and manage data outside of traditional MonoBehaviour scripts. Instead of acting as game objects in the scene like MonoBehaviour does, Scriptable Objects function as project assets.

Getting Started

1. Create a Scriptable Object:

To create new scriptable object, first of all create a script in your application’s Assets folder and inherit from the ‘ScriptableObject’ class. Let’s name it ‘PlayerData’.

using UnityEngine;

[CreateAssetMenu(fileName = "NewPlayerData", menuName = "Player Data", order = 1)]
public class PlayerData : ScriptableObject
{
    public string name;
    public int health;
    public int damage;
}
CreateAssetMenu Attribute:

This attribute adds a context menu item in the Unity editor to easily create instances of this Scriptable Object and stored in the project as “.asset” files.

Properties:
  • ‘fileName’: Defines default file name when creating an instance of the Scriptable Object.
  • ‘menuName’: Determines the path where a scriptable object appears in Unity Editor’s Create menu.
  • ‘order’: Determines the order in which the item appears in the Create menu.
2. Create an instance of the Scriptable Object:

To create a new instance of your scriptable Player Data object, right click on the Assets folder in Unity Editor and select Create > Player Data.

Create an instance of the Scriptable Objects
3. Use the Scriptable Object in a MonoBehaviour Script:

To use these values, Create a new C# script named PlayerController and attach it to a game object.

using UnityEngine;
using UnityEngine.UI;

public class PlayerController : MonoBehaviour
{
    public Text playerNameText;
    public Text playerHealthText;
    public Text playerDamageText;

    // An instance of the ScriptableObject
    public PlayerData playerData;

    void Start()
    {
        playerNameText.text = playerData.name;
        playerHealthText.text = playerData.health.ToString();
        playerDamageText.text = playerData.damage.ToString();
    }
}

In the Inspector, set the ‘PlayerData’ field by draging a PlayerData Scriptable Object instance. Also, set the player text field to relevant text objects , then click Play in the Editor.

You should see players’ information on your game view relevant text fields when you play the game.

Benefits of Scriptable Objects

Reducing the amount of memory used by your project by minimizing value copies is one of the key uses for Scriptable Objects.

  • Flexibility: It’s easy to customize and adapt to different scenarios.
  • Reusability: Instances can be used in a variety of GameObjects and scenes.
  • Serialization: Persistent data that survives scene changes and game resets.
When should you use ScriptableObjects?

Scriptable Objects are suitable for various kinds of situations in which data must be managed and organized in a flexible, reusable, and independent of individual game components. Here are some common use cases where Scriptable Objects use:

1. Configuration and Settings:
  • Storing game settings, configuration settings such as game parameters, user preferences, or any global settings.
  • Easily modifying factors such as level difficulties, spawn rates, and environmental conditions.
[CreateAssetMenu(fileName = "UserData", menuName = "User/UserData")]
public class UserData : ScriptableObject
{
    public int userID;
    public string userName;
    // Add other user preferences here
}
2. Game Data and Assets:
  • Managing data for in-game items, characters, or levels.
  • Storing sprite references, audio clips, or other assets.
[CreateAssetMenu(fileName = "ItemData", menuName = "Item/Data")]
public class ItemData : ScriptableObject
{
    public Sprite itemIcon;
    public AudioClip pickupSound;
    // Add other item-related data here
}
3. Localization:
  • Used to store localized text, audio clips, images or other assets.
  • To make it easier to switch between different languages or regional content.
[CreateAssetMenu(fileName = "LocalizedText", menuName = "Localization/Text")]
public class LocalizedText : ScriptableObject
{
    public string englishText;
    public string frenchText;
    public Sprite flagSprite;
    public AudioClip frenchClip;
    // Add other language translations here
}
4. Event Systems:
  • Transfer events and messages between game objects.
  • To enable efficient communication between different parts of your game without creating direct dependencies.
[CreateAssetMenu(fileName = "GameEvent", menuName = "Events/Game Event")]
public class GameEvent : ScriptableObject
{
    private List<GameEventListener> listeners = new List<GameEventListener>();

    public void Raise()
    {
        for (int i = listeners.Count - 1; i >= 0; i--)
        {
            listeners[i].OnEventRaised();
        }
    }

    public void RegisterListener(GameEventListener listener)
    {
        listeners.Add(listener);
    }

    public void UnregisterListener(GameEventListener listener)
    {
        listeners.Remove(listener);
    }
}
5. State Management:
  • Handling and sharing game states, like player progress or achievements.
[CreateAssetMenu(fileName = "GameState", menuName = "Game/State")]
public class GameState : ScriptableObject
{
    public bool isPlayerAlive;
    public int currentLevel;
    public int currentScore;
    // Add other state-related variables here
}
6. Inventory and Item Systems:
  • Creating scriptable objects for items and inventory in games, makes it easier to create, modify and balance items.
  • Also used to define item behavior and attributes.
[CreateAssetMenu(fileName = "InventoryItem", menuName = "Inventory/InventoryItem")]
public class InventoryItem : ScriptableObject
{
    public string itemName;
    public Sprite icon;
    [TextArea]
    public string description;
    public int amount;
    // Add other item-related data here
}
7. Custom Editors and Tools:
  • Creating custom editors and tools to simplify development processes.
  • Modify game parameters without accessing code.
#if UNITY_EDITOR
[CustomEditor(typeof(GameSettings))]
public class GameSettingsEditor : Editor
{
    public override void OnInspectorGUI()
    {
        // Custom editor GUI code for GameSettings
        // Allow developers to easily modify settings within the Unity Editor
    }
}
#endif

In summary, Scriptable Objects are a flexible object that can be used for many purposes in Unity game development providing clean and modular way to manage data and functionalities. Their ability to persist data across scenes, ease of serialization, and suitability for design and configuration make them a powerful tool in a developer’s toolkit.