FSM状态机改

一.前言

FSM状态机初版

之前写过一版有限状态机,后来发现很多问题;

前一个版本是记录了当前的状态,切换状态时,要等下一帧状态机Update的时候才会调动上个状态的退出,总会有一帧的延迟

除了导致动作延迟外,状态很多的情况报错也无法追述,断点只能回到状态机中;

因此做了如下修改;

1.状态机不再继承MonoBehaviour,只需要是单例,存储所有状态基类;

2.状态机提供切换状态的方法SwitchAction,传参下个状态ID;

3.切换状态时调用上一个状态的退出周期,再调用当前状态的开始周期;

4.同时将当前状态的引用重新赋值为传入的状态;

5.状态机提供Run方法给角色控制器调用,角色控制器Update只执行当前状态的Run;

效果展示:

二.修改

修改后FSM,除增删查外添加切换状态函数SwitchState;

提供FSM状态机的生命周期;FSMInit,FSMRun,FSMEnd;

public class FSM<T>
{
private Dictionary<int, StateBase<T>> FSMActDic;
private StateBase<T> curState; //切换状态时调用
public void SwitchState(int nextID)
{
curState.OnExit();
curState = FSMActDic[nextID];
curState.OnEnter();
} public int GetCurState()
{
foreach (var kv in FSMActDic)
{
if (kv.Value == curState)
return kv.Key;
} return -1;
} public FSM()
{
FSMActDic = new Dictionary<int, StateBase<T>>();
} //增
public void AddState(int id, StateBase<T> state)
{
if(FSMActDic.ContainsKey(id))
return; FSMActDic.Add(id, state);
} //删
public void RemoveSatate(int id)
{
if (FSMActDic.ContainsKey(id))
FSMActDic.Remove(id);
} //获取
public StateBase<T> GetState(int id)
{
if (!FSMActDic.ContainsKey(id))
return null; return FSMActDic[id];
} //状态机初始化调用,给curState赋值并调用其OnStay
public void FSMInit(int id)
{
curState = FSMActDic[id];
curState.OnStay();
} //每帧执行
public void FSMRun()
{
curState.OnStay();
} //退出状态机执行
public void FSMEnd()
{
curState.OnExit();
}
}

三.测试代码

使用状态先初始化,同时设置初始状态;

角色控制类负责初始化和运行FSM状态机;

public class PlayerControl : MonoBehaviour
{
public enum PlayerState
{
none = 0,
idle,
move,
jump,
} public FSM<PlayerControl> mPlayerFSM;
public PlayerState mState;
public Animator mAnimator;
public float mSpeed;
public Vector3 moveDir; private void InitFSM()
{
mPlayerFSM.AddState((int) PlayerState.idle, new ActIdle((int) PlayerState.idle, this));
mPlayerFSM.AddState((int) PlayerState.move, new ActMove((int) PlayerState.move, this));
mPlayerFSM.AddState((int) PlayerState.jump, new ActAttack((int) PlayerState.jump, this));
mPlayerFSM.FSMInit((int)PlayerState.idle);
} void Start()
{
mAnimator = GetComponentInChildren<Animator>();
mSpeed = 10;
mPlayerFSM = new FSM<PlayerControl>();
InitFSM();
mState = PlayerState.idle;
} void Update()
{
//单纯为了在inspector面板中看到当前状态
mState = (PlayerState)mPlayerFSM.GetCurState();
mPlayerFSM.FSMRun();
}
}

在不同的行为类中,监听输入按键通过owner调用fsm的switch方法,切换状态;

举例移动行为类,监听两个轴的输入,切换idle,同时监听攻击按键切换攻击状态;

public class ActMove : StateBase<PlayerControl>
{
public ActMove(int id, PlayerControl t) : base(id, t)
{
} //给子类提供方法
public override void OnEnter(params object[] args)
{
owner.mAnimator.Play("Run");
} public override void OnStay(params object[] args)
{
owner.transform.position += owner.moveDir * Time.deltaTime * owner.mSpeed; if (Input.GetAxis("Horizontal") > 0 && Input.GetAxis("Vertical") == 0)
{
owner.moveDir = owner.transform.right;
}
else if (Input.GetAxis("Horizontal") < 0 && Input.GetAxis("Vertical") == 0)
{
owner.moveDir = -owner.transform.right;
}
else if (Input.GetAxis("Horizontal") > 0 && Input.GetAxis("Vertical") < 0)
{
owner.moveDir = owner.transform.right - owner.transform.forward;
}
else if (Input.GetAxis("Horizontal") < 0 && Input.GetAxis("Vertical") < 0)
{
owner.moveDir = -owner.transform.right - owner.transform.forward;
}
else if (Input.GetAxis("Horizontal") > 0 && Input.GetAxis("Vertical") > 0)
{
owner.moveDir = owner.transform.right + owner.transform.forward;
}
else if (Input.GetAxis("Horizontal") < 0 && Input.GetAxis("Vertical") > 0)
{
owner.moveDir = -owner.transform.right + owner.transform.forward;
}
else if (Input.GetAxis("Horizontal") == 0 && Input.GetAxis("Vertical") < 0)
{
owner.moveDir = -owner.transform.forward;
}
else if (Input.GetAxis("Horizontal") == 0 && Input.GetAxis("Vertical") > 0)
{
owner.moveDir = owner.transform.forward;
} if (Mathf.Abs(Input.GetAxis("Horizontal")) < 0.1f && Mathf.Abs(Input.GetAxis("Vertical")) < 0.1f)
owner.mPlayerFSM.SwitchState((int)PlayerControl.PlayerState.idle); if (Input.GetAxis("Jump") != 0)
owner.mPlayerFSM.SwitchState((int)PlayerControl.PlayerState.jump);
} public override void OnExit(params object[] args)
{ }
}

