Введение

В этой статье я покажу, как правильно пользоваться классом ScriptableObject в Unity. Мы создадим небольшую игру для наглядности, в которой игрок сможет управлять персонажем с различными параметрами, навыками и инвентарем. Мы рассмотрим создание и использование ScriptableObject для хранения данных. В конце вы найдете плюсы и минусы использования данного метода.

Введение в ScriptableObject

Что такое ScriptableObject и зачем он нужен?

ScriptableObject - это класс в Unity, который позволяет хранить данные отдельно от игровых объектов. Это особенно полезно для управления данными, которые часто изменяются или используются многократно. Основные случаи использования включают:

• Хранение игровых данных (например, параметры персонажей, настройки уровней).

• Управление состоянием игры.

• Создание редакторов и инструментов.

Пример использования ScriptableObject в Unity

Общий обзор

Мы создадим мини-игру, где игрок может управлять персонажем с различными параметрами, навыками и инвентарем. Весь функционал будет построен на ScriptableObject для хранения данных персонажей, навыков и предметов.

Шаг 1: Создание ScriptableObject для параметров персонажа

Начнем с создания класса ScriptableObject для хранения параметров персонажа.

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;
}
Пояснение к коду:

• CreateAssetMenu позволяет создавать объекты через контекстное меню в Unity Editor.

• Параметры персонажа включают имя, здоровье, силу атаки, защиту и массив навыков.

Шаг 2: Создание ScriptableObject для навыков

Теперь создадим ScriptableObject для хранения данных о навыках.

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;
}
Пояснение к коду:

• CreateAssetMenu позволяет создавать объекты через контекстное меню в Unity Editor.

• Данные о навыке включают имя, силу и время перезарядки.

Шаг 3: Создание ScriptableObject для предметов

Создадим ScriptableObject для хранения данных о предметах.

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;
}
Пояснение к коду:

• CreateAssetMenu позволяет создавать объекты через контекстное меню в Unity Editor.

• Данные о предмете включают имя, иконку и уникальный идентификатор.

Шаг 4: Использование ScriptableObject в MonoBehaviour

Создадим MonoBehaviour для управления персонажем, который будет использовать ScriptableObject для хранения параметров, навыков и инвентаря.

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}");
        }
    }
}
Пояснение к коду:

• Переменные _stats и _inventory хранят ссылки на объекты ScriptableObject.

• Метод Start выводит параметры персонажа и его навыки в консоль.

• Метод AddItemToInventory добавляет предмет в инвентарь персонажа.

3. Создание мини-игры

Общий обзор

Создадим сцену, на которой игрок сможет управлять персонажем, собирать предметы, использовать навыки и видеть их в инвентаре.

Шаг 1: Создание персонажа и привязка параметров

В Unity создадим префаб персонажа и привяжем к нему параметры, используя ScriptableObject.

1. Создайте GameObject для персонажа.

2. Добавьте компонент Character и привяжите CharacterStats через инспектор.

Создание ScriptableObject
Создание ScriptableObject
Настройка ScriptableObject
Настройка ScriptableObject
Добавление статов игроку
Добавление статов игроку

Шаг 2: Создание предметов и привязка к инвентарю

Добавим несколько предметов в сцену и настроим их взаимодействие с персонажем.

1. Создайте несколько экземпляров InventoryItem.

2. Добавьте их в список inventory у компонента Character.

  1. Создайте скилы и добавьте в статы игрока.

    Создание скилов
    Создание скилов
    Добавление скилов игроку
    Добавление скилов игроку

Шаг 3: Реализация использования навыков

Добавим возможность использования навыков персонажем.

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;
    }
}
Пояснение к коду:

• Компонент SkillUser управляет использованием навыков персонажа.

• Метод UseSkill активирует навык и запускает перезарядку.

Добавьте этот скрипт персонажу и перенесите компонент Character в соответствующее поле

Теперь можно запустить сцену и проверить работоспособность нашей мини-игры через консоль и есть нам понравится результат, добавлять визуальную реализацию.

P.s.

Я специально не стал писать логику для работы с предметами из инвентаря, чтобы не загромождать туториал лишней инфой, все таки статья про другое)
Если вам вдруг интересно, пишите в комментария "Доделай игру" и я добавлю оставшийся функционал

4. Преимущества и недостатки ScriptableObject

Преимущества

Удобство управления данными: Разделение данных от логики, упрощение изменения параметров.

Повторное использование: Легкое использование одного и того же объекта в разных местах проекта.

Снижение загрузки памяти: ScriptableObject загружаются только один раз и могут быть использованы многократно.

Простота тестирования: Легкость тестирования и отладки данных.

Недостатки

Ограниченная поддержка сценариев: Не подходит для всех типов данных и логики.

Необходимость понимания работы Unity Editor: Требуется знание работы с редактором и ScriptableObject.

Нет обновлений в реальном времени: Изменения в ScriptableObject не обновляются автоматически в связанных объектах.

5. Заключение

Мы рассмотрели, как использовать ScriptableObject в Unity для создания более сложной мини-игры с управлением персонажем, его навыками и инвентарем. ScriptableObject предоставляет удобный способ управления данными, улучшая архитектуру и производительность проектов. Попробуйте внедрить этот подход в своих проектах и оцените его преимущества.

Если тебе понравилась статья, обязательно голосуй за нее! Так я пойму что тебе она понравилась и рассмотрю другие тематики, связанные с Unity!

Комментарии (3)


  1. VitalyZaborov
    07.07.2024 04:33
    +3

    Удобство управления данными

    Когда вам, чтобы поменять хп у сотни врагов в вашей игре, нужно выбрать каждого персонально и изменить поле в редакторе - это не удобная работа с данными. Достоинства ScriptableObject совершенно не в этом, а в том, что его полями могут быть не простые типы, а сущности движка: спрайты, префабы, прочие ассеты и другие SO.

    Например, вам нужно создать описание персонажа, которое объединит его префаб, спрайт иконки и контроллер анимации. Вот тут без SO не обойтись. Можно, конечно, хранить эти ассеты в Resources с определёнными именами, но такой способ имеет много минусов и разработчиками движка не рекоментдуется.

    Данные из простых типов (например, характеристики персонажа) гораздо удобнее хранить в обычной экселевской таблице (или в каком-то удобном вам текстовом формате) и уже оттуда генерить в движок. Тогда эти данные легко массово редактировать и их можно мержить.


    1. ArtemiZ_GD Автор
      07.07.2024 04:33

      Спасибо за отзыв)

      В общем то вы правы, но сотни врагов будут не в каждой игре, следовательно нет надобности всегда работать с таблицами. А вот в мое случае у персонажа есть еще и набор скилов, которые вы не сможете таким образом настраивать.

      Нестандартные типы данных я как раз таки показал в статье.


    1. shai_hulud
      07.07.2024 04:33
      +1

      Данные из простых типов (например, характеристики персонажа) гораздо
      удобнее хранить в обычной экселевской таблице (или в каком-то удобном
      вам текстовом формате) и уже оттуда генерить в движок.

      Или в специализированном инструменте для этого - статичной БД. https://assetstore.unity.com/packages/tools/visual-scripting/charon-game-data-editor-95117