一、行为树每次tick执行一次(默认每帧,可改频率),自顶向下从左到右深度优先执行(即设计时应遵循的优先级)。
二、每次tick运行后会立刻得到一个结果:Success 或 Failure 或 Running。
三、Task,即行为树中一个节点(可自己实现),其主要的生命周期类似Unity的Monobehaviour。
四、Task 有四大类:
1、动作节点(Action):通常是一个异步执行的任务,类似于状态机中的一个状态,如果未完成返回 Running,如果完成返回 Success。
执行异步任务通常可以采用两种方式:
⑴、在 OnStart 开始一个异步动作,然后在 OnUpdate 中持续检测并返回去状态;
using UnityEngine;
using BehaviorDesigner.Runtime;
using BehaviorDesigner.Runtime.Tasks;
[TaskCategory("Hero")]
public class DoSomeAction : Action
{
private bool isCompleted;
public override void OnStart()
{
isCompleted = false;
bool isTriggered = DoSth() =>
{
isCompleted = true;
});
isCompleted = !isTriggered || isCompleted; //未触发或触发后同步返回完成
}
public override TaskStatus OnUpdate()
{
return isCompleted ? TaskStatus.Success : TaskStatus.Running;
}
}
⑵、在 OnUpdate 中执行异步动作(如 transform.Translate())并返回状态。
using UnityEngine;
using BehaviorDesigner.Runtime;
using BehaviorDesigner.Runtime.Tasks;
public class MoveTowards : Action
{
public float speed = 0;
public SharedTransform target;
public override TaskStatus OnUpdate()
{
if (Vector3.SqrMagnitude(transform.position - target.Value.position) < 0.1f)
{
return TaskStatus.Success;
}
transform.position = Vector3.MoveTowards(transform.position, target.Value.position, speed * Time.deltaTime);
return TaskStatus.Running;
}
}
2、条件节点(Conditinal):同步返回 Success 或 Failure ,单纯用来做 if 判断。
3、复合节点(Composite):用来做逻辑控制
⑴、Sequence:从左到右的顺序依次执行,相当于子任务以 && 连接,如果有一个子任务返回false,后续子任务都不执行,并且该任务直接返回false。即顺序执行且可能提前终止。常用于:
①、CondX && CondY && CondZ : 判断一系列条件是否全部为真
②、DosthA && DosthB && DosthC : 顺序执行多件事
③、CondX && CondY && DosthA && DosthB:满足一些条件后顺序执行一些事
⑵、Selector:从左到右依次执行,相当于子任务以 || 连接,如果有一个子任务返回true,后续子任务都不执行,并且该任务直接返回true。即左侧优先选择并只执行其中一个。常用于:
①、CondX || CondY || CondZ : 判断一系列子任务中是否有一个为真。
4、装饰节点:装饰现有节点, 如:取反(可以避免写两个Conditional代码)、反复执行等。
五、条件中断:用来中断正在 Running 的 Action 节点(如发现敌人后执行追踪,但敌人跑远后应该中止),有三种:
⑴、打断自身(Self):自身正在运行时(自身某子节点正在运行),如果左侧子节点条件改变,则打断重新检测。
⑵、打断低优先级(Lower Priority):同级右侧节点正在运行时,如果自身条件改变(某个自身子节点条件改变),则打断重新检测。
⑶、打断自身和低优先级(Both):⑴+⑵。
六、行为树最好只只负责策略,其读写的数据可以都放在数据类中。所有数据类的集合相当于行为树的黑板。