查看: 2127|回復(fù): 0
打印 上一主題 下一主題

[教程] 3d素材unity 游戲框架搭建 (四) 簡(jiǎn)易有限狀態(tài)機(jī)

[復(fù)制鏈接]

Rank: 2

納金幣
48
精華
0
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2016-8-19 18:44:06 |只看該作者 |倒序?yàn)g覽
哈嘍,歡迎來到匯寶盆,首先非常感謝作者涼鞋的筆記分享這篇文章,今天要討論的問題是:為什么用有限狀態(tài)機(jī)?
??之前做過一款跑酷游戲,跑酷角色有很多狀態(tài):跑、跳、二段跳、死亡等等。一開始是使用if/switch來切換狀態(tài),但是每次角色添加一個(gè)狀態(tài)(提前沒規(guī)劃好),所有狀態(tài)處理相關(guān)的代碼就會(huì)指數(shù)級(jí)增長(zhǎng),那樣就會(huì)嗅出代碼的壞味道了。在這種處理狀態(tài)并且狀態(tài)數(shù)量不是特別多的情況下,自然就想到了引入狀態(tài)機(jī)。
優(yōu)點(diǎn):
??1.使代碼整潔,狀態(tài)容易擴(kuò)展和管理。
??2.可復(fù)用。
??3.還沒想到.....
缺點(diǎn):
??1.也沒想到......
什么是有限狀態(tài)機(jī)?
??解釋不清楚,看了下百度百科。反正是一種數(shù)據(jù)結(jié)構(gòu),一個(gè)解決問題的工具。
??從百度百科可以看到,有限狀態(tài)機(jī)最最最基礎(chǔ)的概念有兩個(gè):狀態(tài)和轉(zhuǎn)移。
??從剛才跑酷的例子來講,跑、跳、二段跳等這些就是角色的狀態(tài)。
如圖所示: ??主角從跑狀態(tài)切換到跳狀態(tài),從跳狀態(tài)切換到二段跳狀態(tài),這里的切換就是指狀態(tài)的轉(zhuǎn)移。狀態(tài)的轉(zhuǎn)移是有條件的,比如主角從跑狀態(tài)不可以直接切換到二段跳狀態(tài)。但是可以從二段跳狀態(tài)切換到跑狀態(tài)。
??另外,一個(gè)基本的狀態(tài)有:進(jìn)入狀態(tài)、退出狀態(tài)、接收輸入、轉(zhuǎn)移狀態(tài)等動(dòng)作。但是僅僅作為跑酷的角色的狀態(tài)管理來說,只需要轉(zhuǎn)移狀態(tài)就足夠了。有興趣的同學(xué)可以自行擴(kuò)展。
如何實(shí)現(xiàn)?
??恰好之前看到過一個(gè)還算簡(jiǎn)易的實(shí)現(xiàn)(簡(jiǎn)易就是指我能看得懂- -,希望大家也是),原版是用lua實(shí)現(xiàn)的,我的跑酷游戲是用C#實(shí)現(xiàn)的,所以直接貼出C#代碼。
using 3d素材unityEngine;  
using System.Collections;  
using System.Collections.Generic;  
public class FSM {  
    // 定義函數(shù)指針類型
    public delegate void FSMTranslationCallfunc();    /// <summary>
    /// 狀態(tài)類
    /// </summary>
    public class FSMState
    {
        public string name;
        public FSMState(string name)
        {
            this.name = name;
        }
        /// <summary>
        /// 存儲(chǔ)事件對(duì)應(yīng)的條轉(zhuǎn)
        /// </summary>
        public Dictionary <string,FSMTranslation> TranslationDict = new Dictionary<string,FSMTranslation>();
    }
    /// <summary>
    /// 跳轉(zhuǎn)類
    /// </summary>
    public class FSMTranslation
    {
        public FSMState fromState;
        public string name;
        public FSMState toState;
        public FSMTranslationCallfunc callfunc; // 回調(diào)函數(shù)
        public FSMTranslation(FSMState fromState,string name, FSMState toState,FSMTranslationCallfunc callfunc)
        {
            this.fromState = fromState;
            this.toState   = toState;
            this.name = name;
            this.callfunc = callfunc;
        }
    }
    // 當(dāng)前狀態(tài)
    private FSMState mCurState;
    Dictionary <string,FSMState> StateDict = new Dictionary<string,FSMState>();
    /// <summary>
    /// 添加狀態(tài)
    /// </summary>
    /// <param name="state">State.</param>
    public void AddState(FSMState state)
    {
        StateDict [state.name] = state;
    }
    /// <summary>
    /// 添加條轉(zhuǎn)
    /// </summary>
    /// <param name="translation">Translation.</param>
    public void AddTranslation(FSMTranslation translation)
    {
        StateDict [translation.fromState.name].TranslationDict [translation.name] = translation;
    }
    /// <summary>
    /// 啟動(dòng)狀態(tài)機(jī)
    /// </summary>
    /// <param name="state">State.</param>
    public void Start(FSMState state)
    {
        mCurState = state;
    }
    /// <summary>
    /// 處理事件
    /// </summary>
    /// <param name="name">Name.</param>
    public void HandleEvent(string name)
    {
        if (mCurState != null && mCurState.TranslationDict.ContainsKey(name)) {
            Debug.LogWarning ("fromState:" + mCurState.name);
            mCurState.TranslationDict [name].callfunc ();
            mCurState = mCurState.TranslationDict [name].toState;
            Debug.LogWarning ("toState:" + mCurState.name);
        }
    }
}
測(cè)試代碼(需自行修改):
//        Idle,               閑置
//        Run,               
//        Jump,               一段跳
//        DoubleJump,         二段跳
//        Die,                掛彩
        // 創(chuàng)建狀態(tài)
        FSM.FSMState idleState = new FSM.FSMState("idle");
        FSM.FSMState runState  = new FSM.FSMState("run");
        FSM.FSMState jumpstate = new FSM.FSMState("jump");
        FSM.FSMState doubleJumpState = new FSM.FSMState("double_jump");
        FSM.FSMState dieState  = new FSM.FSMState("die");
        // 創(chuàng)建跳轉(zhuǎn)
        FSM.FSMTranslation touchTranslation1 = new FSM.FSMTranslation(runState,"touch_down",jumpState,Jump);
        FSM.FSMTranslation touchTranslation2 = new FSM.FSMTranslation(jumpState,"touch_down",doubleJumpState,DoubleJump);
        FSM.FSMTranslation landTranslation1 = new FSM.FSMTranslation(jumpState,"land",runState,Run);
        FSM.FSMTranslation landTranslation2 = new FSM.FSMTranslation(doubleJumpState,"land",runState,Run);
        // 添加狀態(tài)
        PlayerModel.Instance ().fsm.AddState (idleState);
        PlayerModel.Instance ().fsm.AddState (runState);
        PlayerModel.Instance ().fsm.AddState (jumpState);
        PlayerModel.Instance ().fsm.AddState (doubleJumpState);
        PlayerModel.Instance ().fsm.AddState (dieState);
        // 添加跳轉(zhuǎn)
        PlayerModel.Instance ().fsm.AddTranslation (touchTranslation1);
        PlayerModel.Instance ().fsm.AddTranslation (touchTranslation2);
        PlayerModel.Instance ().fsm.AddTranslation (landTranslation1);
        PlayerModel.Instance ().fsm.AddTranslation (landTranslation2);
        PlayerModel.Instance ().fsm.Start (runState);
