开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

开发者专栏

关注:1701

当前位置:游戏蛮牛 技术专区 开发者专栏

__________________________________________________________________________________
开发者干货区版块规则:

  1、文章必须是图文形式。(至少2幅图)
      2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
      3、本版块只支持在游戏蛮牛原创首发,不支持转载。
      4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
      5、......
__________________________________________________________________________________
查看: 4702|回复: 23

[凉鞋同学] Unity 游戏框架搭建 (四) 简易有限状态机

[复制链接]  [移动端链接]
排名
3595
昨日变化
3

13

主题

125

帖子

1009

积分

Rank: 9Rank: 9Rank: 9

UID
148923
好友
28
蛮牛币
1025
威望
0
注册时间
2016-5-17
在线时间
319 小时
最后登录
2017-5-22

专栏作家

QQ
发表于 2016-5-22 17:12:49 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
本帖最后由 liangxiegame 于 2016-6-5 02:06 编辑

为什么用有限状态机?
  之前做过一款跑酷游戏,跑酷角色有很多状态:跑、跳、二段跳、死亡等等。一开始是使用if/switch来切换状态,但是每次角色添加一个状态(提前没规划好),所有状态处理相关的代码就会指数级增长,那样就会嗅出代码的坏味道了。在这种处理状态并且状态数量不是特别多的情况下,自然就想到了引入状态机。

优点:
  1.使代码整洁,状态容易扩展和管理。
  2.可复用。
  3.还没想到.....
缺点:
  1.也没想到......

什么是有限状态机?
  解释不清楚,看了下百度百科。反正是一种数据结构,一个解决问题的工具。
  从百度百科可以看到,有限状态机最最最基础的概念有两个:状态和转移。
  从刚才跑酷的例子来讲,跑、跳、二段跳等这些就是角色的状态。
如图所示:

 主角从跑状态切换到跳状态,从跳状态切换到二段跳状态,这里的切换就是指状态的转移。状态的转移是有条件的,比如主角从跑状态不可以直接切换到二段跳状态。但是可以从二段跳状态切换到跑状态。
  另外,一个基本的状态有:进入状态、退出状态、接收输入、转移状态等动作。但是仅仅作为跑酷的角色的状态管理来说,只需要转移状态就足够了。有兴趣的同学可以自行扩展。

如何实现?
  恰好之前看到过一个还算简易的实现(简易就是指我能看得懂- -,希望大家也是),原版是用lua实现的,我的跑酷游戏是用C#实现的,所以直接贴出C#代码。

[C#] 纯文本查看 复制代码
using UnityEngine;  
using System.Collections;  
using System.Collections.Generic;  
public class FSM {  
    // 定义函数指针类型
    public delegate void FSMTranslationCallfunc();    /// <summary>
    /// 状态类
    /// </summary>
    public class FSMState
    {
        public string name;

        public FSMState(string name)
        {
            this.name = name;
        }
        /// <summary>
        /// 存储事件对应的条转
        /// </summary>
        public Dictionary <string,FSMTranslation> TranslationDict = new Dictionary<string,FSMTranslation>();
    }
    /// <summary>
    /// 跳转类
    /// </summary>
    public class FSMTranslation
    {
        public FSMState fromState;
        public string name;
        public FSMState toState;
        public FSMTranslationCallfunc callfunc; // 回调函数

        public FSMTranslation(FSMState fromState,string name, FSMState toState,FSMTranslationCallfunc callfunc)
        {
            this.fromState = fromState;
            this.toState   = toState;
            this.name = name;
            this.callfunc = callfunc;
        }
    }
    // 当前状态
    private FSMState mCurState;

    Dictionary <string,FSMState> StateDict = new Dictionary<string,FSMState>();
    /// <summary>
    /// 添加状态
    /// </summary>
    /// <param name="state">State.</param>
    public void AddState(FSMState state)
    {
        StateDict [state.name] = state;
    }
    /// <summary>
    /// 添加条转
    /// </summary>
    /// <param name="translation">Translation.</param>
    public void AddTranslation(FSMTranslation translation)
    {
        StateDict [translation.fromState.name].TranslationDict [translation.name] = translation;
    }
    /// <summary>
    /// 启动状态机
    /// </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#] 纯文本查看 复制代码
        // 创建状态
        FSM.FSMState idleState = new FSM.FSMState("idle");      //        Idle,               闲置
        FSM.FSMState runState  = new FSM.FSMState("run");     //        Run,                跑
        FSM.FSMState jumpState = new FSM.FSMState("jump"); //        Jump,               一段跳
        FSM.FSMState doubleJumpState = new FSM.FSMState("double_jump");  //        DoubleJump,         二段跳
        FSM.FSMState dieState  = new FSM.FSMState("die");   //        Die,                挂彩
        // 创建跳转
        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);

        // 添加状态
        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);

        // 添加跳转
        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);[mw_shl_code=csharp,true]        // 创建状态
        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");
        // 创建跳转
        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);

        // 添加状态
        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);

        // 添加跳转
        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
  就这些,想要进一步扩展的话,可以给FSMState类添加EnterCallback和ExitCallback等委托,然后在FSM的HandleEvent方法中进行调用。当时对跑酷的项目来说够用了,接没继续扩展了,我好懒- -,懒的借口是:没有最好的设计,只有最适合的设计,233333。

