Unity Tutorials Beta

Learn how to create games in Unity, a powerful and popular game engine.

ScriptableObject Tutorial: Getting Started

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

4.9/5 12 Ratings

Version

  • C#4, Unity 2019.1, Unity

Update May 2019: This tutorial was updated to Unity 2019.1 by Ben MacKinnon. Original post by Jeff Fisher.

ScriptableObject, according to Unity, is an inheritable class that allows you to store large quantities of shared data, independent from script instances.

There are a number of reasons to use ScriptableObject 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 ScriptableObject follows the Flyweight design pattern.

Another benefit of ScriptableObjects, which will be the focus of this tutorial, is using them to swap out data with ease. You’ll be doing this by 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 ScriptableObjects 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 empty script, but you’ll add more during this tutorial.
  • Sword Icons: Contains thumbnails of each individual sword.
  • Sword Prefabs: Contains a prefab of every sword in the Sword Merchant scene.

Creating a ScriptableObject

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

Setting Up Your ScriptableObject

It’s time to make your first ScriptableObject!

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 ScriptableObject. But before you can create these implementations, you will need to add your ScriptableObject to the Asset Menu.

Add your ScriptableObject 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 the 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 ScriptableObject and set up various assets using that ScriptableObject.

Using a ScriptableObject

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

First, you need to add some public getter methods so that other scripts can access the private fields inside your ScriptableObject. 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.SwordName); // 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 ScriptableObject asset

Return to Unity and go to the Hierarchy window. Select 1_Longsword under the Swords GameObject. Add the respective 1_Longsword data asset to the Sword‘s Sword Data slot:

Click Play 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.

ScriptableObjects allow you to swap out this data with ease. Go ahead and put a different ScriptableObject Sword Data in that sword’s Sword Data field.

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

Event-Based ScriptableObjects

Alright, so you’ve created a ScriptableObject, 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 ScriptableObjects! 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.

First up is GameEvent:

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 ScriptableObject 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.

Now for GameEventListener:

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 ScriptsScriptableObjects. 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 does the following to your Sword Merchant shop:

  1. Exposes a Game Event to be raised when a sword is selected.
  2. Raises 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 in RWScripts called SwordMerchant.cs and add the following code:

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 SwordMerchantCanvasSwordMerchantPanel in the Hierarchy window. Add your new Sword Merchant component 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 Game Event Listener component for each OnSwordSelected event you now have 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!

This set up may seem a bit convoluted at first. But 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 ScriptableObject 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.

Average Rating

4.9/5

Add a rating for this content

12 ratings

Contributors

Comments