1. 程式人生 > >基於行為樹的AI框架

基於行為樹的AI框架

所謂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  //失敗
}

//基類BTNode
public 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實現遊戲物件有智慧地思考行動。