Unity——有限状态机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修改的更多相关文章
- cocos2d-x 游戏开发之有限状态机(FSM) (一)
cocos2d-x 游戏开发之有限状态机(FSM) (一) 参考:http://blog.csdn.net/mgphuang/article/details/5845252<Cocos2d-x游 ...
- cocos2d-x 游戏开发之有限状态机(FSM) (二)
cocos2d-x 游戏开发之有限状态机(FSM) (二) 1 状态模式
- 有限状态机FSM(自动售报机Verilog实现)
有限状态机FSM(自动售报机Verilog实现) FSM 状态机就是一种能够描述具有逻辑顺序和时序顺序事件的方法. 状态机有两大类:Mealy型和Moore型. Moore型状态机的输出只与当前状态有 ...
- Unity有限状态机编写
有限状态机FSM 是对行为逻辑的抽象. 在整个FSM架构中 首先有一个状态基类stateObject 里面有三个方法,分别是状态前.状态中.状态后. 所有具体行为类都要继承这个基类,在这三个方法中具体 ...
- cocos2d-x 游戏开发之有限状态机(FSM) (四)
cocos2d-x 游戏开发之有限状态机(FSM) (四) 虽然我们了解了FSM,并且可以写自己的FSM,但是有更好的工具帮我们完成这个繁琐的工作.SMC(http://smc.sourceforge ...
- cocos2d-x 游戏开发之有限状态机(FSM) (三)
cocos2d-x 游戏开发之有限状态机(FSM) (三) 有限状态机简称FSM,现在我们创建一个专门的FSM类,负责管理对象(Monkey)的状态.然后Monkey类就实现了行为与状态分离.Monk ...
- 有限状态机FSM
有限状态机(Finite-state machine)又称有限状态自动机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型.常用与:正则表达式引擎,编译器的词法和语法分析,游戏设计,网络 ...
- Atitit. 有限状态机 fsm 状态模式
Atitit. 有限状态机 fsm 状态模式 1. 有限状态机 1 2. "状态表"和"状态轮换表" 1 3. 有限状态机概念(状态(State)事件(Even ...
- Unity编辑器 - 资源修改立即写入磁盘AssetDataBase.SaveAssets()
Unity编辑器 - 资源修改立即写入磁盘AssetDataBase.SaveAssets() 在编写编辑器时,如果需要修改Unity序列化资源(如Prefab,美术资源,ScriptableObje ...
随机推荐
- IdentityServer4[4]使用密码保护API资源
使用密码保护API资源(资源所有者密码授权模式) 资源所有者(Resource Owner)就是指的User,也就是用户.所以也称为用户名密码模式.相对于客户端凭证模式,增加了一个参与者User.通过 ...
- 分组密码(五)AES算法② — 密码学复习(八)
在上一篇简单复习了AES的历史时间节点.产生背景.与DES的对比.算法框图(粗略)以及一些数学基础,如果不记得的话点击这里回顾.下面将介绍AES算法的细节. 下面给出AES算法的流程,图片来源:密码算 ...
- MySQL的本地事务、全局事务、分布式事务
本地事务 事务特性:ACID,其中C一致性是目的,AID是手段. 实现隔离性 写锁:数据加了写锁,其他事务不能写也不能读. 读锁:数据加了读锁,其他事务不能加写锁可以加读锁,可以允许自己升级为写锁. ...
- 极简SpringBoot指南-Chapter05-SpringBoot中的AOP面向切面编程简介
仓库地址 w4ngzhen/springboot-simple-guide: This is a project that guides SpringBoot users to get started ...
- 题解 2020.10.24 考试 T2 选数
题目传送门 题目大意 见题面. 思路 本来以为zcx.pxj变强了,后来发现是SPJ出问题了...考试的时候感觉有点人均啊...结果自己还是只想出来一半. 我们假设 \(f(x)=(\lfloor\f ...
- 纯前端H5小应用_localStorage存储
开发缘由[需求发现和分析] 想要送朋友一个礼物,但是想了想,街上买的东西,em~,我们这样的猿确实不会选礼物啊,由此就想利用自己手中的工具和知识做点有用的东西吧,抱枕是礼物,钢笔是礼物,电子产品也是礼 ...
- Catch That Cow 经典广搜
链接:http://poj.org/problem?id=3278 题目: Farmer John has been informed of the location of a fugitive co ...
- pycharm安装pika提示CondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://repo.anaconda.com>
1. 问题描述: pycharm安装第三方库时提示CondaHTTPError: HTTP 000 CONNECTION FAILED. 2. 错误原因:默认镜像源访问速度过慢,会导致超时从而导致更新 ...
- JSP(java server pages)安装开发和执行环境
JSP是一种动态网页技术标准. 它是在传统的网页HTML文件中插入Java程序段(Scriptlet)和JSP标记(tag)的.jsp文件: java程序段:操纵数据库,重新定向网页,发送email等 ...
- 运维常用python库&模块
sutil:是一个跨平台库(https://github.com/giampaolo/psutil)能够实现获取系统运行的进程和系统利用率(内存,CPU,磁盘,网络等),主要用于系统监控,分析和系统资 ...