Scriptable Objects Tutorial: Getting Started

In this tutorial you’ll learn how to create and use Scriptable Objects in Unity. Scriptable Objects in Unity can increase your workflow, reduce memory usage, and even decouple your code architecture.

Version

  • Other

ScriptableObject, according to Unity, is a class code that allows you to make Scriptable Objects in your game to store large quantities of shared data independent from script instances.

There are a number of reasons to use Scriptable Objects in Unity. They can increase your workflow, reduce memory usage and even decouple your code architecture. You will also lighten the memory usage of each extra prefab instance because, at its core, a Scriptable Object follows the Flyweight design pattern.

Another benefit of Scriptable Objects, which will be the focus of this tutorial, is using them to swap out data with ease. You’ll be doing this through creating a Sword Merchant shop that will display different stats, costs and descriptions for various swords.

In this tutorial, you’ll learn how to create and use Scriptable Objects in Unity.

Note: This tutorial assumes you know your way around the Unity editor. You should know how to edit code in a code editor and have a basic knowledge of C#. If you need to sharpen your Unity skills, check out some of our other Unity tutorials.

Getting Started

Start by downloading the materials you’ll need using the “Download Materials” link at the top or bottom of this tutorial.

Next, extract the download to a location of your choosing and open up the Scriptable Object Tutorial-Starter project in Unity.

You should see the following folder created as part of the starter project setup:

  • _Setup: For this tutorial, you won’t need to go into this folder at all.
  • Scenes: Contains the Sword Merchant scene that you’ll occupy for the entirety of this tutorial. Make sure you’re in this scene now.
  • Scripts: Currently houses one lone script, but you’ll add more during this tutorial.
  • Sword Icons: Contains a still image of each individual sword.
  • Sword Prefabs: Contains a prefab of every sword in the Sword Merchant scene.

Creating a Scriptable Object

First, make sure you are in the Sword Merchant scene. It should look like this:

Setting Up Your Scriptable Object

It’s time to make your first Scriptable Object!

Under the Scripts folder, create a new script called SwordData. This class will be used as a container for all the sword data that will display in your Sword Merchant shop.

Inside this class, start by deriving from ScriptableObject instead of MonoBehaviour:

public class SwordData : ScriptableObject
{

}

This action tells Unity that you still want to use Unity features and methods, like a typical MonoBehaviour, but you’ll no longer need to put this script onto a GameObject. Instead, it will be treated like any other common asset that can be created, similar to creating a prefab, scene or material.

Fill this script with some serialized fields that will contain all the data, corresponding with the information displayed on the Sword Merchant UI.

public class SwordData : ScriptableObject
{
    [SerializeField]
    private string swordName;
    [SerializeField]
    private string description;
    [SerializeField]
    private Sprite icon;
    [SerializeField]
    private int goldCost;
    [SerializeField]
    private int attackDamage;
}
  • swordName: A string to hold the name of the sword.
  • description: A string to hold the description of the sword.
  • icon: A sprite to hold the icon of the sword.
  • goldCost: An int to hold the gold cost of the sword.
  • attackDamage: An int to hold the attack damage of the sword.

Note: SerializeField

In Unity, the SerializeField attribute allows you to have private script variables that are exposed in the Inspector. This will let you set the values in the editor without giving access to the variable from other scripts.

Each sword will need it’s own unique implementation of the SwordData Scriptable Object. But before you can create these implementations, you will need to add your Scriptable Object to the Asset Menu.

Add your Scriptable Object to the Asset Menu by giving the SwordData class the following attribute:

[CreateAssetMenu(fileName = "New SwordData", menuName = "Sword Data", order = 51)]
public class SwordData : ScriptableObject
  • fileName: The default name when the asset is created.
  • menuName: The name of the asset as it appears in the Asset Menu.
  • order: Where the asset will be located within the Asset Menu. Unity separates assets into sub-groups by factors of 50. So 51 will put your new asset in the second grouping of the Asset Menu.

If all went well, you should be able to go to Assets >> Create and see your new Sword Data asset on the menu. It should be located in the second grouping underneath the Folder asset:

Alternatively, you should be able to right click within the Project window and see your new Sword Data asset there as well:

Adding Data

Stay organized by creating a folder under your Scripts folder called Scriptable Objects, and then another folder inside of tha Scriptable Objects folder called Sword Data.

Inside the newly created Sword Data folder, create your first Sword Data asset.

