https://blog.csdn.net/luyuncsd123/article/details/18351137
一、先看下项目目录
代码在src下面,配置文件基本没有
结构如下,--指向文件夹 -->指向具体类
src
--com.lizhao
--ai 正式代码
--abs 各个接口的基类
--common 通用类,这里放的是枚举类
--ifs 接口
--composite 继承IComposite的接口
--impl 各种行为的实现类,最小单元
--action
--composite
--condition
-->BehaviorTree 行为树
-->BehaviorTreeBuilder 树生成类
--tree 不用看
-->Main 测试方法
任何行为都会有执行状态
package com.lizhao.ai.common;
public enum EStatus {
Invalid, //初始状态
Success, //成功
Failure, //失败
Running, //运行
Aborted, //终止
};
二、从各个接口来看,继承关系。
里面的实现列出
/**
* Behavior接口是所有行为树节点的核心,且我规定所有节点的构造和析构方法都必须是protected,以防止在栈上创建对象,
* 所有的节点对象通过Create()静态方法在堆上创建,通过Release()方法销毁
* 由于Behavior是个抽象接口,故没有提供Create()方法,本接口满足如下契约
* 在Update方法被首次调用前,调用一次OnInitialize函数,负责初始化等操作
* Update()方法在行为树每次更新时调用且仅调用一次。
* 当行为不再处于运行状态时,调用一次OnTerminate(),并根据返回状态不同执行不同的逻辑
*/
public interface IBehaviour {
//
// //创建对象请调用Create()释放对象请调用Release()
// protected Behavior() {
// setStatus(EStatus.Invalid);
// }
EStatus tick();//设置调用顺序,onInitialize--update--onTerminate
void onInitialize();//当节点调用前
EStatus update();//节点操作的具体实现
void onTerminate(EStatus Status); //节点调用后执行
void release();//释放对象所占资源
void addChild(IBehaviour child);
void setStatus(EStatus status);
EStatus getStatus();
};
/************************************************************************/
/* 动作基类
/* 具体执行动作 */
/************************************************************************/
public interface IAction extends IBehaviour {
}
/************************************************************************/
/* 组合结点
*/
import java.util.List;
/************************************************************************/
public interface IComposite extends IBehaviour {
void addChild(IBehaviour child);
void removeChild(IBehaviour child);
void clearChild();
List getChildren();
void setChildren(List behaviours);
}
/************************************************************************/
/* 条件基类
/* 具体执行动作 */
/************************************************************************/
public interface ICondition extends IBehaviour {
boolean isNegation();
void setNegation(boolean negation);
}
/************************************************************************/
/* 装饰结点
/* 装饰:
*********************************************************************** */
public interface IDecorator extends IBehaviour {
}
/************************************************************************/
/* 顺序节点 */
/*顺序器:依次执行所有节点直到其中一个失败或者全部成功位置 */
import com.lizhao.ai.ifs.IComposite;
/************************************************************************/
public interface ISequence extends IComposite {
}
/************************************************************************/
/* 选择节点
/* 选择器:依次执行每个子节点直到其中一个执行成功或者返回Running状态 */
import com.lizhao.ai.ifs.IComposite;
/************************************************************************/
public interface ISelector extends IComposite {
}
/************************************************************************/
/* 并行节点
/* 并行器:多个行为并行执行 */
/************************************************************************/
public interface IParallel extends IComposite {
}
三、然后写了各自的基类,用于实现一些通用的方法
先看继承关系
看代码
import com.lizhao.ai.common.EStatus;
import com.lizhao.ai.ifs.IBehaviour;
/**
* Behavior接口是所有行为树节点的核心,且我规定所有节点的构造和析构方法都必须是protected,以防止在栈上创建对象,
* 所有的节点对象通过Create()静态方法在堆上创建,通过Release()方法销毁
* 由于Behavior是个抽象接口,故没有提供Create()方法,本接口满足如下契约
* 在Update方法被首次调用前,调用一次OnInitialize函数,负责初始化等操作
* Update()方法在行为树每次更新时调用且仅调用一次。
* 当行为不再处于运行状态时,调用一次OnTerminate(),并根据返回状态不同执行不同的逻辑
*/
public abstract class BaseBehavior implements IBehaviour {
protected EStatus status;
//创建对象请调用Create()释放对象请调用Release()
protected BaseBehavior() {
setStatus(EStatus.Invalid);
}
//包装函数,防止打破调用契约
public EStatus tick() {
//update方法被首次调用前执行OnInitlize方法,每次行为树更新时调用一次update方法
//当刚刚更新的行为不再运行时调用OnTerminate方法
if (status != EStatus.Running) {
onInitialize();
}
status = update();
if (status != EStatus.Running) {
onTerminate(status);
}
return status;
}
// //释放对象所占资源
public void release(){
};
public void setStatus(EStatus status) {
this.status = status;
}
public EStatus getStatus() {
return status;
}
@Override
public void onInitialize() {
}
@Override
public void onTerminate(EStatus Status) {
}
}
import com.lizhao.ai.ifs.IBehaviour;
import com.lizhao.ai.ifs.IComposite;
import java.util.ArrayList;
import java.util.List;
public abstract class BaseComposite extends BaseBehavior implements IComposite {
protected ArrayList children = new ArrayList<>();
@Override
public void addChild(IBehaviour child) {
children.add(child);
}
@Override
public void removeChild(IBehaviour child) {
children.remove(child);
}
@Override
public void clearChild() {
children.clear();
}
@Override
public List getChildren() {
return children;
}
@Override
public void setChildren(List behaviours) {
this.children = (ArrayList) behaviours;
}
}
import com.lizhao.ai.ifs.ICondition;
public abstract class BaseCondition extends BaseBehavior implements ICondition {
protected boolean negation = false;
@Override
public boolean isNegation() {
return negation;
}
@Override
public void setNegation(boolean negation) {
this.negation = negation;
}
protected int getRandom() {
Double random = Math.random() * 100;
// int i = random.intValue();
return random.intValue();
}
}
import com.lizhao.ai.ifs.IAction;
public abstract class BaseAction extends BaseBehavior implements IAction {
}
四、接下来就是写具体的实现类了,不列出来了,去下载具体代码看吧。里面的逻辑是根据随机数判断的,因为没有具体的场景。
五、之后就是将这些行为都挂到树上了,写一个BehaviorTree,里面有一个根节点,进行遍历操作。
而树的构造方式这边使用一个BehaviorTreeBuilder,用的是Stack(之前自己也写过树,这个小哥用的stack方式确实是比较好),具体的看下面代码
六、最后就是写一个测试方法来调用下了,我们将会构建这么一个逻辑,
创建了一名角色,该角色一开始处于巡逻状态,
一旦发现敌人,先检查自己生命值是否过低,如果是就逃跑,
否则就攻击敌人
比原文的逻辑简化了一部分,因为一直在写代码,没运行起来,不知道结果,就简化了,剩下部分会在下一篇补上
直接画图的话就是这么个结构
SelectorImpl
--SequenceImpl
--ConditionIsSeeEnemy
--SelectorImpl
--SequenceImpl
--ConditionIsHealthLow
--ActionRunaway
--ActionAttack
--ActionPatrol
具体代码
public class Main {
public static void main(String[] args) {
BehaviorTreeBuilder builder = new BehaviorTreeBuilder();
BehaviorTree behaviorTree =
builder.addBehaviour(new SelectorImpl())
.addBehaviour(new SequenceImpl())
.addBehaviour(new ConditionIsSeeEnemy())
.back()
.addBehaviour(new SelectorImpl())
.addBehaviour(new SequenceImpl())
.addBehaviour(new ConditionIsHealthLow())
.back()
.addBehaviour(new ActionRunaway())
.back()
.back()
.addBehaviour(new ActionAttack())
.back()
.back()
.back()
.addBehaviour(new ActionPatrol())
.end();
//模拟执行行为树
for (int i = 0; i < 10; ++i){
behaviorTree.tick();
System.out.println("--------------" + i + "------------");
}
System.out.println("pause ");
}
}
运行结果
运行结果:
Not SeeEnemy
ActionPatrol 巡逻
--------------0------------
Not SeeEnemy
ActionPatrol 巡逻
--------------1------------
Not SeeEnemy
ActionPatrol 巡逻
--------------2------------
SeeEnemy
Health is low
ActionRunaway 跑路
--------------3------------
Not SeeEnemy
ActionPatrol 巡逻
--------------4------------
SeeEnemy
Health is low
ActionRunaway 跑路
--------------5------------
Not SeeEnemy
ActionPatrol 巡逻
--------------6------------
SeeEnemy
Health is low
ActionRunaway 跑路
--------------7------------
SeeEnemy
Health is low
ActionRunaway 跑路
--------------8------------
SeeEnemy
Health is low
ActionRunaway 跑路
--------------9------------
pause