Unity 6.3
0 онлайн 86 гостей 3 в системе
Вход
Модульная игровая архитектура на ScriptableObjects Глава 3 из 12 Оригинал, стр. 10

ScriptableObject и MonoBehaviour

Русский

ScriptableObject и MonoBehaviour

На первый взгляд объекты ScriptableObject устроены просто: их API содержит всего несколько методов. В данном случае это преимущество, поскольку чем проще система, тем меньше вероятность ошибок.

UML-диаграмма объектов Unity

Как и MonoBehaviour, класс ScriptableObject наследуется от UnityEngine.Object.

Сравнение Лучше всего понять ScriptableObject в сравнении с родственным ему классом MonoBehaviour. В таблице показаны их сходства и различия. MonoBehaviour

ScriptableObject

И MonoBehaviour, и ScriptableObject являются типами. скриптов. Классы MonoBehaviour и ScriptableObject наследуются от UnityEngine.Object.

Компоненты MonoBehaviour получают обратные вызовы от Unity. Чтобы связать методы с циклом PlayerLoop игрового движка, назовите их в соответствии с функциями событий MonoBehaviour, например Update(). Например: Start, Awake, Update, OnEnable, OnDisable, OnCollisionEnter

Объекты ScriptableObject не получают большинство обратных вызовов жизненного цикла Unity, таких как Update, Start и FixedUpdate. Во время выполнения объекты ScriptableObject поддерживают ограниченный набор функций событий: Awake, OnEnable, OnDestroy и OnDisable. Редактор Unity также вызывает OnValidate и Reset при работе с окном Inspector. В ScriptableObject можно определять и другие методы, но PlayerLoop не вызывает их автоматически.

Во время выполнения компоненты MonoBehaviour должны быть прикреплены к объектам GameObject.

Объекты ScriptableObject не привязаны к конкретному GameObject.

Для создания MonoBehaviour во время выполнения используйте API AddComponent.

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

Данные MonoBehaviour сохраняются внутри сцен и префабов.

Каждый экземпляр ScriptableObject можно сохранить в отдельном файле ассета на уровне проекта.

В редакторе Unity изменения значений MonoBehaviour сбрасываются после выхода из режима Play.

В редакторе Unity изменения значений ScriptableObject не сбрасываются после выхода из режима Play. В автономной сборке изменения значений ScriptableObject во время выполнения не сохраняются.

MonoBehaviour и ScriptableObject поддерживают сериализацию и отображаются в окне Inspector.

Обратные вызовы и сообщения Объекты ScriptableObject поддерживают лишь часть функций событий, доступных MonoBehaviour. В них можно создавать собственные методы, но вызывать эти методы необходимо самостоятельно. В таблице ниже приведены только методы, которые PlayerLoop вызывает автоматически.

Функция события

Когда вызывается

(во время выполнения)

Awake

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

OnEnable

Вызывается сразу после Awake при загрузке или создании экземпляра ScriptableObject. OnEnable выполняется при вызове ScriptableObject.CreateInstance или после успешной повторной компиляции скриптов.

OnDisable

Вызывается, когда ScriptableObject выходит из области использования: например, при загрузке сцены без ссылок на его ассет или непосредственно перед OnDestroy этого ScriptableObject.

Unity также выполняет OnDisable перед повторной компиляцией скриптов. При входе в режим Play метод OnDisable вызывается непосредственно перед OnEnable.

OnDestroy

Вызывается при уничтожении ScriptableObject, например при его удалении в редакторе Unity или из кода. Если ScriptableObject создан во время выполнения, OnDestroy также вызывается при завершении приложения или выходе редактора Unity из режима Play. Примечание: уничтожается только нативная C++-часть объекта. Подробнее см. раздел «Создание и жизненный цикл».

Функции только для редактора Unity

Когда вызывается

OnValidate

Выполняется при загрузке скрипта или изменении значения в окне Inspector. Метод можно использовать, чтобы удерживать данные в допустимом диапазоне.

Reset

Вызывается при выборе команды Reset в контекстном меню окна Inspector.

Чтобы уничтожить ScriptableObject, удалите его в редакторе Unity либо вызовите Destroy или DestroyImmediate во время выполнения. Ниже кратко показаны функции событий и жизненный цикл ScriptableObject. Сравните их с порядком выполнения функций событий MonoBehaviour, двигаясь сверху вниз.

Инициализация

Редактор Unity

Завершение работы

Функции событий ScriptableObject и порядок их выполнения

Файлы Одно из главных различий между MonoBehaviour и ScriptableObject заключается в способе сохранения данных. Unity сериализует компоненты MonoBehaviour внутри файлов сцен или префабов. Сохраняются следующие данные: - Сам MonoBehaviour - Связанный с ним GameObject - Его Transform - Остальные компоненты и MonoBehaviour на том же GameObject

