Java游戏服务器开发之行为树

Java游戏服务器开发之行为树
之前有看到过状态机、行为树这一块的内容,但是没有认真细看,现在终于静下心来认真看了看,就看了别人的实现方式(网上代码没有Java实现的),
然后使用Java语言实现了一下
运行之后,在回头看代码,果然又清晰了一些
希望写完这篇博客之后,能认识的更深刻一些,哈哈。
首先,要先感谢下这几位博主,里面的一些概念及代码都是参考这几个小哥来写的。
https://www.cnblogs.com/designyourdream/p/4459971.html
https://segmentfault.com/a/1190000012397660#articleHeader8

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,   //终止
		};
二、从各个接口来看,继承关系。
IBehaviour一个最基本的节点,是一个抽象接口,所有的接口都是继承自他。
不含有子节点(叶子节点)
IAction,游戏中的具体执行操作,比如攻击,捡物品,跑路等
ICondition,游戏中用来判断的一些条件(比如是否看到玩家,地上是否有金币),成功就返回success,失败就返回分failure
含有子节点(组合、枝干节点)
IDecorator,装饰器,将子节点的操作中添加细节,比如重复操作该子节点,具体代码见下篇
IComposite,复合节点,将多个节点进行组合。
ISequence,顺序器,组合到一起的节点会顺序执行,直到全部执行完毕或者某个返回failure
比如组合ABCD节点,顺序就是A-success-B-success-C-success-D-success,
在B那里返回failure,则不会执行到C,A-success-B-failure
ISelector,选择器,组合到一起的节点会顺序执行,直到全部执行完毕或者某个返回success
比如组合ABCD节点,顺序就是A-failure-B-failure-C-failure-D-failure,
在B那里返回success,则不会执行到C,A-failure-B-success
IParallel,并行器,多个子行为同时执行,当满足条件的时候跳出 具体代码见下篇

里面的实现列出

    

/**
			 * 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<IBehaviour> getChildren();

			  void setChildren(List<IBehaviour> 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<IBehaviour> 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<IBehaviour> getChildren() {
			return children;
		  }

		  @Override
		  public void setChildren(List<IBehaviour> behaviours) {
			this.children = (ArrayList<IBehaviour>) 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 

nice
上面的代码在码云上 https://gitee.com/lizhaoandroid/BehaviorTree ,定格分支为release1.1上
可以加qq群一起学习讨论Java游戏服务器开发的相关知识 676231524



猜你喜欢

转载自blog.csdn.net/cmqwan/article/details/80453352