为什么用有限状态机?

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

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

什么是有限状态机?

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

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

如何实现?

  恰好之前看到过一个还算简易的实现(简易就是指我能看得懂- -,希望大家也是),原版是用lua实现的,我的跑酷游戏是用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);
}
}
}

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

//        Idle,               闲置
// Run, 跑
// Jump, 一段跳
// DoubleJump, 二段跳
// Die, 挂彩 // 创建状态
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);

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

此篇的内容就这些。

转载请注明地址:凉鞋的笔记:liangxiegame.com

更多内容

Unity 游戏框架搭建 (四) 简易有限状态机的更多相关文章

  1. Unity 游戏框架搭建 (五) 简易消息机制

    什么是消息机制? 23333333,让我先笑一会. 为什么用消息机制?   三个字,解!!!!耦!!!!合!!!!. 我的框架中的消息机制用例: 1.接收者 ``` using UnityEngine ...

  2. Unity 游戏框架搭建 (十一) 简易AssetBundle打包工具(一)

    最近在看Unity官方的AssetBundle(以下简称AB)的教程,也照着做了一遍,不过做出来的AssetBundleManager的API设计得有些不太习惯.目前想到了一个可行的解决方案.AB相关 ...

  3. Unity 游戏框架搭建 (十) QFramework v0.0.2小结

    从框架搭建系列的第一篇文章开始到现在有四个多月时间了,这段时间对自己来说有很多的收获,好多小伙伴和前辈不管是在评论区还是私下里给出的建议非常有参考性,在此先谢过各位. 说到是一篇小节,先列出框架的概要 ...

  4. Unity 游戏框架搭建 2018 (一) 架构、框架与 QFramework 简介

    约定 还记得上版本的第二十四篇的约定嘛?现在出来履行啦~ 为什么要重制? 之前写的专栏都是按照心情写的,在最初的时候笔者什么都不懂,而且文章的发布是按照很随性的一个顺序.结果就是说,大家都看完了,都还 ...

  5. Unity 游戏框架搭建 (十六) v0.0.1 架构调整

    背景: 前段时间用Xamarin.OSX开发一些工具,遇到了两个问题. QFramework的大部分的类耦合了Unity的API,这样导致不能在其他CLR平台使用QFramework. QFramew ...

  6. Unity 游戏框架搭建 (十三) 无需继承的单例的模板

    之前的文章中介绍的Unity 游戏框架搭建 (二) 单例的模板和Unity 游戏框架搭建 (三) MonoBehaviour单例的模板有一些问题. 存在的问题: 只要继承了单例的模板就无法再继承其他的 ...

  7. Unity 游戏框架搭建 (十七) 静态扩展GameObject实现链式编程

    本篇本来是作为原来 优雅的QChain的第一篇的内容,但是QChain流产了,所以收录到了游戏框架搭建系列.本篇介绍如何实现GameObject的链式编程. 链式编程的实现技术之一是C#的静态扩展.静 ...

  8. Unity 游戏框架搭建 2019 (四十六) 简易消息机制 & 集成到 MonoBehaviourSimplify 里

    在上一篇,我们接触了单例,使用单例解决了我们脚本之间访问的问题. 脚本之间访问其实有更好的方式. 我们先分下脚本访问脚本的几种形式. 第一种,A GameObject 是 B GameObject 的 ...

  9. Unity 游戏框架搭建 (十九) 简易对象池

    在Unity中我们经常会用到对象池,使用对象池无非就是解决两个问题: 一是减少new时候寻址造成的消耗,该消耗的原因是内存碎片. 二是减少Object.Instantiate时内部进行序列化和反序列化 ...

随机推荐

  1. JDK的并发容器

          除了提供诸如同步控制,线程池等基本工具外,为了提高开发人员的效率,JDK已经为我们准备了一大批好用的并发容器,这些容器都是线程安全的,可以大大减少开发工作量.你可以在里面找到链表.Hash ...

  2. Python ORM框架之 Peewee入门

    之前在学Django时,发现它的模型层非常好用,把对数据库的操作映射成对类.对象的操作,避免了我们直接写在Web项目中SQL语句,当时想,如果这个模型层可以独立出来使用就好了,那我们平台操作数据库也可 ...

  3. 那些年,让我们一起着迷的Spring

    构建企业级应用框架(SpringMVC+Spring+Hibernate/ibatis[Mybatis]) 框架特点:半成品,封装了特定的处理流程和控制逻辑,成熟的,不断升级的软件.重用度高,开发效率 ...

  4. XD

    题目 是否完成 题目分类 简要题解 没有上司的舞会(codevs1380) Y 树形dp dp[u][0]表示不包含此节点,dp[u][1]表示包含,转移方程为 dp[u][0]+=max(dp[v] ...

  5. Js实现京东无延迟菜单效果(demo)

    一个端午节,外面人山人海,又那么热,我认为宅在家里看看慕课网,充实自己来的实际... 这是一个js实现京东无延迟菜单效果,感觉很好,分享给大家... 1.开发基本的菜单结构 2.开发普通的二级菜单效果 ...

  6. Spring component-scan 的逻辑 、单例模式下多实例问题、事务失效

    原创内容,转发请保留:http://www.cnblogs.com/iceJava/p/6930118.html,谢谢 之前遇到该问题,今天查看了下 spring 4.x 的代码 一,先理解下 con ...

  7. 开源解析库 - JSON

    Json及其实现 JSON作为一种轻量级的数据交换格式,多被用于跨语言通信(比如CPP与PHP之间的数据交互). 至于何为JSON,其详细解释参考 官网. 既然是一种格式,那便必然有相应的编码实现.在 ...

  8. Unity运动残影技能

    残影实现: 1.List<DrawMesh> list,此list中包含某一帧动画模型网格.材质 2.每过一段时间就将运动物体的模型add到list中(优化:未实现,网格合并) 3.Lat ...

  9. 01--数据库MySQL:【数据库DB】和【数据库管理系统DBMS】 简介

    1.数据库DB 数据库:DB(DataBase) 按照一定规则存储在计算机的内部存储设备上被各种用户或者应用共享的数据集合 2.数据库管理系统DBMS 1)数据库管理系统DBMS:DBMS(DataB ...

  10. Unity应用架构设计(11)——一个网络层的构建

    对于客户端应用程序,免不了和远程服务打交道.设计一个良好的『服务层』能帮我们规范和分离业务代码,提高生产效率.服务层最核心的模块一定是怎样发送请求,虽然Mono提供了很多C#网络请求类,诸如WebCl ...