基于行为树的AI框架

来源:互联网 发布:网络上骂王宝强的 编辑:程序博客网 时间:2024/06/06 11:40

所谓AI即人工智能,例如扫荡副本,boss,小怪有智慧地攻击玩家等pve(player vs Environment)的地方都会用到。程序可以设计不同的AI来调整难度,让boss小怪显得更加有智慧。实现AI的方式有很多种,从有限状态机(FSM),分层有限状态机(HFSM)到决策树(Decision Tree),都可以维护庞大数量的知识条目。本文要介绍的是Next-Gen AI的行为树(Behavior Tree)。

行为树(Behavior Tree) 具有如下的特性:
 它只有4大类型的Node:
  * Composite Node  组合节点
  * Decorator Node  装饰节点
  * Condition Node  条件节点
  * Action Node   行为节点
  任何Node被执行后,必须向其Parent Node报告执行结果:成功 / 失败。
  这简单的成功 / 失败汇报原则被很巧妙地用于控制整棵树的决策方向。

其中,组合节点有顺序节点(SequenceNode有一个子节点返回false就结束,相当于与运算)和选择节点(SelectorNode有一个子节点返回true就结束,相当于或运算)两种,条件节点和行为节点属于叶子节点,即没有子节点。光说文字很难理解。一个比较有名的AI行为树如下



下面是一个项目中用到的AI行为树框架

类继承关系如下

根据上面各节点的描述,有以下流程图。


具体的伪代码如下

using System;public enum State{    INIT,  //初始化    PENDING,  //正在执行    FINISH,  //成功    FAIL  //失败}//基类BTNodepublic class BTNode{    State state;    ComponentNode parent;    public virtual void reset()    {      state = State.Init;    }   //执行方法,用于重载override       public virtual void execute(AIControl agent)   {          }   public virtual void finish(AIControl agent, State stat)   {       this.state = stat;       if(this.parent!=null)       {           //把state传给父节点           this.parent.tryMoveNext(agent, stat);       }   }}//复合节点public class ComponentNode:BTNode{    List<BTNode> childs; //子节点    bool isFirstExe; //是否第一次执行,用于初始化    addChild(){};//添加子节点    removeChild(){};//移除子节点    override finish(){base.finish();}    moveNext()    {        if(CanMoveNext())        {            nextChild.execute();        }        else        {            moveEnd();        }    }    //先判断条件是否能执行下一个子节点再执行    tryMoveNext(State stat)    {         if(checkState(stat))         {             moveNext();         }    }    override execute()    {       if(isFistExe){isFirstExe = false;beforeFirstExecute();}       moveNext();    }    virtual beforeFirstExecute(){}//用于初始化    virtual checkState(){}//用于override    virtual moveEnd(){}   //用于override}public class SequenceNode : ComponentNode{    override bool checkState(State stat)    {         if(stat == State.Fail)         {             finish(State.fail);             return false;          }         return true;    }    override void moveEnd()    {        finish(State.finish);    }}public class SelectorNode : ComponentNode{    override bool checkState(State stat)    {         if(stat == State.finish)         {             finish(State.finish);             return false;          }          return true;    }    override void moveEnd()    {        finish(State.Fail);    }}public class BehaviorNode:BTNode{    }//条件节点class ConditionNode : BehaviorNode{    override void execute()    {        if(condition())        {            finish(State.finish);        }        else        {            finish(State.fail);        }    }    virtual bool condition(){}}//行为节点class ActionNode:BehaviorNode{   virtual void execute()   {       finish(State.pending);   }}//具体实现的选择节点class xxx:SelectorNode{    override void beforeFirstExecute(){}    override void execute(){}}//具体实现的顺序节点class yyy:SequenceNode{    override void beforeFirstExecute(){}    override void execute(){}}//具体实现的条件节点class yyy : ConditionNode{     override bool condition(){}}//具体实现的行为节点class zzz:ActionNode{    override void execute(){}}//AIControl存放一颗AI行为树的根节点,每隔一段时间从根节点遍历行为树,根据当前的情况实现不同的分支叶子节点,从而实现具体的游戏逻辑class AIControl{    root = 读表根节点    think()    {       每隔一段时间 root.execute(this);       }    }

以上是一个底层的行为树基本框架,具体的程序实现,需要根据策划的需求,实现各个具体的节点,一般是继承选择节点,顺序节点,条件节点,行为节点用得比较多。一些需要循环执行等特殊操作的装饰类节点在项目中比较少用,在这里也就没有具体实现了。项目中通过读取策划导出的约定好的AI行为树文件,在逻辑层调用AIControl.think实现游戏对象有智慧地思考行动。

1 0
原创粉丝点击