Skip to main content

行为树编辑器用户手册

概述

行为树(Behavior Tree)是常用的游戏AI交互方式之一,可以称为是AI智能体(AI Agent)处理器(Processing Unit)。是一种通过树形结构来形容复杂AI逻辑策略的行为表达方式。

行为树相当于AI的大脑,黑板(Blackboard)相当于大脑中的“记忆”。行为树的运行规则便是不断地从黑板中读取数据来做出决策并执行不同的行为分支。

行为树编辑器包括:

  • 行为树的编辑部分
  • 黑板键的编辑部分

用户指南

本章节主要讲述如何在引擎编辑器内创建行为树资源。

创建行为树资源

行为树资源文件分为两种。一种是行为树(Behavior Tree),其后缀名为.bt;另一种是黑板(Blackboard),其后缀名为.bb

创建行为树

行为树本质是AI的处理器,通过黑板中获取的数据做出决策并执行各种分支。

通过以下方式在资源预览窗口中创建行为树:

在资源预览窗口中鼠标右击空白处,在弹出的菜单中依次点击创建资源(Create Res) -> 人工智能(AI)-> 行为树(Behavior Tree)并为该资源设定名称。

创建黑板

黑板(Blackboard)资源视作AI智能体的“大脑”,它会储存一些称为黑板键(Blackboard Key)的数据对象,这些key类似大脑中的“记忆”,通过特定方式的对这些key执行更新、读和写的操作,来帮助行为树持续做出决策。

通过以下方式创建黑板资源:

在资源预览窗口中鼠标右击空白处,在弹出的菜单中依次点击创建资源(Create Res) -> 人工智能(AI)-> 黑板(Blackboard)并为该资源设定名称。

编辑黑板

由于行为树会在其执行过程中关联黑板资源,并通过黑板中的数据反复进行决策,所以通常需要先创建黑板,再创建行为树。

在资源预览窗口中双击黑板资源文件打开行为树编辑器并进入到黑板编辑模式。

单击黑板窗口中的新键(New Key)按钮可添加新的黑板键(Blackboard Key)

若正在编辑的行为树已经关联过黑板,在行为树编辑器中点击右上角的黑板(Blackboard)可从行为树编辑模式切换到黑板编辑模式。

目前支持的黑板键类型:

黑板键被创建后,在详细面板(Details Panel)中可以编辑黑板键的相关属性。

支持:名称(Name)描述(Description)同步示例(Instance Synced)类型(Type)属性的修改。

在黑板键的类型(Type)属性中可以更改其关联的属性类型。

若要删除已经创建的黑板键,可以通过鼠标右击该黑板键,然后选择删除(Delete),或者选中目标并按Delete键。

编辑行为树

在资源预览窗口中双击行为树打开行为树编辑器并进入到行为树编辑模式。

若此时处于行为树的黑板编辑模式,可通过点击行为树编辑器右上角的行为树(Behavior Tree)按钮切换到行为树编辑模式(注意:行为树需要关联到某个黑板资源后才可切换编辑模式)。

指定黑板

行为树想要读取黑板的内容,需要先指定一个关联的黑板资源。

在行为树图中选择Entry节点(这是所有行为树的入口节点),然后在详细面板中设置需要关联的黑板资源。

指定黑板资源成功后,Entry节点会显示关联的黑板资源并更新所关联的黑板键。

节点相关操作

右击行为树图中的空白处,选择需要创建的节点,可将不同的节点添加到该行为树中。

也可以从节点引脚处拖拽出引线,从菜单中选择要创建的节点。

要从图表中删除节点,先选中目标节点,然后按Delete键,或者右击节点选择删除(Delete)

拖拽引脚到另一个节点的输入引脚上即可把两个节点连接在一起。

如果需要断开节点链接,右击节点,然后选择断开链接(Break Link)

编辑节点。选中所需要编辑的节点,在详细面板中可修改该节点属性。

装饰器和服务节点

在节点快捷菜单处可为行为树图中的节点添加装饰器和服务节点。

右击目标节点,选择添加新服务(Add New Service)添加新装饰器(Add New Decorator)

从节点移除装饰器或服务节点,需选择目标节点,然后按Delete键;或者右击节点,然后选择删除(Delete)

智能体开发流程

