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

扫一扫,访问微社区

开发者专栏

关注:2006

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

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

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

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

[复制链接]  [移动端链接]
排名
2753
昨日变化
9

28

主题

328

帖子

1590

积分

Rank: 9Rank: 9Rank: 9

UID
148923
好友
46
蛮牛币
1758
威望
0
注册时间
2016-5-17
在线时间
490 小时
最后登录
2017-12-12

专栏作家

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

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

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

x
本帖最后由 liangxiegame 于 2017-12-5 22:39 编辑

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

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

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

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

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

[C#] 纯文本查看 复制代码
namespace QFramework
{
    using System.Collections.Generic;

    /// <summary>
    /// 教程地址:http://liangxiegame.com/post/4/
    /// </summary>
    public class QFSMLite
    {
        /// <summary>
        /// FSM callfunc.
        /// </summary>
        public delegate void FSMCallfunc(params object[] param);

        /// <summary>
        /// QFSM state.
        /// </summary>
        class QFSMState
        {
            private string mName;

            public QFSMState(string name)
            {
                mName = name;
            }

            /// <summary>
            /// The translation dict.
            /// </summary>
            public readonly Dictionary<string, QFSMTranslation> TranslationDict = new Dictionary<string, QFSMTranslation>();
        }

        /// <summary>
        /// Translation 
        /// </summary>
        public class QFSMTranslation
        {
            public string FromState;
            public string Name;
            public string ToState;
            public FSMCallfunc OnTranslationCallback; // 回调函数

            public QFSMTranslation(string fromState, string name, string toState, FSMCallfunc onTranslationCallback)
            {
                FromState = fromState;
                ToState = toState;
                Name = name;
                OnTranslationCallback = onTranslationCallback;
            }
        }

        public string State { get; private set; }

        /// <summary>
        /// The m state dict.
        /// </summary>
        private readonly Dictionary<string, QFSMState> mStateDict = new Dictionary<string, QFSMState>();

        /// <summary>
        /// Adds the state.
        /// </summary>
        /// <param name="name">Name.</param>
        public void AddState(string name)
        {
            mStateDict[name] = new QFSMState(name);
        }

        /// <summary>
        /// Adds the translation.
        /// </summary>
        /// <param name="fromState">From state.</param>
        /// <param name="name">Name.</param>
        /// <param name="toState">To state.</param>
        /// <param name="callfunc">Callfunc.</param>
        public void AddTranslation(string fromState, string name, string toState, FSMCallfunc callfunc)
        {
            mStateDict[fromState].TranslationDict[name] = new QFSMTranslation(fromState, name, toState, callfunc);
        }

        /// <summary>
        /// Start the specified name.
        /// </summary>
        /// <param name="name">Name.</param>
        public void Start(string name)
        {
            State = name;
        }

        /// <summary>
        /// Handles the event.
        /// </summary>
        /// <param name="name">Name.</param>
        /// <param name="param">Parameter.</param>
        public void HandleEvent(string name, params object[] param)
        {
            if (State != null && mStateDict[State].TranslationDict.ContainsKey(name))
            {
                QFSMTranslation tempTranslation = mStateDict[State].TranslationDict[name];
                tempTranslation.OnTranslationCallback(param);
                State = tempTranslation.ToState;
            }
        }

        /// <summary>
        /// Clear this instance.
        /// </summary>
        public void Clear()
        {
            mStateDict.Clear();
        }
    }
}



测试代码(需自行修改):

[C#] 纯文本查看 复制代码
      
  
            mPlayerFsm = new QFSMLite();

            // 添加状态
            mPlayerFsm.AddState(STATE_DIE);
            mPlayerFsm.AddState(STATE_RUN);
            mPlayerFsm.AddState(STATE_JUMP);
            mPlayerFsm.AddState(STATE_DOUBLE_JUMP);
            mPlayerFsm.AddState(STATE_DIE);

            // 添加跳转
            mPlayerFsm.AddTranslation(STATE_RUN, EVENT_TOUCH_DOWN, STATE_JUMP, JumpThePlayer);
            mPlayerFsm.AddTranslation(STATE_JUMP, EVENT_TOUCH_DOWN, STATE_DOUBLE_JUMP, DoubleJumpThePlayer);
            mPlayerFsm.AddTranslation(STATE_JUMP, EVENT_LAND, STATE_RUN, RunThePlayer);
            mPlayerFsm.AddTranslation(STATE_DOUBLE_JUMP, EVENT_LAND, STATE_RUN, RunThePlayer);

            // 启动状态机
            mPlayerFsm.Start(STATE_RUN);


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

相关链接:

我的框架地址:https://github.com/liangxiegame/QFramework
教程源码:https://github.com/liangxiegame/QFramework/tree/master/Assets/HowToWriteUnityGameFramework/
转载请注明地址:凉鞋的笔记http://liangxiegame.com/
状态机 unity;unity 框架搭建;unity 状态机;unity中的状态机;unity搭建框架

评分

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

查看全部评分

本帖被以下淘专辑推荐:


回复

使用道具 举报

7日久生情
2100/5000
排名
761
昨日变化
6

0

主题

318

帖子

2100

积分

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

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

回复 支持 反对

使用道具 举报

7日久生情
1813/5000
排名
1349
昨日变化

5

主题

621

帖子

1813

积分

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

UID
143831
好友
2
蛮牛币
3481
威望
0
注册时间
2016-3-29
在线时间
451 小时
最后登录
2017-11-26

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

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

回复 支持 反对

使用道具 举报

3偶尔光临
223/300
排名
15851
昨日变化
13

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日久生情
2103/5000
排名
941
昨日变化
8

4

主题

430

帖子

2103

积分

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

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

回复 支持 反对

使用道具 举报

7日久生情
2021/5000
排名
627
昨日变化

1

主题

532

帖子

2021

积分

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

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

谢谢分享 !

回复

使用道具 举报

排名
2753
昨日变化
9

28

主题

328

帖子

1590

积分

Rank: 9Rank: 9Rank: 9

UID
148923
好友
46
蛮牛币
1758
威望
0
注册时间
2016-5-17
在线时间
490 小时
最后登录
2017-12-12

专栏作家

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

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

回复 支持 反对

使用道具 举报

5熟悉之中
669/1000
排名
4280
昨日变化
2

1

主题

168

帖子

669

积分

Rank: 5Rank: 5

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

回复 支持 反对

使用道具 举报

7日久生情
2092/5000
排名
596
昨日变化
2

1

主题

176

帖子

2092

积分

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

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

回复 支持 反对

使用道具 举报

排名
33443
昨日变化
21

0

主题

16

帖子

36

积分

Rank: 1

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

回复 支持 反对

使用道具 举报

排名
19432
昨日变化
18

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 蛮牛币. 幸运榜 / 衰神榜

回复 支持 反对

使用道具 举报

排名
2753
昨日变化
9

28

主题

328

帖子

1590

积分

Rank: 9Rank: 9Rank: 9

UID
148923
好友
46
蛮牛币
1758
威望
0
注册时间
2016-5-17
在线时间
490 小时
最后登录
2017-12-12

专栏作家

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

谢谢建议

回复 支持 反对

使用道具 举报

排名
2753
昨日变化
9

28

主题

328

帖子

1590

积分

Rank: 9Rank: 9Rank: 9

UID
148923
好友
46
蛮牛币
1758
威望
0
注册时间
2016-5-17
在线时间
490 小时
最后登录
2017-12-12

专栏作家

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

谢谢建议

回复 支持 反对

使用道具 举报

3偶尔光临
266/300
排名
8393
昨日变化
7

0

主题

68

帖子

266

积分

Rank: 3Rank: 3Rank: 3

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

回复 支持 反对

使用道具 举报

2初来乍到
145/150
排名
17951
昨日变化
11

0

主题

93

帖子

145

积分

Rank: 2Rank: 2

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

回复 支持 反对

使用道具 举报

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

本版积分规则

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