MonoBehaviour прикрепляется к GameObject

ScriptableObject находится в проекте ScriptableObject и MonoBehaviour

В отличие от MonoBehaviour, Unity сохраняет объекты ScriptableObject в отдельных файлах ассетов. Такие файлы меньше, а данные в них лучше обособлены, чем в случае с MonoBehaviour.

Если в окне Project Settings > Asset Serialization выбрать Mode: Force Text, ассет ScriptableObject можно открыть в текстовом редакторе. Он будет выглядеть примерно так:

Экземпляр ScriptableObject, сериализованный в текстовом виде

YAML - не язык разметки Unity использует высокопроизводительную библиотеку сериализации, реализующую подмножество спецификации YAML. Это легковесный и удобочитаемый язык, родственный XML и JSON. В YAML данные организованы в иерархию вложенных элементов. У каждого объекта есть Class ID, File ID и тип объекта. Обратите внимание: для ScriptableObject используется тип «MonoBehaviour», а не отдельный собственный тип.

ID класса

ID файла

Тип объекта

Пары ключ-значение

Заголовок объекта в YAML

Под каждым объектом перечислены его сериализованные свойства в виде пар «ключ значение». Подробнее см. статью «Разбираемся в языке сериализации YAML в Unity».

Создание и жизненный цикл Жизненный цикл ScriptableObject похож на жизненный цикл любого другого ассета проекта, например материала или текстуры. Как и в предыдущем примере, добавьте к скрипту атрибут [CreateAssetMenu], чтобы создать пользовательскую команду меню в редакторе Unity. При необходимости можно задать имя файла по умолчанию через fileName и порядок пункта меню через order. Ниже показан наиболее распространенный способ создания ассета ScriptableObject.

