Класс, от которого можно наследоваться, если нужно создавать объекты, существующие независимо от GameObject.
Используйте ScriptableObjects для централизации данных таким образом, чтобы они были удобно доступны из сцен и ассетов в рамках проекта.
Создание экземпляров объектов ScriptableObject с помощью CreateInstance.
Вы можете сохранить ScriptableObjects в файлы ассетов либо из Редактора UI (см. CreateAssetMenuAttribute), или по телефону AssetDatabase.CreateAsset Вы также можете генерировать ScriptableObjects в качестве выходного файла из ScriptedImporterСм. AssetImportContext.AddObjectToAsset.
Если a ScriptableObject не был сохранен в ассете, и на него делается ссылка из объекта в сцене, Unity сериализирует его непосредственно в файл сцены. Для ScriptableObjects которые имеют только один постоянный экземпляр в проекте и используются только в режиме редактирования, вы можете использовать ScriptableSingleton<T0> базовый класс. Для одиночных ScriptableObject времени выполнения вам придётся самостоятельно реализовать паттерн «одиночка» и вручную управлять созданием и загрузкой ассета.
Доступ к ранее сохраненным объектам с помощью AssetDatabaseнапример AssetDatabase.LoadAssetAtPath. Когда ссылка на ScriptableObject делается из поля на MonoBehaviour, ScriptableObject загружается автоматически, так что скрипт может просто использовать значение поля, чтобы добраться до него.
Поля C# ScriptableObject сериализированы точно так же, как поля на MonoBehaviour, см. Сериализация скриптов Классы, которые включают большие массивы или другие потенциально большие данные, должны быть объявлены с помощью PreferBinarySerialization атрибут, потому что YAML не является эффективным представлением для такого типа данных.
Вызов Destroy на ScriptableObject освобождает связанные с ним нативные ресурсы, но сам объект остаётся в памяти до сборки мусора. Объекты в таком отсоединённом состоянии выглядят как null, хотя на самом деле таковыми не являются. Однако этот класс не поддерживает Нулевой условный оператор (?.) и оператор нулевого слияния (??).
Следующий пример показывает типичное применение ScriptableObject: разные наборы параметров транспортных средств представлены полями класса VehicleTypeInfo, производного от ScriptableObject. У каждого типа транспорта будет собственный файл-ассет с подходящими значениями параметров. Каждый экземпляр транспорта в игре ссылается на ассет своего типа, а не хранит собственную избыточную копию параметров. Такой подход удобен: поведение транспорта настраивается в одном месте. Он также выгоден по производительности, особенно когда объём общих данных велик.
В первом скрипте примера реализован класс, производный от ScriptableObject.
using UnityEngine;
[CreateAssetMenu]
public class VehicleTypeInfo : ScriptableObject
{
// Class that represents a specific type of vehicle
[Range(0.1f, 100f)]
public float m_MaxSpeed = 0.1f;
[Range(0.1f, 10f)]
public float m_MaxAcceration = 0.1f;
// This class could have many other vehicle parameters, such as Turning Radius, Range, Damage etc
}
Второй скрипт реализует MonoBehaviour, который использует ScriptableObject.
using UnityEngine;
using UnityEditor;
public class VehicleInstance : MonoBehaviour
{
// Snippet of a MonoBehaviour that would control motion of a specific vehicle.
// In PlayMode it accelerates up to the maximum speed permitted by its type
[Range(0f, 200f)]
public float m_CurrentSpeed;
[Range(0f, 50f)]
public float m_Acceleration;
// Reference to the ScriptableObject asset
public VehicleTypeInfo m_VehicleType;
public void Initialize(VehicleTypeInfo vehicleType)
{
m_VehicleType = vehicleType;
m_CurrentSpeed = 0f;
m_Acceleration = Random.Range(0.05f, m_VehicleType.m_MaxAcceration);
}
void Update()
{
m_CurrentSpeed += m_Acceleration * Time.deltaTime;
// Use parameter from the ScriptableObject to control the behaviour of the Vehicle
if (m_VehicleType && m_VehicleType.m_MaxSpeed < m_CurrentSpeed)
m_CurrentSpeed = m_VehicleType.m_MaxSpeed;
gameObject.transform.position += gameObject.transform.forward * Time.deltaTime * m_CurrentSpeed;
}
}
public class ScriptableObjectVehicleExample
{
[MenuItem("Example/Setup ScriptableObject Vehicle Example")]
static void MenuCallback()
{
// This example programmatically performs steps that would typically be performed from the Editor's user interface
// to creates a simple demonstration. When going into Playmode the three objects will move according to the limits
// set by their vehicle type.
// Step 1 - Create or reload the assets that store each VehicleTypeInfo object.
VehicleTypeInfo wagon = AssetDatabase.LoadAssetAtPath<VehicleTypeInfo>("Assets/VehicleTypeWagon.asset");
if (wagon == null)
{
// Create and save ScriptableObject because it doesn't exist yet
wagon = ScriptableObject.CreateInstance<VehicleTypeInfo>();
wagon.m_MaxSpeed = 5f;
wagon.m_MaxAcceration = 0.5f;
AssetDatabase.CreateAsset(wagon, "Assets/VehicleTypeWagon.asset");
}
VehicleTypeInfo cruiser = AssetDatabase.LoadAssetAtPath<VehicleTypeInfo>("Assets/VehicleTypeCruiser.asset");
if (cruiser == null)
{
cruiser = ScriptableObject.CreateInstance<VehicleTypeInfo>();
cruiser.m_MaxSpeed = 75f;
cruiser.m_MaxAcceration = 2f;
AssetDatabase.CreateAsset(cruiser, "Assets/VehicleTypeCruiser.asset");
}
// Step 2 - Create some example vehicles in the current scene
{
var vehicle = GameObject.CreatePrimitive(PrimitiveType.Sphere);
vehicle.name = "Wagon1";
var vehicleBehaviour = vehicle.AddComponent<VehicleInstance>();
vehicleBehaviour.Initialize(wagon);
}
{
var vehicle = GameObject.CreatePrimitive(PrimitiveType.Sphere);
vehicle.name = "Wagon2";
var vehicleBehaviour = vehicle.AddComponent<VehicleInstance>();
vehicleBehaviour.Initialize(wagon);
}
{
var vehicle = GameObject.CreatePrimitive(PrimitiveType.Cube);
vehicle.name = "Cruiser1";
var vehicleBehaviour = vehicle.AddComponent<VehicleInstance>();
vehicleBehaviour.Initialize(cruiser);
}
}
}