右击资源预览窗口的空白处,在弹出的菜单中依次点击创建资源(Create Res) -> 人工智能(AI) -> 行为树(Behavior Tree)来创建一个行为树并将其命名为bt_agent

然后再用相同的方法来创建一个名为bb_agent的黑板资源。

D://JJ/tmp/pic/133117446707067545.png

双击打开bb_agent,在该黑板内分别添加三个不同类型的黑板键,分别是ObjectVectorInt,然后再分别更改它们的名称并进行保存。

双击打开bt_agent,设置bb_agent为其关联的黑板资源。

点击Entry节点引脚并拖拽到空白处,在弹出的菜单中选择合并(Composites)目录下的选择器(Selector)节点,添加一个选择器节点。

选中新创建的选择器节点,在详细面板中设置节点名称为Root

image-20221111161120022

点击Root节点并拖拽节点引脚,添加一个名为State Is Idle的序列节点。此处使用序列节点是为了告诉目标智能体(Agent)接下来需要执行一系列动作。

点击Root节点并拖拽节点引脚,添加一个名为State Is Combat的序列节点。通过这个节点来控制智能体调整移动速度并移动到指定位置。移动到指定位置后,播放一段动画,执行一个自定义任务,最后再重复该过程。

每个节点右上角的数字代表了当前节点在整个行为树中的执行操作顺序。

行为树会遵循从左向右、自上而下的执行顺序,因此节点的排列顺序很重要。对智能体决策方面相对重要的动作通常放在左边,而次要的动作则放在右边。

从State Is Idle节点连出引线添加一个播放动画(Play Animation)节点。

从State Is Idle节点连出引线添加一个等待(Wait)节点,并将等待时间(Wait Time)设置为5.0s。

从State Is Combat节点连出引线添加一个设定整型值(Set Integer Value)节点。设定该节点名称(Name)为Walk Speed、关联的黑板键(Blackboard Key)为TargetWalkSpeed、节点当前值(Current Value)为5。

从State Is Combat节点连出引线添加一个移动至(Move To)节点,设定该节点关联的黑板键为TargetLocation。

从State Is Combat节点连出引线添加一个播放动画(Play Animation)节点,设定动画名称(Animation Name)为预期执行的动画名称(具体需要根据实际情况和关联的智能体支持的动画来设定)。

从State Is Combat节点连出引线添加一个自定义任务(Custom Task)节点,根据需求设定任务名称(Task Name)任务数据(Task Data)属性。自定义任务节点被执行后,将会接收到一个包含任务名称和任务数据的消息。

在之前创建的Root选择器节点上添加一个服务(Service)节点,用来更新关联的黑板键,设定该节点关联的黑板键为TargetObject。

在之前创建的两个序列节点上分别添加一个新的装饰器(Decorator)节点,节点类型为黑板(Blackboard)

设定装饰器节点关联的黑板键为TargetObject,分别将两个节点的黑板键操作(Key Operation)属性设定为Is Set,这样就可以在黑板键值变化的同时执行不同的逻辑分支。

至此一个简单的智能体行为树示例就编辑完成了。

行为树节点类型

行为树节点执行的主要工作包括任务、逻辑流控制和数据更新。

合成节点

合成(Composite)节点定义分支的根以及执行该分支的基本规则。

序列

序列(Sequence)合成节点按从左到右的顺序执行其子节点。当其中一个子节点执行失败时,序列节点也将停止执行。

属性:

属性说明
名称(Name)节点在行为树图中显示的名称

选择器

选择器(Selector)合成节点按从左到右的顺序执行其子节点。当其中一个子节点执行成功时,选择器节点将停止执行。

属性:

属性说明
名称(Name)节点在行为树图中显示的名称

任务节点

任务(Task)节点是行为树的叶。它们是可执行的操作节点,没有输出连接(节点显示颜色为紫色)。

等待

等待(Wait)任务节点控制行为树在此节点上等待,直至指定的等待时间结束。

属性:

属性说明
名称(Name)节点在行为树图中显示的名称
等待时间(Wait Time)等待的时长,单位:秒(s)
随机偏差(Random Deviation)向等待时间属性添加一个随机时间(可正可负),允许等待时间出现的时间偏差范围

移动至

移动至(Move To)任务节点通知目标移动到指定位置。

属性:

