您想找什么?
Hero background image
在您的 Unity 项目中使用基于脚本对象的枚举
此页面为机器翻译。如需查看原文以确保准确性并作为权威参考,

本页介绍如何在 Unity 项目中使用基于 ScriptableObject 的枚举。

这是六个迷你指南系列中的第三个,旨在帮助 Unity 开发人员使用电子书中的演示使用脚本对象在 Unity 中创建模块化游戏架构.

该演示的灵感来源于经典的球类和桨类街机游戏机制,并展示了脚本对象如何帮助您创建可测试、可扩展和便于设计的组件。

电子书、演示项目和这些迷你指南共同提供了在 Unity 项目中使用 ScriptableObject 类编程设计模式的最佳实践。这些技巧可以帮助你简化代码、减少内存使用量并提高代码的可重用性。

本系列包括以下文章:

开始前的重要提示

在深入学习 ScriptableObject 演示项目和本系列迷你指南之前,请记住,设计模式的核心只是想法。它们并不适用于所有情况。这些技巧可以帮助你学习使用 Unity 和 ScriptableObjects 的新方法。

每种模式都各有利弊。只选择对您的具体项目有意义的项目。你们的设计师是否非常依赖 Unity 编辑器?基于 ScriptableObject 的模式是帮助他们与开发人员协作的不错选择。

归根结底,适合自己项目和团队的代码架构才是最好的代码架构。

tab 1
删除或重新排列枚举值可能会导致意想不到的行为。
可扩展枚举

枚举是在代码中管理一组固定命名值的便捷方法。不过,它们也有一些局限性。由于序列化的枚举值是以整数而非符号名称存储的,因此删除或重新排列值可能会导致不正确或意外的行为。这意味着,枚举(尤其是当你有很多枚举时)会给 Unity 开发带来麻烦。

标准方法

下面是一个典型的枚举:

[系统.序列化]
公共枚举手势
{
摇滚
纸张
剪刀
}

您可以使用System.Serializable属性将枚举序列化,并将其显示在检查器中。

问题

重新排序或删除某个值可能会带来麻烦。因为每个内部值都是一个整数,它所代表的内容可能会有所不同。在给出的示例中,删除 Paper 的值会使 Scissors 的值变为 1。

或者,如果我们添加一个值,就像下面的例子一样。

如果所选枚举值位于被删除条目之后,则会发生变化。

这可能会在维护和更新项目时造成问题,尤其是在枚举包含大量值的情况下。您可以通过留下空白或未使用的元素,或明确设置整数值来缓解这一问题。然而,这两种解决方案都不理想。

tab3
检查脚本对象之间的等价性
基于脚本对象的枚举

基于脚本对象的枚举具有传统枚举的功能,但以单个资产的形式存储。例如,请看下面示例中PaddleBallSO项目中的PlayerIDSO可脚本对象。

本质上,这是一个空白的 ScriptableObject。

您可以用它在项目中创建大量可脚本对象资产,如 P1、P2 等。即使它们不包含任何数据,也可以使用 ScriptableObjects 进行比较。只需在项目中创建一个新的可脚本对象资产并为其命名即可。

您可以根据需要在项目中创建任意多个播放器 ID,并在它们之间轻松切换。只需更改 GameDataSO 脚本中指定的资产即可。

如果要检查相等性,其工作原理与枚举类似。两个变量是否指向同一个 ScriptableObject?如果是这样,它们就是同一种物品类型。否则就不是。

即使没有任何额外数据,ScriptableObject 也能代表一个类别或项目类型。

Player ID in PaddleBallSO

PaddleBallSO 中,PlayerIDSO 变成了球队名称。我们在 GameDataSO 中使用 P1 和 P2 资产来区分两个桨。

GameSetup 脚本会为每个球拍分配一个球员 ID。在游戏过程中,Paddle 脚本会将玩家的输入与指定的团队 ID 进行比较。

这适用于任何类型的多人游戏。或者,也可以考虑在其他需要使用枚举的地方采用它们。

