Behavior Designer 是 Unity 中一个用于创建行为树的插件,主要用于 AI 和 NPC(非玩家角色)的行为管理。行为树(Behavior Trees)是一种基于树形结构的决策树模型,广泛应用于游戏开发中,特别是在控制复杂的 AI 行为时。
Behavior Designer 的用途包括:
- AI 角色控制: 可以通过行为树来定义 NPC 的决策过程,使其能够根据环境、条件、目标等动态变化做出决策。
通过节点化设计,简化了传统状态机或代码逻辑的复杂性,使行为设计更加直观。 - 行为分支: 支持并行和顺序执行节点,允许在不同条件下执行不同的行为,比如在敌人靠近时开始攻击,在发现目标时追踪等。
- 任务系统: 可以创建多个子任务,分配给 AI 角色。比如一个简单的任务可以是巡逻,复杂的任务可以是与敌人战斗或躲避危险。
- 高度可定制: 你可以根据游戏需求自定义行为节点,甚至结合其他系统(如路径寻路、战斗系统等)来实现更加复杂的行为。
- 可视化设计: Behavior Designer 提供了可视化的界面,使开发人员和设计师能够通过拖放来构建行为树,而无需编写大量的代码。
- 调试和优化: 提供调试功能,可以实时查看行为树的执行情况,方便开发人员检查 AI 行为的正确性,并对性能进行优化。
适用场景
- 复杂游戏 AI 的构建,如 NPC 行为、敌人 AI、角色控制等
- 需要创建多阶段、动态行为的游戏,例如 RPG、策略、射击、冒险类游戏
- 简化 AI 逻辑和加速开发流程,适用于快速迭代和测试 AI 行为的项目
行为树或有限状态机
在什么情况下你会使用行为树而不是有限状态机(例如 Playmaker)?在最高级别,行为树用于 AI,而有限状态机 (FSM) 用于更通用的可视化编程。虽然你可以使用行为树进行通用可视化编程,使用有限状态机进行 AI,但这并不是每个工具的设计目的。行为树比 FSM 有几个优点:它们提供了很大的灵活性,功能非常强大,而且很容易进行更改。
首先让我们看看第一个优势:灵活性。使用 FSM,如何同时运行两个不同的状态?唯一的方法是创建两个单独的
FSM。使用行为树,您需要做的就是添加并行任务,然后就大功告成了——所有子任务都将并行运行。使用 Behavior
Designer,这些子任务可以是 PlayMaker FSM,并且这些 FSM 将并行运行。灵活性的另一个例子是任务保护任务。在此示例中,您有两个不同的任务播放音效。这两个不同的任务位于行为树的两个不同分支中,因此它们彼此不了解,并且可能同时播放音效。您不希望发生这种情况,因为听起来不太好。在这种情况下,您可以添加一个信号量任务(在行为设计器中称为任务保护),它只允许一次播放一个音效。当第一个声音播放完毕后,第二个声音将开始播放。
行为树的另一个优点是功能强大。这并不是说 FSM 不强大,只是它们在不同方面很强大。我们认为,行为树比有限状态机更容易让您的 AI
对当前游戏状态做出反应。创建一棵能够对各种情况做出反应的行为树更容易,而使用有限状态机则需要大量状态和转换才能获得类似的 AI。为了使用
FSM 实现相同的结果,您最终会得到一个印度电线式状态机。行为树的最后一个优势是它们非常容易更改。行为树如此受欢迎的原因之一是它们很容易用可视化编辑器创建。如果您想使用 FSM
更改状态执行顺序,您必须更改状态之间的转换。使用行为树,您所要做的就是拖动任务。您不必担心转换。此外,只需更改任务或向任务分支添加新的父任务,就可以完全改变
AI 对不同情况的反应方式。话虽如此,行为树和 FSM 并不一定要相互排斥。行为树可以描述AI 的流程,而 FSM可以描述功能。这种组合让您既拥有行为树的强大功能,又拥有 FSM 的功能。
Task生命周期
从最高层次来看,行为树是Task的集合。任务的 API 与 Unity 的 MonoBehaviour 类似,因此编写自己的Task应该非常容易。Task类具有以下 API:
// 当行为树启用时,OnAwake 会被调用一次。可以将其视为构造函数
void OnAwake();
// OnStart 在执行前立即调用。它用于设置需要从上次运行重置的任何变量
void OnStart();
// OnUpdate 运行实际任务
TaskStatus OnUpdate();
// OnFixedUpdate 在 FixedUpdate 循环期间执行。必须在 OnUpdate 中返回 TaskStatus
void OnFixedUpdate();
// 执行成功或失败后调用
void OnEnd();
// 当行为暂停或恢复时调用
void OnPause(bool paused);
// 返回优先级选择器使用的任务优先级
float GetPriority();
// 返回任务的效用,由效用选择器用于效用理论
float GetUtility();
// 行为树执行完成后调用OnBehaviorComplete
void OnBehaviorComplete();
// 由检查器调用,以重置公共属
void OnReset();
// 允许从任务中调用
void OnDrawGizmos();
// 保留对拥有此任务的行为的引用
Behavior Owner;
任务有三个公开的属性:名称、注释和即时。即时是唯一一个功能不明显的属性。当任务返回成功或失败时,它会立即在同一更新标记内转到下一个任务。如果取消选中即时任务,它现在将等待更新标记,然后再执行下一个任务。这是一种限制行为树的简单方法。
执行任务时采用如下流程图:
待续…