属性说明
名称(Name)节点在行为树图中显示的名称
可接受半径(Acceptable Radius)任务节点成功运行时Pawn与目标之间所需的距离
超时设置(Time Out)默认设置0为不超时,超过设置时间(非0值)后则认为任务超时返回失败
黑板键(Blackboard Key)可以用来检查的键。对返回None的数据类型(例如:Object)最有用,因为其他类型的数据可能会返回它们的初始值(例如:0、false、{0,0,0})

播放动画

播放动画(Play Animation)任务节点通知目标播放设定的动画。

属性:

属性说明
名称(Name)节点在行为树图中显示的名称
循环(Looping)勾选启用后,将会循环播放该动画
动画(Animation)要播放的动画资源

旋转至

旋转至(Rotate To)任务节点将会使关联的Pawn向指定的黑板键旋转。

属性:

属性说明
精度(Precision)可以成功执行的度数
名称(Name)节点在行为树图中显示的名称
黑板键(Blackboard Key)目标旋转所朝向的黑板键。可以是一个向量值,也可以是一个对象(Object)。

设置向量值

设置向量值(Set Vector Value)节点可设置Vector黑板键变量值。

属性:

属性说明
值X(Value X)X轴方向变量值
值Y(Value Y)Y轴方向变量值
值Z(Value Z)Z轴方向变量值
名称(Name)节点在行为树图中显示的名称
黑板键(Blackboard Key)当前设置的目标黑板键变量对象

设置字符串值

设置字符串值(Set String Value)节点可设置一个字符串黑板键变量值。

属性:

属性说明
当前值(Current Value)当前黑板键对象设置的变量值
名称(Name)节点在行为树图中显示的名称
黑板键(Blackboard Key)当前设置的目标黑板键变量对象

设置整型值

设置整型值(Set Integer Value)节点可设定Integer类型黑板对象变量值。

属性:

属性说明
当前值(Current Value)当前黑板键对象设定的默认变量值
偏差(Deviation)是否允许当前变量值有一定范围偏差
最小偏差(Min Deviation)允许产生的最小范围偏差值
最大偏差(Max Deviation)允许产生的最大范围偏差值
名称(Name)节点在行为树图中显示的名称
黑板键(Blackboard Key)当前设置的目标黑板键变量对象

设置浮点值

设置浮点值(Set Float Value)节点可设定Float类型黑板对象变量值。

属性:

属性说明
当前值(Current Value)当前黑板键对象设定的默认变量值
名称(Name)节点在行为树图中显示的名称
黑板键(Blackboard Key)当前设置的目标黑板键变量对象

设置布尔值

设置布尔值(Set Bool Value)节点可设定Bool类型黑板对象变量值。

属性:

属性说明
名称(Name)节点在行为树图中显示的名称
当前值(Current Value)当前黑板键对象设定的默认变量值
黑板键(Blackboard Key)当前设置的目标黑板键变量对象

自定义任务

自定义任务(Custom Task)节点可用来自定义任务。

属性:

属性说明
名称(Name)节点在行为树图中显示的名称
任务名称(Task Name)自定义任务函数名称
任务数据(Task Data)自定义任务函数附加参数

装饰器节点

装饰器(Decorator)节点需附接于合成节点或任务节点,并决定树中的分支甚至单个节点能否被执行(节点显示颜色为蓝色)。

比较黑板条目

比较黑板条目(Compare BB Entries)装饰器节点可比较两个黑板键的值,并根据结果允许或阻止节点的执行。

属性:

