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. By Ben MacKinnon.

4.5 (45) · 1 Review

Download materials
Save for later
Share
You are currently viewing page 2 of 3 of this article. Click here to view the first page.

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