StateTree概述

StateTree系统的概述。

Choose your operating system:

Windows

macOS

Linux

概述

StateTree 是一种通用分层状态机,组合了行为树中的 选择器(Selectors) 与状态机中的 状态(States)过渡(Transitions) 。用户可以创建非常高效、保持灵活且井然有序的逻辑。

StateTree包含以树结构布局的状态。状态选择可以在树中的任意位置触发,但它最初从根开始。在选择过程中,将对每个状态的 进入条件(Enter Conditions) 求值。如果通过,选择将前进到该状态的子状态(如果可用)。如果没有子状态可用,将激活当前状态。

选择状态将激活从根到叶状态的所有状态。每个状态由 求值器(Evaluators)任务(Tasks)过渡(Transitions) 组成。

求值器包含在状态选择期间以及在StateTree Tick期间执行的逻辑。求值器提供了决策所需的数据。StateTree中的数据从根流向叶。这样一来,任意状态所公开的数据都将可用于树中向下的所有其他状态。

选择某个状态时,所选状态及其所有父状态都将激活。为所有活动状态执行所有任务,执行方式为从根开始,直至所选的状态。

每个任务都向StateTree提供一个输出。常见输出示例包括选择目标、播放动画和查看对象。每个状态可以有多个任务,只要状态保持活动,该状态中的所有任务都会并发运行。完成执行的第一个任务将触发过渡,这可能导致选择新状态。

作为一个简单的例子,你可以使用StateTree创建昼夜变换系统。你会为每个时刻创建一个状态,并会在每个状态下创建单独的任务。每个任务可以处理不同的元素,例如雾密度、天空球体颜色,等等。

另一个例子是让AI艾真体在关卡中四处行走,并在环顾四周的同时持续检查是否有打击效果。你可以使用一个状态来表示四处行走和环顾四周,另一个状态来表示对打击做出反应。

StateTree中的过渡可以指向树中的其他任意状态。过渡包含 触发器条件(Trigger Conditions) ,需要满足这些条件,过渡才会触发状态选择过程。

如果状态选择成功,将选择一个新的状态。一些过渡会被持续监控,而其他过渡仅在状态完成时执行。过渡从叶状态开始进行求值,并朝根向上推进。在此过程中,将选择第一个成功并导致状态选择的过渡。此层级允许对常见过渡进行分组。

下面是StateTree的不同元素:

图例

StateTree元素

说明

1

根(Root)

StateTree开始运行时选择的第一个状态。

2

求值器(Evaluator)

提供在状态选择过程中使用的数据。

3

选择器状态(Selector State)

指的是有子状态的状态。该状态绝不会直接被选择,选择将继续到其子状态之一。

4

状态进入条件(State Enter Condition)

指用于确定是否可以选择某个状态的条件列表。

5

任务(Task)

指的是属于某个状态并且在该状态激活时执行的一组操作。

6

过渡(Transition)

定义触发状态选择过程的条件。任务完成、成功或失败时,或者某个被监控的条件达成时,会触发过渡。

选择流

选择新状态

StateTree以类似于行为树的方式选择活动状态。状态选择从第一个Tick上的根开始,并在树中向下继续对每个状态的进入条件求值。

  • 如果进入条件未通过,选择将继续到下一个同级状态。

  • 如果进入条件通过,并且该状态是叶状态,则将其选择作为新状态。

  • 如果该状态有子状态,将继续对第一个子状态执行相同过程,直到找到叶状态为止。

如果一个状态有子状态,但没有一个子状态可选择(其进入条件失败),那么即使该状态的所有进入条件都通过测试,也不会选择该状态。

行为树与状态机之间的一大区别是,状态机通常在执行沿树向下推进时提交状态选择,而行为树则尝试查找合适的叶节点。

一般来说,即使已经选择一个状态,行为树也会继续执行状态选择逻辑。这是在状态之间过渡的唯一方法。

StateTree基于过渡按需运行状态选择过程。在第一个Tick上,会隐式过渡到根状态,这将选择要运行的第一个状态。选择该状态之后,过渡会指示何时及在何处执行选择逻辑。

执行状态任务

选择一个状态之后,其所有任务都将开始并发执行。任务将一直执行,直到某个过渡触发选择过程并选择某个状态为止。所选状态可以是当前状态(该状态继续执行)或新状态。

最常见的过渡触发器是 完成(completion) ,它在活动状态的第一个任务完成后立即执行。其他过渡可能标记为 条件(conditional) 并在每个Tick上进行测试。如果条件过渡通过测试,将执行状态选择逻辑,并且选择过程在目标状态处开始。如果目标状态有子状态,选择过程会将子状态视为选择逻辑的一部分。