属性说明
名称(Name)节点在行为树图中显示的名称
操作(Operator)
  • 相等(Is Equal):这两个黑板键的值是否相等
  • 不等(Is Not Equal):这两个黑板键的值是否不相等
  • 黑板键A(Blackboard Key A)此比较中的第一个键
    黑板键B(Blackboard Key B)此比较中的第二个键
    观察者终止(Observer Aborts)
  • 无(None):不中止执行
  • 低优先级(Lower Priority):中止该节点右侧所有节点
  • 自身(Self):中止该节点自身和在其下面运行的所有子树
  • 两者(Both):中止该节点自身和在其下面运行的所有子树,以及该节点右侧所有节点。
  • 在位置处

    在位置处(Is At Location)装饰器节点会检查AI控制的Pawn是否位于给定的位置。

    属性:

    属性说明
    名称(Name)节点在行为树图中显示的名称
    半径(Radius)测试范围半径变量值
    黑板键(Blackboard Key)需要测试的黑板键值
    循环

    循环(Loop)装饰器节点会对节点或分支进行指定次数循环或无限次循环。

    属性:

    属性说明
    名称(Name)节点在行为树图中显示的名称
    循环次数(Num Loops)循环运行的次数
    黑板

    黑板(Blackboard)装饰节点检查给定的黑板键是否设置了值。

    属性:

    属性说明
    名称(Name)节点在行为树图中显示的名称
    黑板键(Blackboard Key)装饰器将运行的黑板键
    黑板键操作(Key Operation)
  • 已经设置(Is Set):数值是否已设置
  • 尚未设置(Is Not Set):数值是否尚未设置
  • 观察者终止(Observer Aborts)
  • 无(None):不中止执行
  • 低优先级(Lower Priority):中止该节点右侧所有节点
  • 自身(Self):中止该节点自身和在其下面运行的所有子树
  • 两者(Both):中止该节点自身和在其下面运行的所有子树,以及该节点右侧所有节点。
  • 通知观察者(Notify Observer)
  • 结果改变时(On Result Change):仅在条件改变时进行重新计算
  • 值改变时(On Value Change):仅在观察到的黑板键改变时进行重新计算
  • 条件语句循环

    当黑板条件满足后,条件语句循环(Conditional Loop)装饰器节点将使它所连接的节点进行循环执行。

    属性:

    属性说明
    名称(Name)节点在行为树图中显示的名称
    黑板键(Blackboard Key)装饰器将运行的黑板键
    黑板键操作(Key Operation)
  • 已经设置(Is Set):数值是否已设置
  • 尚未设置(Is Not Set):数值是否尚未设置
  • 观察者终止(Observer Aborts)
  • 无(None):不中止执行
  • 低优先级(Lower Priority):中止该节点右侧所有节点
  • 自身(Self):中止该节点自身和在其下面运行的所有子树
  • 两者(Both):中止该节点自身和在其下面运行的所有子树,以及该节点右侧所有节点。
  • 通知观察者(Notify Observer)
  • 结果改变时(On Result Change):仅在条件改变时进行重新计算
  • 值改变时(On Value Change):仅在观察到的黑板键改变时进行重新计算
  • 服务节点

    服务(Service)节点需附接于合成节点或任务节点,通常用于按照设定的频率检查和更新黑板(节点显示颜色为绿色)。

    默认服务

    默认服务(Default Service)节点通常用于通过设定的频率更新黑板。

    属性:

    属性说明
    名称(Name)节点在行为树中显示的名称
    黑板键(Blackboard Key)当前黑板键对象设置的变量值
    间隔(Interval)定义服务节点后续Tick之间的时间间隔
    随机偏差(Random Deviation)为时间间隔属性添加一个随机范围值
    每帧更新(Call Tick)是否激活Tick函数

    自定义服务

    目前提供两种服务(Service)回调方式,用于拓展、实现自定义服务功能。

    C++注册

    函数头文件:

    i_ai_command_processor.h

    函数声明:

    // 服务
    typedef void (*on_service)(IAICommandProcessor* from, PERSISTID object,
    onst char* bt_file, const char* bb_key);

    回调注册方法:

    AICommandProcessor:: virtual bool RegisterOnService(on_service f);

    回调注册查询:

    AICommandProcessor::IsRegisterCallback(EAICommandCallback:: OnService)

    参数类型:

    • ·IAICommandProcessor* from:AIcommandProcessor对象
    • PERSISTID object:当前AIObject对象ID
    • const char* bt_file:当前绑定的行为树资产文件
    • const char* bb_key: 当前ServiceNode设置的黑板键

    脚本注册

    在组件编辑器的大纲(Hierarchy)面板中选中LSceneSettings,并在其属性面板中的AI脚本(AI Script)中配置默认回调脚本文件。

    image-20221216160009103

    注册回调函数示例代码:

    --AI
    function on_init(self)

    --服务:更新黑板
    nx_callback(self, "on_service", "ai_service")

    return 1
    end

    函数示例代码:

    function ai_service(self,  target,  behavior_tree, blackboard_key)

    // 文件判断
    if "" == behavior_tree then
    // TODO Something
    end

    // 黑板键判断
    if "" == blackboard_key then
    // TODO Something
    end
    end