The new Sword Data asset should still have the default fileName specified earlier. Select the asset and duplicate it six times Ctrl/Cmd + D to create seven total Sword Data assets, one for each of the swords. Now, rename each asset accordingly to match its respective prefab:

Click on the first Sword Data asset in the Sword Data folder, and take a look at the Inspector window:

Here, you’ll see an asset to store information about this particular sword. Fill in the information for each sword. Try to give them all a unique description, gold cost, and attack damage. Be sure to use the appropriate sprites located under the Sword Icons folder for the Icon Sprite field:

Congrats! You’ve created a Scriptable Object and set up various assets using that Scriptable Object.

Using a Scriptable Object

Now it’s time to get the data from these Scriptable Objects.

First, you need to add some public getter methods so that other scripts can access the private fields inside your Scriptable Object. Open up SwordData.cs and add the following under the fields that you added earlier:

    public string SwordName
    {
        get
        {
            return swordName;
        }
    }

    public string Description
    {
        get
        {
            return description;
        }
    }

    public Sprite Icon
    {
        get
        {
            return icon;
        }
    }

    public int GoldCost
    {
        get
        {
            return goldCost;
        }
    }

    public int AttackDamage
    {
        get
        {
            return attackDamage;
        }
    }

Open up Sword.cs and add the following code:

    [SerializeField]
    private SwordData swordData; // 1

    private void OnMouseDown() // 2
    {
        Debug.Log(swordData.name); // 3
        Debug.Log(swordData.Description); // 3
        Debug.Log(swordData.Icon.name); // 3
        Debug.Log(swordData.GoldCost); // 3
        Debug.Log(swordData.AttackDamage); // 3
    }

Here’s what you’ve added with the above code:

  1. The data container for this sword’s data.
  2. OnMouseDown is a built-in MonoBehaviour function that will be called when the user clicks the mouse.
  3. Examples of how to retrieve the data from your Scriptable Object asset

Return to Unity and go to the Hierarchy window. Select the 1_Longsword game object under the sword’s prefab. Add the respective 1_Longsword Data asset to the exposed Sword Data variable under the Sword.cs script in the Inspector window:

Click Play Ctrl/Cmd + P in the Unity editor and then click the sword on the far left:

You should see console output resembling the data provided from the Sword Data asset.

Scriptable Objects allow you to swap out this data with ease. Go ahead and put different Scriptable Object Sword Data in that sword’s Sword Data field.

That was a lot of swords… Here! Have another!

Event-Based Scriptable Objects

Alright, so you’ve created a Scriptable Object, and you saw how you can access its data in-game. But you still need to integrate your Sword Data with the UI!

You could use the quick and dirty Singleton pattern to do this. However, you now have a new found power…

…which is Scriptable Objects! Use it to your advantage to create nice, clean and decoupled code.

For this section you’ll learn how to create Game Events utilizing the UnityEvent class.

Game Events and Listeners

Under the Scripts folder, create the following two scripts GameEvent.cs and GameEventListener.cs. They both depend on each other, so you’ll need both before any errors are cleared.

using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "New Game Event", menuName = "Game Event", order = 52)] // 1
public class GameEvent : ScriptableObject // 2
{
    private List<GameEventListener> listeners = new List<GameEventListener>(); // 3

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

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

    public void UnregisterListener(GameEventListener listener) // 8
    {
        listeners.Remove(listener);
    }
}

Here’s what’s going on in the above code:

  1. Adds the GameEvent as an asset on your asset menu.
  2. The GameEvent is a Scriptable Object so it needs to derive from ScriptableObject.
  3. A list of GameEventListeners that will subscribe to your GameEvent.
  4. A method to invoke all of the subscribers of a GameEvent.
  5. The last GameEventListener to be subscribed will be the first to get invoked (last in, first out).
  6. Invokes each GameEventListeners UnityEvent.
  7. A method to allow GameEventListeners to subscribe to this GameEvent.
  8. A method to allow GameEventListeners to unsubscribe to this GameEvent.
using UnityEngine;
using UnityEngine.Events; // 1

public class GameEventListener : MonoBehaviour
{
    [SerializeField]
    private GameEvent gameEvent; // 2
    [SerializeField]
    private UnityEvent response; // 3

    private void OnEnable() // 4
    {
        gameEvent.RegisterListener(this);
    }

    private void OnDisable() // 5
    {
        gameEvent.UnregisterListener(this);
    }

    public void OnEventRaised() // 6
    {
        response.Invoke();
    }
}