数据流

StateTree元素可以彼此共享数据。StateTree中的不同元素可以按以下方式绑定到数据:

StateTree 元素

元素可以绑定到的数据

进入条件(Enter Conditions)

它们可以绑定到当前状态及所有父状态中的求值器。

过渡条件(Transition Conditions)

它们可以绑定到当前状态及所有父状态中的求值器和任务。

求值器(Evaluators )

它们可以绑定到当前状态及父状态中可用的其他求值器。

任务(Tasks)

它们可以绑定到当前状态及父状态中的求值器和其他任务。

蓝图集成

StateTree设计为通过蓝图脚本编写进行扩展。你可以通过扩展以下蓝图类来创建自定义任务、求值器和条件:

基类

说明

UStateTreeTaskBlueprintBase

StateTree任务的基类。

UStateTreeEvaluatorBlueprintBase

StateTree求值器的基类。

UStateTreeConditionBlueprintBase

StateTree条件的基类。

在上述例子之后,你可以使用StateTree和蓝图创建昼夜变换系统。此系统会根据时间更改关卡的雾密度。该系统还可以检查是否有风暴咒语,以便更改光照条件且不受时间影响。

对于这个例子,你可以创建以下蓝图类:

蓝图类

功能

任务(Task)

随时间推移逐渐更改雾密度。该任务可以添加到表示特定时刻的所有状态。

条件(Condition)

检查是否施了风暴咒语。该条件可以在根状态处求值。如果为true,它会将执行移至特别的风暴状态。

求值器(Evaluator)

将时间公开给过渡和进入条件。该求值器可以在根状态处求值,以确定要选择的正确状态。

常见模式

对类似任务分组

智能对象任务分组在一个状态及其子状态中

任务可以分组在一个公共状态下。在上述例子中,有一个状态用于处理世界中的智能对象。该状态包含用于处理"伸展智能对象"和"使用智能对象"的子状态。

其中每个子状态都包含在选择该状态时执行的任务。"伸展"子状态包含用于查找智能对象并将AI艾真体移至智能对象的任务。

当你使用此分组策略时,所有任务都通过该状态共享相同的过渡。

序列

"下一个"过渡简化了状态序列的创建和布局。

StateTree包含 下一个(Next) 过渡,它简化了状态序列的创建和布局。

在上述例子中,选择 伸展(Reach) 状态时,将执行 查找SO目标(Find SO Target)移至SO(Move to SO)查看(Look) 任务。这些任务完成后 ,下一个(Next) 过渡会将执行移至下面的 使用(Use) 状态,其中的任务可以开始执行。

失败处理

StateTree中的失败处理示例

StateTree以分层方式处理任务完成失败,从活动任务开始,并沿树向上推进。

在上述例子中, 伸展插槽(Reach Slot) 状态会在成功时将执行移至下一个状态(等待),或在失败时将执行移至其父状态(在相交处等待)。 在相交处等待(Wait at Intersection) 状态会在其任意子状态失败时触发过渡到 空闲(Idling) 状态。

等待(Wait) 状态会在成功或失败时将执行无限期移至自身,直到其父状态选择不同的状态为止。

分层数据

在该例子中,任务可以获取数据并将数据与后续任务共享

任务可以彼此共享数据。任务公开的数据将可用于属于活动状态的其他任意任务。这可提高StateTree中资源处理的效率。

在上述例子中,群体声明等待插槽(Crowd Claim Wait Slot) 任务将尝试为AI艾真体声明智能对象插槽,如果成功,它会将执行传递给 移至等待插槽(Move To Wait Slot) 任务。该任务将使用父任务中的插槽位置。如果成功,它会将执行传递给 在插槽处等待(Wait At Slot) 任务,它还将使用其父任务中的插槽位置。

优化行为

StateTree提供了一种组织任务的方法,以便轻松实现上下文行为。

StateTree提供了一种组织任务的方法,以便轻松实现上下文行为。

在上述例子中,等待(Wait) 状态处理AI艾真体的站立移动——AI艾真体环顾四周并在被击中时做出反应。默认情况下,将执行 等待查看(Wait Look) 状态。如果该状态成功,它会将执行返回给父状态。但是,如果失败,它会将执行移至 等待打击(Wait Hit) 状态。

等待打击(Wait Hit) 状态将执行 质量查看(Mass LookAt)质量上下文动画(Mass Contextual Anim) 任务。然后,这些任务将播放打击的相应动画。