附:[我的框架地址](https://github.com/liangxiegame/QFramework)
转载请注明地址:[凉鞋的笔记](http://liangxiegame.com/)
状态机 unity;unity 框架搭建;unity 状态机;unity中的状态机;unity搭建框架

评分

参与人数 2鲜花 +10 收起 理由
老妖 + 5 很给力!
luckytlf000 + 5 很给力!希望以后多出些类似的帖子~.

查看全部评分

本帖被以下淘专辑推荐:


回复

使用道具 举报

7日久生情
1637/5000
排名
1031
昨日变化
1

0

主题

277

帖子

1637

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
8899
好友
0
蛮牛币
2568
威望
0
注册时间
2013-11-25
在线时间
566 小时
最后登录
2017-5-26
发表于 2016-5-23 10:58:55 | 显示全部楼层
谢谢分享                                       

回复 支持 反对

使用道具 举报

7日久生情
1547/5000
排名
1563
昨日变化
6

5

主题

540

帖子

1547

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
143831
好友
2
蛮牛币
2645
威望
0
注册时间
2016-3-29
在线时间
396 小时
最后登录
2017-5-25

蛮牛译员活力之星七夕浪漫情人

发表于 2016-5-23 20:25:23 | 显示全部楼层
谢谢分享  

回复 支持 反对

使用道具 举报

3偶尔光临
223/300
排名
13948
昨日变化
4

0

主题

75

帖子

223

积分

Rank: 3Rank: 3Rank: 3

UID
125726
好友
0
蛮牛币
362
威望
0
注册时间
2015-10-16
在线时间
116 小时
最后登录
2017-1-20
发表于 2016-5-23 22:59:21 | 显示全部楼层
你是写给你自己看的吗?

回复 支持 反对

使用道具 举报

7日久生情
1704/5000
排名
1152
昨日变化
3

3

主题

368

帖子

1704

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
46577
好友
1
蛮牛币
2021
威望
0
注册时间
2014-9-24
在线时间
597 小时
最后登录
2017-5-26
发表于 2016-5-24 08:53:32 | 显示全部楼层
不错,让我也算是正式了解了

回复 支持 反对

使用道具 举报

7日久生情
1644/5000
排名
782
昨日变化
3

1

主题

446

帖子

1644

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
111260
好友
0
蛮牛币
6205
威望
0
注册时间
2015-6-30
在线时间
277 小时
最后登录
2017-5-26
发表于 2016-5-24 09:27:32 | 显示全部楼层

谢谢分享 !

回复

使用道具 举报

排名
3595
昨日变化
3

13

主题

125

帖子

1009

积分

Rank: 9Rank: 9Rank: 9

UID
148923
好友
28
蛮牛币
1025
威望
0
注册时间
2016-5-17
在线时间
319 小时
最后登录
2017-5-22

专栏作家

QQ
 楼主| 发表于 2016-5-24 12:08:09 | 显示全部楼层
佳佳的乐趣 发表于 2016-5-23 22:59
你是写给你自己看的吗?

是呀,算是为自己的框架写的文档吧。

回复 支持 反对

使用道具 举报

5熟悉之中
661/1000
排名
3779
昨日变化
1

1

主题

167

帖子

661

积分

Rank: 5Rank: 5

UID
34428
好友
0
蛮牛币
1215
威望
0
注册时间
2014-7-15
在线时间
225 小时
最后登录
2017-2-14
发表于 2016-5-25 10:56:51 | 显示全部楼层
有没有 行为树  或 神经网络 的框架?

回复 支持 反对

使用道具 举报

7日久生情
1712/5000
排名
762
昨日变化
1

1

主题

164

帖子

1712

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
25979
好友
0
蛮牛币
800
威望
0
注册时间
2014-5-21
在线时间
615 小时
最后登录
2017-5-26
QQ
发表于 2016-5-25 11:45:21 | 显示全部楼层
首先 对大神表达我的敬畏之情~    小弟也是Unity开发人员 但是刚刚从业~     对于大神上述讲解的代码部分还是理解的  于是乎就想下载大神的框架来学习学习~     可是下载以后真心看不懂   不会用~     希望大神能有一份详细的解释文档 或者使用说明

回复 支持 反对

使用道具 举报

排名
28941
昨日变化
18

0

主题

16

帖子

36

积分

Rank: 1

UID
133558
好友
0
蛮牛币
8
威望
0
注册时间
2016-1-5
在线时间
14 小时
最后登录
2016-5-27
发表于 2016-5-26 15:43:24 | 显示全部楼层
的的的顶顶顶顶顶阿萨德

回复 支持 反对

使用道具 举报

排名
17021
昨日变化
6

0

主题

15

帖子

52

积分

Rank: 2Rank: 2

UID
59338
好友
0
蛮牛币
39
威望
0
注册时间
2014-12-4
在线时间
17 小时
最后登录
2017-4-28
发表于 2016-5-26 17:40:33 | 显示全部楼层
謝分享!  
[发帖际遇]: waltermak 被钱袋砸中进医院,看病花了 2 蛮牛币. 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

排名
3595
昨日变化
3

13

主题

125

帖子

1009

积分

Rank: 9Rank: 9Rank: 9

UID
148923
好友
28
蛮牛币
1025
威望
0
注册时间
2016-5-17
在线时间
319 小时
最后登录
2017-5-22

专栏作家

QQ
 楼主| 发表于 2016-5-26 18:59:28 | 显示全部楼层
missyouangeled 发表于 2016-5-25 11:45
首先 对大神表达我的敬畏之情~    小弟也是Unity开发人员 但是刚刚从业~     对于大神上述讲解的代码部分还 ...

谢谢建议

回复 支持 反对

使用道具 举报

排名
3595
昨日变化
3

13

主题

125

帖子

1009

积分

Rank: 9Rank: 9Rank: 9

UID
148923
好友
28
蛮牛币
1025
威望
0
注册时间
2016-5-17
在线时间
319 小时
最后登录
2017-5-22

专栏作家

QQ
 楼主| 发表于 2016-5-26 18:59:35 | 显示全部楼层
missyouangeled 发表于 2016-5-25 11:45
首先 对大神表达我的敬畏之情~    小弟也是Unity开发人员 但是刚刚从业~     对于大神上述讲解的代码部分还 ...

谢谢建议

回复 支持 反对

使用道具 举报

3偶尔光临
244/300
排名
7894
昨日变化
4

0

主题

65

帖子

244

积分

Rank: 3Rank: 3Rank: 3

UID
98960
好友
0
蛮牛币
349
威望
0
注册时间
2015-5-9
在线时间
81 小时
最后登录
2017-5-15
QQ
发表于 2016-5-31 23:36:29 | 显示全部楼层
算是读通了,准备试试练练手,谢谢分享

回复 支持 反对

使用道具 举报

2初来乍到
140/150
排名
15798
昨日变化
13

0

主题

91

帖子

140

积分

Rank: 2Rank: 2

UID
148998
好友
0
蛮牛币
65
威望
0
注册时间
2016-5-18
在线时间
25 小时
最后登录
2017-4-17
发表于 2016-6-11 20:37:13 | 显示全部楼层
感谢分享,多谢多谢多谢

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表