Version: 6000.3
语言: 中文
单一行为
Unity 属性

脚本对象

切换到脚本

ScriptableObject 是一个可序列化的 Unity 类型,派生自UnityEngine.Object.与 MonoBehaviour 一样,您不会直接实例化 ScriptableObject 类,而是创建从它派生的自定义 C# 类,然后创建这些自定义类的实例,通常通过 Unity 编辑器中的 Assets 菜单。

从 ScriptableObject 派生的所有类实例通常称为 ScriptableObjects。与 MonoBehaviour 不同,ScriptableObjects 不附加到游戏对象Unity 场景中的基本对象,可以表示角色、道具、风景、相机、航路点等。游戏对象的功能由附加到它的组件定义。更多信息
请参阅术语表
作为组件,但在项目中以资产 可以在游戏或项目中使用的任何媒体或数据。资产可能来自在 Unity 外部创建的文件,例如 3D 模型、音频文件或图像。您还可以在 Unity 中创建一些资产类型,例如动画师控制器、混音器或渲染纹理。更多信息
请参阅术语表
,独立于游戏对象。因为 ScriptableObjects 继承自UnityEngine.Object,您可以将它们的实例拖动或拾取到检查器一个 Unity 窗口,显示有关当前选定游戏对象、资产或项目设置的信息,允许您检查和编辑值。更多信息
请参阅术语表
.

ScriptableObject 的主要值是作为数据存储,但它们也可以定义行为。ScriptableObjects 的一个常见用途是作为多个对象在运行时使用的共享数据的容器,这可以通过避免值的副本来减少项目的内存使用。

例如,如果您的项目具有预制件:一种资产类型,允许您存储包含组件和属性的游戏对象。预制件充当模板,你可以从中在场景中创建新的对象实例。更多信息
请参阅术语表
将不变的数据存储在附加的 MonoBehaviour 中脚本一段代码,允许您创建自己的组件、触发游戏事件、随时间修改组件属性以及以您喜欢的任何方式响应用户输入。更多信息
请参阅术语表
,则预制件的每个新实例都会获得自己的数据副本。您可以使用 ScriptableObject 来存储数据,然后从所有预制件通过引用访问它,而不是像这样复制数据。这意味着内存中有一个数据副本。