自从出了行为树之后,有限状态机就没太大的用武之地了,后面有机会介绍官方的BehaviourTree插件吧;

Unity——有限状态机FSM修改的更多相关文章

  1. cocos2d-x 游戏开发之有限状态机(FSM) (一)

    cocos2d-x 游戏开发之有限状态机(FSM) (一) 参考:http://blog.csdn.net/mgphuang/article/details/5845252<Cocos2d-x游 ...

  2. cocos2d-x 游戏开发之有限状态机(FSM) (二)

    cocos2d-x 游戏开发之有限状态机(FSM)  (二) 1 状态模式

  3. 有限状态机FSM(自动售报机Verilog实现)

    有限状态机FSM(自动售报机Verilog实现) FSM 状态机就是一种能够描述具有逻辑顺序和时序顺序事件的方法. 状态机有两大类:Mealy型和Moore型. Moore型状态机的输出只与当前状态有 ...

  4. Unity有限状态机编写

    有限状态机FSM 是对行为逻辑的抽象. 在整个FSM架构中 首先有一个状态基类stateObject 里面有三个方法,分别是状态前.状态中.状态后. 所有具体行为类都要继承这个基类,在这三个方法中具体 ...

  5. cocos2d-x 游戏开发之有限状态机(FSM) (四)

    cocos2d-x 游戏开发之有限状态机(FSM) (四) 虽然我们了解了FSM,并且可以写自己的FSM,但是有更好的工具帮我们完成这个繁琐的工作.SMC(http://smc.sourceforge ...

  6. cocos2d-x 游戏开发之有限状态机(FSM) (三)

    cocos2d-x 游戏开发之有限状态机(FSM) (三) 有限状态机简称FSM,现在我们创建一个专门的FSM类,负责管理对象(Monkey)的状态.然后Monkey类就实现了行为与状态分离.Monk ...

  7. 有限状态机FSM

    有限状态机(Finite-state machine)又称有限状态自动机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型.常用与:正则表达式引擎,编译器的词法和语法分析,游戏设计,网络 ...

  8. Atitit. 有限状态机 fsm 状态模式

    Atitit. 有限状态机 fsm 状态模式 1. 有限状态机 1 2. "状态表"和"状态轮换表" 1 3. 有限状态机概念(状态(State)事件(Even ...

  9. Unity编辑器 - 资源修改立即写入磁盘AssetDataBase.SaveAssets()

    Unity编辑器 - 资源修改立即写入磁盘AssetDataBase.SaveAssets() 在编写编辑器时,如果需要修改Unity序列化资源(如Prefab,美术资源,ScriptableObje ...

随机推荐

  1. 👊 Spring技术原理系列-从零开始教你SpringEL表达式使用和功能分析讲解指南(上篇)

    Spring EL表达式语言,这种语言jsp中学到的el,但是在整个spring之中其表达式语言要更加的复杂,而且支持度更加的广泛,最重要的是他可以进行方法的调用,对象的实例化,集合操作等等,但是唯一 ...

  2. C# WPF MVVM项目实战(进阶②)

    这篇文章还是在之前用Caliburn.Micro搭建好的框架上继续做的开发,今天主要是增加了一个用户窗体ImageProcessView,然后通过Treeview切换选择项之后在界面显示不同效果的图片 ...

  3. Vulnstack内网靶场1

    最近发现了一个内网的靶场网站,简单配置一下网络就可以,不用自己搭建这么麻烦漏洞信息 (qiyuanxuetang.net) 环境配置 内网1靶场由三台机器构成:WIN7.2008 server.200 ...

  4. node-pre-gyp以及node-gyp的源码简单解析(以安装sqlite3为例)

    title: node-pre-gyp以及node-gyp的源码简单解析(以安装sqlite3为例) date: 2020-11-27 tags: node native sqlite3 前言 简单来 ...

  5. Linux虚拟机配置静态ip地址

    使用VMware搭建的虚拟机ip地址经常变动,在这里记录一下虚拟机设置静态ip地址: 首先通过VMware菜单栏编辑->虚拟网络编辑器->NAT设置查看子网ip地址和网关ip: 例如我这里 ...

  6. 构建idea父工程

    构建idea父工程 首先通过idea新建一个Maven项目: 选择本地Maven版本: 工程名称: 选择字符编码:utf-8 file -> Settings -> Editor -> ...

  7. 如何无缝迁移 SpringCloud/Dubbo 应用到 Serverless 架构

    作者 | 行松 阿里巴巴云原生团队 本文整理自<Serverless 技术公开课>,"Serverless"公众号后台回复"入门",即可获取系列文章 ...

  8. Schematics Tools(Schematics 工具)

    Schematics工具 # Process: 创建逻辑示意图 arcpy.CreateDiagram_schematics("", "", "&qu ...

  9. SSM框架项目的mvc拦截器

    为了防止用户在不登录的情况下通过并接请求直接访问系统,我们需要通过session和拦截器来防止这样的情况. 拦截器的配置: 为拦截器建立一个包:interceptor,并在包里建立 LoginInte ...

  10. Upload-labs通关指南(下) 11-20

    承接上篇,这次我们继续做下半部分. 有些题目有其他做法是针对于windows系统特性的,并不能在linux上奏效,因此不在考虑范围之内. Pass-11 制作图片马直接上传 copy a.jpg /a ...