貼上代碼地址址:https://github.com/liangxiegame/QFramework/blob/master/Script/DesignPattern/QFSM.cs
??就這些,想要進(jìn)一步擴(kuò)展的話,可以給FSMState類添加EnterCallbackExitCallback等委托,然后在FSMHandleEvent方法中進(jìn)行調(diào)用。當(dāng)時(shí)對(duì)跑酷的項(xiàng)目來說夠用了,接沒繼續(xù)擴(kuò)展了,我好懶- -,懶的借口是:沒有最好的設(shè)計(jì),只有最適合的設(shè)計(jì),233333
看完了這篇分享,是不是對(duì)3d素材unity游戲搭建有一定的了解了呢,如果能給您帶來一些幫助,匯寶盆萬分榮幸!更多精彩可以進(jìn)群討論分享納金網(wǎng)匯寶盆交流⑤群 341024464。
本文轉(zhuǎn)載自網(wǎng)絡(luò),謝謝作者分享。

本帖被以下淘專輯推薦:

  • · 教程|主題: 5, 訂閱: 1
分享到: QQ好友和群QQ好友和群 騰訊微博騰訊微博 騰訊朋友騰訊朋友 微信微信
轉(zhuǎn)播轉(zhuǎn)播0 分享淘帖1 收藏收藏1 支持支持0 反對(duì)反對(duì)0
回復(fù)

使用道具 舉報(bào)

手機(jī)版|納金網(wǎng) ( 閩ICP備2021016425號(hào)-2/3

GMT+8, 2024-10-31 07:24 , Processed in 0.099101 second(s), 30 queries .

Powered by Discuz!-創(chuàng)意設(shè)計(jì) X2.5

© 2008-2019 Narkii Inc.

回頂部