C#
[CreateAssetMenu(fileName="MyScriptableObject"] public class MyScriptableObject: ScriptableObject { public int SomeVar; }
Чтобы создать экземпляр ScriptableObject во время выполнения, вызовите статический метод CreateInstance: ScriptableObject.CreateInstance<MyScriptableObjectClass>();

Уничтожение ScriptableObject Как и другие объекты Unity, ScriptableObject состоит из нативной C++-части и управляемой C#-части. Нативную часть можно уничтожить напрямую, но управляемая останется до очистки сборщиком мусора (GC). Такая очистка выполняется при смене сцены или вызове Resources.UnloadUnusedAssets.

Нативная сторона

Экземпляр C++ ScriptableObject

Управляемая сторона

Экземпляр C# ScriptableObject

Ссылка на ScriptableObject

У ScriptableObject есть нативная и управляемая части.

Чтобы не задерживать сборку мусора, явно присвойте null всем ссылкам на ассет ScriptableObject. Примечание: ссылки важно обнулить до вызова Destroy или DestroyImmediate. Иначе ссылка в редакторе Unity может отображаться как null, хотя управляемый объект все еще существует. GC очистит его только после удаления всех ссылок на ScriptableObject.

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

English

ScriptableObjects versus MonoBehaviours

On the surface, ScriptableObjects are simple. The API sports only a few methods. In this case, that’s a good thing. Simplicity means less can go wrong.

Unity Object UML

Like MonoBehaviour, the ScriptableObject class derives from UnityEngine.Object class.

Comparison Probably the best way to understand ScriptableObjects is to compare them with their siblings, MonoBehaviours. This chart breaks down their similarities and differences. MonoBehaviour

ScriptableObject

MonoBehaviours and ScriptableObjects are both scripts. MonoBehaviour and ScriptableObject classes derive from UnityEngine.Object. MonoBehaviours receive callbacks from Unity. Connect your methods to the game engine’s player loop by naming them according to MonoBehaviour’s event functions like Update(). e.g., Start, Awake, Update, OnEnable, OnDisable, OnCollisonEnter

ScriptableObjects do not receive most Unity lifecycle callbacks from Unity like Update, Start or FixedUpdate. ScriptableObjects support a limited number of event functions, including Awake, OnEnable, OnDestroy, and OnDisable at runtime. The Editor also calls OnValidate and Reset from the Inspector. You can create other methods on a ScriptableObject, but the player loop does not invoke them automatically.

MonoBehaviours must be attached to GameObjects at runtime.

ScriptableObjects are not attached to any specific GameObject.

If you create one at runtime, use the AddComponent API.

Save ScriptableObjects into their own asset files at the Project level. Then, reference the ScriptableObject asset from a Monobehaviour or other script.

When we do save them, we save MonoBehaviours data into Scenes and prefabs.

Each ScriptableObject instance can be saved into its own file at the Project level.

In the Editor, changes to MonoBehaviour values reset when exiting Play mode.

In the Editor, changes to ScriptableObject values do not reset when exiting Play mode. In a standalone build, changes to ScriptableObject values at runtime are not saved.

MonoBehaviours and ScriptableObjects are both serializable and can be viewed in the Inspector.

Callbacks and messages ScriptableObjects have a subset of the event functions available to MonoBehaviours. You can create your own methods in your ScriptableObjects too, but you need to call them yourself. The table below shows only the methods that will be called automatically in the PlayerLoop. Event function

When it executes

(runtime) Awake

This is called as the ScriptableObject script starts, similar to MonoBehaviour’s Awake callback. This also executes when the game is launched or if a scene loads with a reference to the ScriptableObject asset.

OnEnable

This is called when the ScriptableObject is loaded or instantiated, immediately after the Awake callback. OnEnable executes during the ScriptableObject.CreateInstance or after successful script recompilation.

OnDisable

This is called when the ScriptableObject goes out of scope. This happens if you load a Scene without references to the ScriptableObject asset or right before the ScriptableObject’s OnDestroy. Unity also executes OnDisable before script recompilations. When entering Play mode, OnDisable runs right before OnEnable.

OnDestroy

This is called when something destroys the ScriptableObject, either deleting it in the Editor or from code. If you’ve created the ScriptableObject at runtime, OnDestroy also invokes when the application quits or if the Editor exits Play mode. Note: This only destroys the native C++ part of the object. See Lifecycle and Creation for more information.

Editor-only functio ns

When it executes

OnValidate

OnValidate executes when the script is loaded or a value changes in the Inspector. This can be used to ensure that your data stays within a certain range.

Reset

Reset invokes when you hit the Reset button in the Inspector context menu.

To destroy a ScriptableObject, remove it from the Editor or call Destroy/DestroyImmediate at runtime. Here’s a brief overview of a ScriptableObject’s event functions and life cycle. Compare this with the order of execution of MonoBehaviour event functions, starting from the top.

ScriptableObject event functions and execution order

Files One of their biggest differences between MonoBehaviours and ScriptableObjects is how they save their data. Unity serializes MonoBehaviours within either a Scene or a prefab file. The saved data contains: —

The MonoBehaviour itself

The attached GameObject

Its Transform

Any other components and MonoBehaviours on the attached GameObject

ScriptableObject versus MonoBehaviour

In contrast, Unity saves ScriptableObjects into their own asset files. These files are smaller and more compartmentalized than MonoBehaviours.

If you choose to use Mode: Force Text in the Project Settings > Asset Serialization window, you can open a ScriptableObject asset in a text editor. It might look something like this:

A ScriptableObject instance, serialized as text

YAML ain’t markup language Unity uses a high performance serialization library that implements a subset of the YAML specification. This is a lightweight, easy-to-read language related to XML and JSON. In YAML, data is organized as a hierarchy of nested elements. Each object has a Class ID, File ID, and object type. Note that ScriptableObjects use “MonoBehaviour” as their object type, instead of defining their own.

An object header in YAML

Under each object are its serialized properties, represented by key-value pairs. For more information, read the blog post “Understanding Unity’s serialization language, YAML”.

Creation and lifecycle The lifecycle of a ScriptableObject is similar to that of any other asset (materials, textures, and so on) in your project. As in the previous example, apply the

C#
[CreateAssetMenu] attribute to your script in order to add a custom menu action to the Editor. You can optionally specify the default fileName or menu item order. The following code is the most common way to create a ScriptableObject asset. [CreateAssetMenu(fileName="MyScriptableObject"] public class MyScriptableObject: ScriptableObject { public int SomeVar; }
If you need to make a ScriptableObject instance at runtime, you can call the static CreateInstance method: ScriptableObject.CreateInstance<MyScriptableObjectClass>();

Destroying ScriptableObjects Like other Unity objects, a ScriptableObject consists of a native C++ portion, as well as a C# managed portion. You can destroy the native C++ directly, but the managed part remains until the asset garbage collector (GC) clears it. The GC cleanup occurs if you change scenes or call Resources.UnloadUnusedAssets.

ScriptableObjects have both a native and managed side.

Explicitly set any references to the ScriptableObject asset to null to avoid delaying garbage collection. Note: It’s important to do this before calling Destroy or DestroyImmediate. Otherwise, the reference to the object may be nominally marked “null” in the Editor, even if it isn’t really null. GC cleanup only happens once there are no more references to the ScriptableObject.

Once you have the knack of creating and destroying your own ScriptableObjects, it’s time to explore some creative ways to use them in your game application.