unity 简易有限状态机实现
在我们从事unity工作时,有时候会面对复杂的状态切换,最简单的方法就是用if else 或者 switch 进行状态判断,如果状态少还好,但是当状态多达十几个甚至几十个的时候,我们的所要写的代发就可能出现耦合、冗余甚至难以维护的情况。这时候设计一款有限状态机FSM就可以帮我们轻松的搞定这些问题。
有限状态机,(Finite-state machine, FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。简单说就是控制对象的有限状态间的转换。
本人参考了 凉鞋 老师的QFramework的简易状态机
FSM主要实现功能:
State 的 添加/移除
设置初始 State
转换相关State(current State -> next State,StateChaged) 配置/移除
State enter / exit 方法回调
State 转换执行逻辑触发,事件方法回调,并更新State状态
具体代码如下:
using System;
using System.Collections.Generic;
using UnityEngine;
namespace YFramework
{
///
/// 简易有限状态机
///
public class FSMLite
{
///
/// 状态转换传入参数
///
public delegate void FSMStateChaged(params object[] stateParams);
///
/// 状态
///
public class FSMState
{
private string name;
public readonly Dictionary stateTranslations = new Dictionary();
public Action stateEnter;
public Action stateExit;
public FSMState(string name, Action stateEnter, Action stateExit)
{
this.name = name;
this.stateEnter = stateEnter;
this.stateExit = stateExit;
}
}
///
/// 状态转换 保存转换前和转换后的状态
///
public class FSMTranslation
{
public string name;
public string fromState;
public string toState;
public FSMStateChaged callBack;
public FSMTranslation(string name, string fromState, string toState, FSMStateChaged callBack)
{
this.name = name;
this.fromState = fromState;
this.toState = toState;
this.callBack = callBack;
}
}
private readonly Dictionary mStates = new Dictionary();
///
/// 当前状态
///
public string State { get; private set; }
///
/// 添加状态
///
public void AddState(string stateName, Action star = null, Action end = null)
{
mStates[stateName] = new FSMState(stateName, star, end);
}
///
/// 添加注册状态转换
///
public void AddTranslation(string translationName, string fromState, string toState, FSMStateChaged callBack)
{
if (mStates.ContainsKey(fromState))
mStates[fromState].stateTranslations[translationName] = new FSMTranslation(translationName, fromState, toState, callBack);
else
Debug.LogError("Please Add FSMState:" + fromState);
}
///
/// 删除状态
///
public void RemoveState(string stateName)
{
if (mStates.ContainsKey(stateName))
mStates.Remove(stateName);
}
///
/// 删除状态转换
///
public void RemoveTraslation(string translationName,string stateName)
{
if (mStates.ContainsKey(stateName) && mStates[stateName].stateTranslations.ContainsKey(translationName))
{
mStates[stateName].stateTranslations.Remove(translationName);
}
}
///
/// 设置初始状态
///
public void Star(string stateName)
{
if (mStates.ContainsKey(stateName))
State = stateName;
else
{
State = null;
Debug.LogError(string.Format("FMSStates don't contains the star state '{0}'", stateName));
}
}
///
/// 执行状态转换
///
public void StateChage(string translationName, params object[] mParams)
{
if (!string.IsNullOrEmpty(State) && mStates.ContainsKey(State) && mStates[State].stateTranslations.ContainsKey(translationName))
{
FSMTranslation translation = mStates[State].stateTranslations[translationName];
translation.callBack(mParams);
State = translation.toState;
if (mStates[translation.fromState].stateExit != null)
mStates[translation.fromState].stateExit();
if (mStates[translation.toState].stateEnter != null)
mStates[translation.toState].stateEnter();
}
else if (string.IsNullOrEmpty(State))
Debug.LogError(string.Format("the Star State is null or you don't set the Star State", State));
else if (!mStates.ContainsKey(State))
Debug.LogError(string.Format("the state '{0}' have not added", State));
else if (!mStates[State].stateTranslations.ContainsKey(translationName))
Debug.LogError(string.Format("the current state doesn't have the event '{0}' action", translationName));
}
///
/// 清空状态
///
public void StateClear()
{
mStates.Clear();
}
}
}
测试代码如下:
public void FSMTest()
{
//创建FSM
FSMLite lite = new FSMLite();
string StateJump = "jump";
string StateRun = "run";
string StateDoubleJump = "doubleJump";
string EventLand = "land";
string EventTouchDown = "touchDown";
string EventJump = "eventJump";
FSMLite.FSMStateChaged playerRun = (mParams) =>
{
Debug.Log("PlayerRun ~");
};
FSMLite.FSMStateChaged playerFristJump = (mParams) =>
{
Debug.Log("Player Frist Jump ~");
};
FSMLite.FSMStateChaged playerDoubleJump = (mParams) =>
{
Debug.Log("Player Double Jump ~");
};
//添加State
lite.AddState(StateRun,()=> Debug.Log("Run Star"),()=> Debug.Log("Run End"));
lite.AddState(StateJump, () => Debug.Log("Jump Star"), () => Debug.Log("Jump End"));
lite.AddState(StateDoubleJump, () => Debug.Log("Double Jump Star"), () => Debug.Log("Double Jump End"));
//配置State转换
lite.AddTranslation(EventLand, StateJump, StateRun, playerRun);
lite.AddTranslation(EventLand, StateDoubleJump, StateRun, playerRun);
lite.AddTranslation(EventTouchDown, StateRun, StateJump, playerFristJump);
lite.AddTranslation(EventJump, StateJump, StateDoubleJump, playerDoubleJump);
//设置初始State
lite.Star(StateRun);
//执行转换
lite.StateChage(EventTouchDown, null);
}
代码稍微有点多,功能的实现也比较简单,希望有不足的地方大家可以留言,我会尽快改进~
希望能对大家的学习生活有所帮助~