行为树

  • 用了很久的行为树了,用来做过 AI、新手引导,感觉说一些使用细节属实是没啥必要,说一个我自己遇到的问题把,有的时候就想代码做一些判断重复的事情,这个时候用行为树就很傻了,如果节点只有 20 个以下我还能接受。
  • 但是如果是策划配表没有什么上限的东西呢,总不能一个个拖动吧,所以我用行为树的这种逻辑写了一个代码版本的行为树。

实现思路

  • 想一下行为树的逻辑,从头到尾依次判断,然后一直到某个节点成功,如果所有的节点都失败了,就结束当前树,算是一次行为完成。
  • 如果你勾选了外部的完成后重新开始,那么就变成了一个不断循环的逻辑。
  • 分析完毕,开始构思代码逻辑。
  • 首先需要一个类来表示整个树,假设我们叫它 LoopTaskTree。
  • 然后 Tree 里面需要放置各种各样的节点,BaseLoopTask,分析一下发现代码上暂时不用考虑 or 这个状态,目前我们需要的是重复判断某个事情,也就是说 Task 的状态有 Success、Failure、Running 三种。
  • 接着就是让这个树循环判断起来。
  • 用 Update() 就可以完成这件事,然后写一个 Manager 来管理,里面执行三个重要逻辑 —— Update() —— Add() —— Remove()。
  • 这里有一个需要注意的地方就是需要做一个缓存,因为如果在某一个 Update 中对正在执行遍历 Loop 的列表做出修改的话,可能会出现同一个 Tree 判定两次然后执行两次的结果,所以移除和增加都要做缓存,然后在每帧开始的时候做移除、增加,这里的顺序不能反,最后才能做便利。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/// 每帧的便利循环
public void Update()
{
//先判断是否执行过初始化
if (m_IsInit)
{
//先做移除
DoRemove();
//再做增加
DoAdd();
//然后遍历所有的 Tree 做 Update
foreach (var item in m_AllVerifys)
foreach (var obj in item.Value)
obj.Update();
}
}

具体使用

  • 这个循环判定的逻辑是要跟策划的配表强绑定的,所以要根据自己的需求继承 BaseLoopTask。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class BaseLoopTask
{
public string Name;
public bool IsInit = false;
public ELoopBaseTaskType Type;
public bool HasLimit = false;

/// <summary>
/// 重写这个方法的时候必须继承父类的方法
/// </summary>
/// <param name="param"></param>
public virtual void Init(params object[] param)
{
IsInit = true;
}
}

public enum ELoopBaseTaskType
{
Action,
Condition,
}

  • 可以看到这个 BaseLoopTask 有两种类型,一种是条件类型,一种是执行类型,所以我们根据实际需求写好条件和执行,然后再根据配表解析参数生成就行了。
  • 工程源码 https://gitee.com/XiaozhuGit/loop-task-tree.git