ScriptableObjects 的主要用例是:

  • 在编辑器会话期间保存和存储数据。这就是为什么 Unity 中的许多创作工具(例如EditorToolEditorWindow衍生ScriptableObject.
  • 将数据保存为项目中的资产,以便在运行时使用。

有关 ScriptableObject 类的每个成员的完整参考,请参阅 ScriptableObject 脚本参考

创建 ScriptableObject

要创建新的 ScriptableObject 脚本,最快的方法是通过以下方式之一使用 资产(Assets) 菜单中的预定义 ScriptableObject 脚本模板:

  • 在主菜单中,转到 资产(Assets) > 创建>脚本(Create Scripting) >,然后选择 ScriptableObject 脚本
  • 项目(Project) 窗口工具栏中,右键点击以打开 项目(Project) 窗口上下文菜单,然后选择 创建>脚本(Create Scripting) > ScriptableObject 脚本。你也可以点击 项目(Project) 窗口中的加号,直接打开 创建(Create) 菜单。

这为您提供了一个继承自UnityEngine.ScriptableObject.然后,你可以使用 CreateAssetMenu 属性创建此类的实例,每个实例都成为项目中的资产。

示例:使用 ScriptableObject 实例化预制件

以下示例使用 ScriptableObject 来存储在创作时定义的数据,这些数据稍后用于确定在运行时实例化预制件的位置。首先,在Assets文件夹:

// Define a base ScriptableObject class called SpawnManagerScriptableObject
using UnityEngine;

// Use the CreateAssetMenu attribute to allow creating instances of this ScriptableObject from the Unity Editor.
[CreateAssetMenu(fileName = "Data", menuName = "ScriptableObjects/SpawnManagerScriptableObject", order = 1)]
public class SpawnManagerScriptableObject : ScriptableObject
{
    public string prefabName;

    public int numberOfPrefabsToCreate;
    public Vector3[] spawnPoints;
}

使用上一个脚本Assets文件夹中,通过导航到 资产(Assets) > 创建 > ScriptableObjects> SpawnManagerScriptableObject,创建新ScriptableObject的实例。为新的 ScriptableObject 实例指定一个有意义的名称并更改值。要在运行时使用这些值,你需要创建一个引用 ScriptableObject 的新脚本,在本例中为SpawnManagerScriptableObject如下:

using UnityEngine;

public class Spawner : MonoBehaviour
{
    // The GameObject to instantiate.
    public GameObject entityToSpawn;

    // An instance of the ScriptableObject defined above.
    public SpawnManagerScriptableObject spawnManagerValues;

    // This will be appended to the name of the created entities and increment when each is created.
    int instanceNumber = 1;

    void Start()
    {
        SpawnEntities();
    }

    void SpawnEntities()
    {
        int currentSpawnPointIndex = 0;

        for (int i = 0; i < spawnManagerValues.numberOfPrefabsToCreate; i++)
        {
            // Creates an instance of the prefab at the current spawn point.
            GameObject currentEntity = Instantiate(entityToSpawn, spawnManagerValues.spawnPoints[currentSpawnPointIndex], Quaternion.identity);

            // Sets the name of the instantiated entity to be the string defined in the ScriptableObject and then appends it with a unique number. 
            currentEntity.name = spawnManagerValues.prefabName + instanceNumber;

            // Moves to the next spawn point index. If it goes out of range, it wraps back to the start.
            currentSpawnPointIndex = (currentSpawnPointIndex + 1) % spawnManagerValues.spawnPoints.Length;

            instanceNumber++;
        }
    }
}

注意:脚本文件必须与类具有相同的名称。

将上一个脚本附加到您场景场景包含游戏的环境和菜单。将每个唯一的场景文件视为一个独特的关卡。在每个场景中,你放置你的环境、障碍物和装饰品,基本上是将你的游戏设计和构建成碎片。更多信息
请参阅术语表
.然后,在 Inspector 中,使用 新的.asset实例SpawnManagerScriptableObject您设置的。

Entity To Spawn 字段设置为Assets文件夹,然后进入播放模式。您在Spawner使用您在SpawnManagerScriptableObject实例。

如果您在检查器中使用 ScriptableObject 引用,则可以双击引用字段以打开 ScriptableObject 的检查器。您还可以为您的类型创建自定义检查器,以帮助管理它所表示的数据。

保存对 ScriptableObject 数据的更改

在 Unity 编辑器中,您可以在编辑模式和播放模式下将数据保存到 ScriptableObjects。在运行时的独立播放器中,你只能从 ScriptableObject 资产中读取保存的数据。当您使用编辑器创作工具或 Inspector 修改 ScriptableObject 资源时,Unity 会自动将数据写入磁盘,并在编辑器会话之间保留。

但是,Unity 不会自动将更改保存到ScriptableObject在编辑模式下通过脚本制作。在这些情况下,您必须调用EditorUtility.SetDirty确保 Unity 的序列化系统将其识别为已更改并将更改保存到磁盘。否则,更改可能不会在编辑器会话之间持续存在。

假设你有以下名为GameSettings:

using UnityEngine;

[CreateAssetMenu]
public class GameSettings : ScriptableObject
{
    public int highScore;
}

如果你有一个编辑器脚本,可以将highScore值,请确保包含对EditorUtility.SetDirty如下所示:

// Save this as Assets/Editor/GameSettingsEditor.cs
using UnityEditor;
using UnityEngine;

public class GameSettingsEditor : EditorWindow
{
    GameSettings settings;

    [MenuItem("Window/Game Settings Editor")]
    public static void ShowWindow()
    {
        GetWindow<GameSettingsEditor>("Game Settings Editor");
    }

    void OnGUI()
    {
        settings = EditorGUILayout.ObjectField("Settings", settings, typeof(GameSettings), false) as GameSettings;
        if (settings == null) return;

        EditorGUILayout.LabelField("High Score", settings.highScore.ToString());

        if (GUILayout.Button("Increase High Score"))
        {
            settings.highScore += 10;

            // Call SetDirty to ensure the change is saved
            EditorUtility.SetDirty(settings);
            // Optional: AssetDatabase.SaveAssets(); // To save immediately
        }
    }
}

无需调用SetDirty,则更改为highScore显示在内存中,但如果关闭并重新打开编辑器,该值将恢复为其先前的值。

其他资源

单一行为
Unity 属性