How to Properly Use ScriptableObject in Unity

Introduction

In this article, I will show you how to use the ScriptableObject class in Unity correctly. We will create a small game for demonstration purposes, in which the player can control a character with different parameters, skills, and inventory. We will look at creating and using ScriptableObject to store data. At the end, you will find the pros and cons of using this method.

Introduction to ScriptableObject

What is ScriptableObject and why is it needed?

ScriptableObject is a class in Unity that allows you to store data separately from game objects. This is especially useful for managing data that changes frequently or is reused. Common use cases include:

• Storing game data (e.g. character parameters, level settings).

• Game state management.

• Creation of editors and tools.

Example of using ScriptableObject in Unity

general review

We will create a mini-game where the player can control a character with different parameters, skills and inventory. All functionality will be built on ScriptableObject to store data of characters, skills and items.

Step 1: Create a ScriptableObject for the character parameters

Let's start by creating a ScriptableObject class to store character parameters.

using UnityEngine;

[CreateAssetMenu(fileName = "NewCharacterStats", menuName = "Character Stats")]
public class CharacterStats : ScriptableObject
{
    [SerializeField] private string _characterName;
    [SerializeField] private int _health;
    [SerializeField] private int _attackPower;
    [SerializeField] private int _defense;
    [SerializeField] private Skill[] _skills;

    public string CharacterName => _characterName;
    public int Health => _health;
    public int AttackPower => _attackPower;
    public int Defense => _defense;
    public Skill[] Skills => _skills;
}
Explanation of the code:

• CreateAssetMenu allows you to create assets via the context menu in the Unity Editor.

• Character stats include name, health, attack power, defense, and skill array.

Step 2: Create a ScriptableObject for skills

Now let's create a ScriptableObject to store the skill data.

using UnityEngine;

[CreateAssetMenu(fileName = "NewSkill", menuName = "Skill")]
public class Skill : ScriptableObject
{
    [SerializeField] private string _skillName;
    [SerializeField] private int _power;
    [SerializeField] private float _cooldown;

    public string SkillName => _skillName;
    public int Power => _power;
    public float Cooldown => _cooldown;
}
Explanation of the code:

• CreateAssetMenu allows you to create assets via the context menu in the Unity Editor.

• Skill data includes name, power, and cooldown time.

Step 3: Create a ScriptableObject for the items

Let's create a ScriptableObject to store data about items.

using UnityEngine;

[CreateAssetMenu(fileName = "NewItem", menuName = "Inventory Item")]
public class InventoryItem : ScriptableObject
{
	[SerializeField] private string _itemName;
	[SerializeField] private Sprite _itemIcon;
	[SerializeField] private int _itemID;

	public string ItemName => _itemName;
	public Sprite ItemIcon => _itemIcon;
	public int ItemID => _itemID;
}
Explanation of the code:

• CreateAssetMenu allows you to create assets via the context menu in the Unity Editor.

• Item data includes name, icon, and unique identifier.

Step 4: Using ScriptableObject in MonoBehaviour

Let's create a MonoBehaviour to control the character, which will use a ScriptableObject to store parameters, skills, and inventory.

using System.Collections.Generic;
using UnityEngine;

public class Character : MonoBehaviour
{
    [SerializeField] private CharacterStats _stats;
    [SerializeField] private List<InventoryItem> _inventory = new();

    public void AddItemToInventory(InventoryItem item)
    {
        _inventory.Add(item);
        Debug.Log($"Added item: {item.ItemName}");
    }

    private void Start()
    {
        Debug.Log($"Name: {_stats.CharacterName}, Health: {_stats.Health}, Attack: {_stats.AttackPower}, Defense: {_stats.Defense}");
        
        foreach (var skill in _stats.Skills)
        {
            Debug.Log($"Skill: {skill.SkillName}, Power: {skill.Power}, Cooldown: {skill.Cooldown}");
        }
    }
}
Explanation of the code:

• The _stats and _inventory variables store references to ScriptableObject objects.

• The Start method outputs the character's parameters and skills to the console.

• The AddItemToInventory method adds an item to the character's inventory.

3. Creating a mini-game

general review

Let's create a scene where the player can control the character, collect items, use skills and see them in the inventory.

Step 1: Create a character and bind parameters

In Unity, we will create a character prefab and bind parameters to it using ScriptableObject.

1. Create a GameObject for the character.

2. Add a Character component and bind CharacterStats via the inspector.

Creating a ScriptableObject

Creating a ScriptableObject

Setting up a ScriptableObject

Setting up a ScriptableObject

Adding stats to a player

Adding stats to a player

Step 2: Create items and bind to inventory

Let's add some objects to the scene and set up their interaction with the character.

1. Create multiple instances of InventoryItem.

2. Add them to the inventory list of the Character component.

  1. Create skills and add them to the player's stats.

    Creating skills

    Creating skills

    Adding skills to a player

    Adding skills to a player

Step 3: Implementing the use of skills

Let's add the ability for a character to use skills.

using System.Collections;
using UnityEngine;

public class SkillUser : MonoBehaviour
{
    [SerializeField] private Character _character;

    private bool _isAbleToUseSkill = true;

    private void Update()
    {
        if (_isAbleToUseSkill)
        {
            for (int i = 0; i < _character.Stats.Skills.Length; i++)
            {
                if (Input.GetKeyDown(KeyCode.Alpha1 + i))
                {
                    UseSkill(i);
                }
            }
        }
    }

    private void UseSkill(int index)
    {
        if (index < _character.Stats.Skills.Length)
        {
            Skill skill = _character.Stats.Skills[index];
            Debug.Log($"Using skill: {skill.SkillName}");
            StartCoroutine(Cooldown(skill));
        }
    }

    private IEnumerator Cooldown(Skill skill)
    {
        _isAbleToUseSkill = false;
        Debug.Log($"Skill {skill.SkillName} on cooldown for {skill.Cooldown} seconds.");
        yield return new WaitForSeconds(skill.Cooldown);
        Debug.Log($"Skill {skill.SkillName} is ready to use again.");
        _isAbleToUseSkill = true;
    }
}
Explanation of the code:

• The SkillUser component controls the use of character skills.

• The UseSkill method activates the skill and starts the cooldown.

Add this script to the character and drag the Character component to the corresponding field

Now we can run the scene and check the functionality of our mini-game through the console and if we like the result, add visual implementation.

P.s.

I specifically did not write the logic for working with items from the inventory, so as not to clutter the tutorial with unnecessary information, after all, the article is about something else)
If you are suddenly interested, write in the comments “Finish the game” and I will add the remaining functionality

4. Advantages and Disadvantages of ScriptableObject

Advantages

Ease of data management: Separate data from logic, simplify changing parameters.

Reuse: Easy use of the same object in different places of the project.

Reduced memory load: ScriptableObjects are loaded only once and can be used multiple times.

Ease of testing: Ease of testing and debugging data.

Flaws

Limited scripting support: Not suitable for all data types and logic.

The Need to Understand How the Unity Editor Works: Requires knowledge of working with the editor and ScriptableObject.

No real time updates: Changes to ScriptableObject are not automatically updated in related objects.

5. Conclusion

We looked at how to use ScriptableObject in Unity to create a more complex mini-game with character management, skills, and inventory. ScriptableObject provides a convenient way to manage data, improving the architecture and performance of projects. Try implementing this approach in your projects and evaluate its benefits.

If you liked the article, be sure to vote for it! That way I'll know you liked it and will consider other topics related to Unity!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *