介绍
表达式可以提供给AI编写者功能更加强大的计算需求,表达式常用于编写复杂的条件,用于筛选单位;执行复杂的运算,以供AI决策使用;表达式最常见的用法是读取Board中储存的值。
在哪里写表达式
在行为树编辑器中,可以填写表达式的节点参数,在参数描述中均有明显的“可以填写表达式”或”xxx表达式”标记,或者填写样例中写明了表达式:
基本用法-值,运算和属性
表达式支持的基本类型包括整数,实数,向量(点),列表,字符串,布尔值和None
整数 | 1 | INTEGER(1) | int(20) |
实数 | 1 | FLOAT(1) | Fix32(20.0) |
字符串 | "hello" | STRING(12345) | str(12345) |
向量 | VECTOR(1,0,3) | VECTOR(1.0,0,3) | VECTOR(0,0,0) |
列表 | [1,2,3] | [](空列表) | ["hello", "you"] |
布尔值 | TRUE | FALSE | |
None | None |
数学运算 整数和实数可以做数学运算:1+2.0*(3-1)
数字比较 1 > 2;1 <= 3
字符串 字符串拼接:"hello"+"world"
向量加减 VECTOR(1,2,3)+VECTOR(3,4,5)
向量乘除 向量可以乘以或除以数字,对应伸长或缩短:VECTOR(1,2,3)*3;VECTOR(1,2,3)/2
向量模 向量可以获取长度(模),结果为实数:VECTOR(1,2,3).length
列表判断 列表可以使用in, not in操作来判断指定值是否在列表内,结果为布尔值:1 in [1,2,3] (是True);VECTOR(1,2,3) not in [ ] (是True)
列表拼接 [1,2,3] + [4,5,6]
布尔值运算 布尔值可以使用and, or, not逻辑运算:True and False (是False);1 in [1,2] or 1 not in [3, 4] (是True)
数字类型转换 使用INTEGER(xxx)或FLOAT(xxx)对数字的类型进行转换
数字转换字符串 使用STRING(xxx)将数字转换为对应的字符串
不建议尝试将字符串转换回数字
布尔值转换 使用bool(xxx)将值转换为布尔值,非零为True,VECTOR一定为True,非空的列表和字符串为True,其余都是False
从board中取值
Board是行为树存储值的一个区域,每个单位都有属于自己的Board,一个单位的所有行为树共用同一个Board。
Board是一个key-value的映射集合,每个value都有一个key与之对应,你通过指定key来获取对应的value,Board中的key是不可重复的,一个key对应一个value。
Board可以通过TAG系列节点来直接操作,本节将会说明如何在表达式中使用Board中的数据
在表达式中使用自己的TAG
使用 &TAG 的语法来在表达式中指代该TAG对应的值。
如,你在行为树中使用TAG-设置tag值节点,将名为number的tag设置了值为1。那么,后续你就可以在表达式中使用&number来获取到此值,并可以使用此值参与上文提到的运算。如&number+1
不能在表达式中修改TAG与值的对应关系,只可以读取
复杂对象-单位
在行为树中可能还会出现的一种对象类型是【单位实体】,使用筛选节点或从外部传入的行为树参数均可能是单位。典型的使用单位的场景就是从board中读取一个被其他节点设置好的单位,如 &ai_target
对于一个单位,你可以以【单位.属性】的语法访问如下属性,如&ai_target.hp
.hp .hpp .mp .mpp .mhp .mmp
分别代表血量,百分比血量,蓝量,百分比蓝量,最大血量,最大蓝量,类型为FLOAT
.position .born_pos .face_dir
单位的坐标,出生位置,面朝方向,类型为VECTOR
.attack_range .alarm_range .cancel_alarm_range
单位的普攻攻击范围,警戒范围,取消警戒范围,类型为FLOAT
.alive
单位是否活着,类型为布尔值
.ability_range[N]
单位N号技能的攻击范围,类型为FLOAT
.camp_id .role_id
单位的阵营id和角色id,类型为INTEGER
.board["TAG"] 或 .client_ai_comp.board["TAG"]
该单位的board中TAG对应的值,注意如果此TAG不存在,那么访问会中断行为树执行
后一种写法为兼容写法,请使用第一种写法
判断TAG是否在单位的board里
"TAG" in &ai_target.board
指代自己
在表达式中使用@来指代正在执行的单位本身,即【我】
使用@hp,@attack_range[N]等语法访问自己的属性,无需加.
@board["TAG"] 与 &TAG 等价,但当TAG不存在时,前者写法会中断行为树执行,而后者写法会使节点执行失败
复杂对象-区域
区域对象只有可能通过类型为AREA的行为树参数传入,并且只能用来调用【区域】行为树节点
复杂对象-路径点
路径点对象就是VECTOR列表
路径点对象可以通过类型为POINT_LIST的行为树参数传入,也可以通过手动构造VECTOR列表来构造,如[VECTOR(0,0,0), VECTOR(50, 0, 50)]将会构造一个两个点构成的路径
路径点对象可以用来调用【移动-沿路径移动】行为树节点,也可以拆开当成VECTOR列表来使用
高级用法-筛选表达式
一些节点需要使用者提供自定义的条件,用来对指定的列表进行筛选,排序或者选出其中符合条件的元素,如
丢弃列表中不符合自定义条件的元素
根据自定义条件,选取列表中的最优元素
顾名思义,获取第一个符合自定义条件的元素
这些节点都有标志性命名的参数,如cond_expr, filter_expr, compare_expr
因为这些节点对列表中的元素挨个检查是否满足条件,所以在表达式中,我们使用$符号来代替当前正在被比较的单位,如$.hpp > 0.5,构成了一个条件,表示对于某单位,它的百分比血量应该大于0.5
与@不同,$后面需要加.来访问属性
具体举例:
以下填写将保留列表中血量大于50%的单位
以下填写保留列表中距离【我】的距离小于我的普攻攻击范围的单位
有些节点需要两两比较单位,以确定单位之间的优先级关系,此时表达式中需要使用$1和$2来分别指代【任意两个单位】
具体举例:
以下填写将获取列表中血量最多的单位(通过两两比较单位的血量,找到最多的)
以下填写将获取列表中离【我】最近的单位,通过两两比较与我的距离,找到最近的
($1.positon-@position).length < ($2.positon-@position).length
高级用法-井号表达式
行为树内置了三个井号表达式
#SELF
指代单位本身【我】,在表达式里单独写一个@是不合法的
#RANDINT(A, B)
生成A, B之间的随机整数,闭区间
#RANDFLOAT(A, B)
生成A, B之间的随机实数,闭区间
注:
#SELF.board["TAG"] 和 @board["TAG"] 和 &TAG 在TAG存在时行为相同
TAG不存在时,前两个会中止行为树执行,后一个会让节点返回失败