AI模組(有限狀態機、行為樹)-應用在cocos中

梦千裳~發表於2024-04-26

前言:

本模組是在cocos專案中運用戰鬥框架,根據學習別人的文章來結合專案進行編寫的,若有不對不合理的地方有勞大家指正,萬分感謝!!!若有能有用的上的,萬分榮幸!

簡介:

AI模組一般是對怪物的AI實現,或者託管等自動戰鬥的情況。具體方式可能根據專案的具體需求來選擇,常用的有:有限狀態機,行為樹。

有限狀態機(fsm)

介紹:

狀態機,或稱有限狀態機FSM(Finite State Machine),是一種重要的程式設計思想。

狀態機有3要素:狀態事件響應

  • 狀態:系統處在什麼狀態?
  • 事件:發生了什麼事?
  • 響應:此狀態下發生了這樣的事,系統要如何處理?

狀態機有三大特徵:

  • 狀態總數(state)是有限的。
  • 任一時刻,只處在一種狀態之中。
  • 某種條件下,會從一種狀態轉變(transition)到另一種狀態。

下面用在Cocos專案中的例子來做個簡單的應用:

各個狀態均包含以下操作:

export interface IState{
    OnEnter();//進入狀態機回撥
    OnExit();//退出狀態機回撥
    OnUpdate(deltaTime);//持續執行狀態
    //OnCheck();
    //OnFixdeUpdate();
}

定義對應狀態:

export enum StateType{
    //狀態機中可能的狀態
    /**未啟用 */
    InActive, 
    /**等待遊戲開始 */          
    WaitingStart,
    /**待機 */
    Idle,
    /**待機 */
    Idle_TowerDefense,
    /**移動 */
    Move,
    /**攻擊 */
    Attack,
    /**正在大殺特殺 */
    Killing,
    /**死亡中 */
    Die,
    /**怪物扮演中的玩家 */
    MonsterCosplay,
    /**顯示結算介面 */
    END,
}

定義狀態機:

@ccclass('FSM')
export class FSM{
    public curState:IState;
    public states = new Map<StateType,IState>;
    public blackboard:BlackBoard;

    public constructor(blackboard:BlackBoard){
        this.states = new Map<StateType,IState>();
        this.blackboard = blackboard;
    }

    /**增加對應狀態 */
    public AddState(stateType:StateType,state:IState){
        if(this.states.has(stateType)){
            return;
        }
        this.states.set(stateType,state);
    }

    /**切換到對應狀態 */
    public SwitchState(stateType:StateType){
        if(!this.states.has(stateType)){
            return;
        }
        if(this.curState != null){
            this.curState.OnExit();
        }
        this.curState = this.states.get(stateType);
        this.curState.OnEnter();
    }

    /**獲取到對應狀態 */
    public GetIState(stateType:StateType){
        return this.states.get(stateType);
    }

    /**這裡實現狀態機對應執行邏輯 */
    public OnUpdate(deltaTime){
        this.curState?.OnUpdate(deltaTime);
    }

    // public OnCheck(){
    //     this.curState.OnCheck();
    // }

    // public OnFixedUpdate(){
    //     this.curState.OnFixedUpdate();
    // }

}

定義AI角色狀態,並初始化狀態機(根據自己的邏輯來切換對應狀態):

//初始化狀態機
@ccclass('Test')
export class Test extends AttrBase {
    public fsm: FSM;
    public blackboard: TestBlackboard = new TestBlackboard();//此處儲存共享資料,或者向外展示的資料,可配置的資料

    InitFsm() {
        this.fsm = new FSM(this.blackboard);
        /**攻擊狀態 */
        this.fsm.AddState(StateType.Attack, new AttackState(this.fsm));
        /**增加待機狀態 */
        this.fsm.AddState(StateType.Idle, new IdleState(this.fsm));
        /**增加死亡狀態 */
        this.fsm.AddState(StateType.Die, new DieState(this.fsm));
        /**增加等待開始狀態 */
        this.fsm.AddState(StateType.WaitingStart, new WaittingState(this.fsm));
        /**增加結束狀態 */
        this.fsm.AddState(StateType.END, new ENDState(this.fsm));
    }
    Init(){
        super.Init();
        this.InitFsm();
        this.fsm.SwitchState(StateType.WaitingStart);//切換狀態為遊戲開始狀態
    }
}

//定義各個狀態
class WaittingState implements IState {
    private fsm: FSM;
    public blackboard: TestBlackboard;
    public constructor(fsm: FSM) {
        this.fsm = fsm;
        this.blackboard = fsm.blackboard as TestBlackboard;
    }

    //新開局初始化
    OnEnter() {
    }
    OnExit() {
    }

    OnUpdate(deltaTime: number) {
        if(GamePlaying){//遊戲開始
            this.fsm.SwitchState(StateType.Idle);//切換狀態IDLE
        }
    }
}

行為樹(這裡沒有太深入的研究,應用的也不太多,大概瞭解了下理論)

簡介:

行為樹(Behavior Tree)是一種用於描述複雜行為邏輯的圖形化結構,常用於遊戲開發、機器人控制、人工智慧等領域。它由節點組成,節點之間透過連線線連線,形成樹狀結構。行為樹主要由以下幾種型別的節點組成:

  • 行為節點(Action Nodes):執行具體的動作或任務,例如移動、攻擊、待機等。
  • 條件節點(Conditional Nodes):判斷條件是否滿足,通常用於控制流程的分支。
  • 複合節點(Composite Nodes):用於組合和控制其他節點的執行順序和邏輯關係,主要分為序列節點和選擇節點兩種型別:
    • 序列節點(Sequence Nodes):按順序執行其子節點,只有當所有子節點都成功執行時,序列節點才會返回成功;一旦有一個子節點失敗,則序列節點會立即返回失敗,不再執行後續節點。
    • 選擇節點(Selector Nodes):按順序嘗試執行其子節點,一旦某個子節點成功執行,選擇節點即返回成功;只有當所有子節點都失敗時,選擇節點才會返回失敗。
  • 裝飾節點(Decorator Nodes):用於修改其子節點的行為或結果,常見的裝飾節點包括反轉節點、條件節點、超時節點等。

簡單的程式碼運用

    private actionType: number = 0;
    public get ActionType(): number { return this.actionType; }
    /**玩家的行為:0為待機,1為移動,2為跳,3為跑,4為散步,9為瀕死,10為死亡 */
    public set ActionType(value: number) {
        switch (value) {
            case 0:
            case 9:
                this.ChangeAni("idle", true);
                break;
            case 2:
                break;
            case 1:
            case 3:
            case 4:
                this.ChangeAni("run", true);
                break;
            case 5:
            case 6:
            case 7:
            case 8:
                break;
            case 10:
                this.ChangeAni("die",false);
                break;
            default:
                Logger.Error("Character ActionType Error: " + value);
                break;
        }
        this.actionType = value;
    }
    
    ChangeAni(aniName: string, isLoop: boolean, func?){
        //定義自己的對應邏輯
    }

參考文章:

如何深入理解“有限狀態機”的設計思想? - 知乎 (zhihu.com)

JavaScript與有限狀態機 - 阮一峰的網路日誌 (ruanyifeng.com)

ChatGpt的回答

相關文章