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.
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.
Create skills and add them to the player's stats.
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!