由于脚本对象只是检查器中的赋值,因此不会出现重命名和重排序的问题。

想要将标识符名称分别改为 "Player1 "或 "Player2"?你可以这样做,而且一切都能继续工作。添加更多可脚本对象?问题不大--检查器中的资产分配保持不变。

tab5
区块使用指定小组进行比较。
Patterns demo

这种行为对创建游戏非常有用。在 "模式 "演示中,单击 "切换枚举 "按钮更换团队。DemoBall 上的 MonoBehaviour 会相应地更新 SpriteRenderer。

球与木块碰撞时,会对木块造成伤害吗?通过对平等性进行快速测试就能知道。下面的代码示例就是比较它们的一种方法。

该方法可以确定两个游戏对象是否属于同一团队,这在检查友方与敌方的互动时非常有用。这种简单的比较适用于物品拾取、伤害或其他任何有 "团队 "或 "排列 "的东西。

扩展行为

有趣的部分发生在为可脚本对象添加逻辑时。与传统的枚举不同,ScriptableObject 除了保存数据外,还可以拥有字段和方法。

使用这些功能,每个可脚本对象都可以有专门的比较逻辑。例如,您可以使用一个可脚本对象来定义特殊的伤害效果(如冷、热、电、魔法等)。

如果您的应用程序需要一个库存系统来装备游戏物品,那么脚本对象就可以代表物品类型或武器插槽。某些角色是否不能持有某些物品?有些物品是否具有魔法或特殊能力?基于脚本对象的枚举可以添加方法来检查这一点。

上一个示例中的MonoBehaviour DemoBall包含用于比较可脚本对象的AreEqual方法。在扩展行为时,可以将比较逻辑捆绑到 ScriptableObject 本身中。

在 "模式 "演示中,你可以修改小球,使其在与物体碰撞时更具选择性。请看下面代码示例中用于碰撞的通用项目。

这可以实现与当前演示类似的结果,但它现在有了一个m_Weakness字段。这允许每个可脚本对象定义另一个可脚本对象,以便在碰撞时销毁。

每个 ScriptableObject 只需管理自己的比较逻辑,而不是调用AreEqual方法。

其结果是更加灵活和可扩展。与其让球破坏不同球队的一个区块,不如让它具体化。场景中的多个球可能会破坏不同的块,这取决于它们各自的 CollisionItems。

这为不同的、更复杂的互动奠定了基础。如果你想制作一个剪刀石头布系统,你可以定义三个可脚本对象:石头、剪子、布每个程序都可以有自己独特的m_Weakness,并使用IsWinner方法来处理交互。

与枚举不同,可脚本对象(ScriptableObjects)使这一过程模块化并具有适应性。无需依赖额外的数据结构或添加额外的逻辑来与单独的数据集同步。只需添加一个额外的字段和/或方法来处理逻辑。

基于脚本对象的枚举的优点

一旦熟悉了基于 ScriptableObject 的枚举,你就会发现它们可以改善你的工作流程,尤其是在与队友合作时。由于它们是资产,更新它们会减少合并冲突,降低数据丢失的风险。

添加新的基于 ScriptableObject 的枚举就像创建另一个资产一样。与传统枚举不同,添加新值不会破坏现有代码。此外,Unity 已经内置了搜索、过滤和组织这些资产的工具,就像其他资产一样。

此外,使用编辑器的拖放用户界面,设计人员还可以扩展游戏数据,而无需软件开发人员的额外支持。您仍然需要协调如何设置字段,但设计人员可以自行在这些字段中填充数据。

可编剧的插曲
更多可脚本对象资源

基于脚本对象的枚举是您的团队可以用来提高协作和效率的又一资源。

在我们的技术电子书中阅读更多有关脚本对象设计模式的内容 使用脚本对象在 Unity 中创建模块化游戏架构.您还可以在以下文章中了解有关常见 Unity 开发设计模式的更多信息 使用游戏编程模式提升代码水平.

您喜欢本文吗?
是的!
还行。