The above code further develops your project:

  1. Required to use the UnityEvent class.
  2. The GameEvent this GameEventListener will subscribe to.
  3. The UnityEvent response that will be invoked when the GameEvent raises this GameEventListener.
  4. Register the GameEvent to the GameEventListener when this GameObject is enabled.
  5. Unregister the GameEvent from the GameEventListener when this GameObject is disabled.
  6. Called when a GameEvent is raised causing the GameEventListener to invoke the UnityEvent.

…my brain. That was a lot, but it will all come together!

Editor Setup

Return to the Unity editor and create a new folder called Game Events underneath Scripts >> ScriptableObjects. Then create seven Game Events from the asset menu, just like you did for each Sword Data asset. Place them under the new Game Events folder.

Replace the code inside your Sword.cs script with the following:

    [SerializeField]
    private GameEvent OnSwordSelected; // 1

    private void OnMouseDown()
    {
        OnSwordSelected.Raise(); // 2
    }

Adding the above code adds two features to your Sword Merchant shop:

  1. The Game Event to be raised when this sword is selected.
  2. Will raise the event when the sword is clicked.

Save the script. Then, under each sword GameObject in the Hierarchy, link the appropriate OnSwordSelected event.

Each sword now has a reference to an event that will be raised when the sword is clicked.

UI Integration

It’s time to get that UI working. The goal is to display the correct Sword Data for each sword that is clicked.

UI References

Before you can update the UI, you need a reference to each piece of the UI. Begin by creating a new script called SwordMerchant.cs and add the following code to the newly created script:

using UnityEngine;
using UnityEngine.UI;

public class SwordMerchant : MonoBehaviour
{
    [SerializeField]
    private Text swordName; // 1
    [SerializeField]
    private Text description; // 2
    [SerializeField]
    private Image icon; // 3
    [SerializeField]
    private Text goldCost; // 4
    [SerializeField]
    private Text attackDamage; // 5
}

With the above code, you’ve added:

  1. A reference to the Text component of the NameText GameObject.
  2. A reference to the Text component of the DescriptionText GameObject.
  3. A reference to the Image component of the Sword_Icon GameObject.
  4. A reference to the Text component of the GoldText GameObject.
  5. A reference to the Text component of the AttackText GameObject.

The above GameObjects are located under SwordMerchantCanvas >> SwordMerchantPanel in the Hierarchy window. Add this script to the SwordMerchantCanvas GameObject in the Hierarchy window and then set all the references:

UI Listeners and Responses

All of your swords have an event that the UI can subscribe to using the GameEventListener script. Add a GameEventListener for each OnSwordSelected event onto the SwordMerchantCanvas GameObject:

As you may have noticed, your Game Event Listener has two fields: A Game Event that it listens to, and a response that it will invoke when the Game Event is raised.

In this case, the response will update the UI. Add the following method to your SwordMerchant.cs script:

    public void UpdateDisplayUI(SwordData swordData)
    {
        swordName.text = swordData.SwordName;
        description.text = swordData.Description;
        icon.sprite = swordData.Icon;
        goldCost.text = swordData.GoldCost.ToString();
        attackDamage.text = swordData.AttackDamage.ToString();
    }

This method takes in a Sword Data asset, and then updates each UI field to the corresponding Sword Data field. Notice GoldCost and AttackDamage return an int so you need to convert that to a string for the text.

With your new method, you can add a response to each GameEventListener.

For each response you add, you’ll need to set the None (Object) field to a reference to your SwordMerchantCanvas GameObject. After this, select SwordMerchant.UpdateDisplayUI from the drop down menu to the right of the drop down listing Runtime Only.

Be sure to use the correct Sword Data asset for each OnSwordSelected event.

You should be able play the game, click on a sword and see the UI update accordingly!

Because you are using Game Events, you can simply turn off the SwordMerchantCanvas, and everything should still run smoothly, just without the UI. This means your sword prefabs are decoupled from the SwordMerchantCanvas

Where to Go From Here?

If you missed anything along the way, you can download the final project for this tutorial using the “Download Materials” link at the top or bottom of this tutorial.

If you’d like to go a step further, try to make each sword play a different sound. Try extending the Sword Data Scriptable Object and listening for the OnSwordSelected GameEvents.

Looking to learn more about Unity? Watch our Unity video tutorial series or read our written Unity tutorials.

Feel free to ask any questions or leave any comments in the discussion forum below.

Contributors

Comments