基于FSM 有限状态机

最近在做一款大型的商业项目,多个面板之间的切换以及 显示隐藏,很明显,这里如果说使用 禁用或者激活游戏物体的方法是不可行的,因为你无法保证一定是有多少种面板,另外一个就是你也不发保证每次要打开的是谁?隐藏的是谁?也许有同学会说到使用对象池技术,用的时候取,不用的时候回收自身, 这样的话乍一听虽然没问题,但是真正做的时候会很烧脑。下面将一个一个的进行列举:

首先比如说 场景中 n 个对象,那么我们第一次打开的时候 肯定就是 n+0,第二次打开的按照正常逻辑肯定就是n+1个面板了,以此类推,那么这个时候比如说我们的玩家比较调皮。第一次打开的为 n+0,第二次打开的面板为 n+5,那么你是该显示那个面板呢?也有比较倔强的朋友,我写判断啊,OK,即使你写判断,你算算多少 if else 或者他说 switch,OK,那么你依然可以想想有多少枚举?

so,这里我们引入了 FSM 有限状态机,它的原理是神马样子的呢?

StateMgr(FSM)_List


假如说上面的 正方形是我们游戏中不同的面板,那么这里我们从当前的状态可以改变到任一状态,只需要中间牵出一条线即可,不会影响我们整个面板 UI 的业务,相当于我们永远持有一个当前状态,我们默认让它的状态为 null,也就是玩家没有作任何的操作的时候,然后还有一个状态集。那么当我们用户进行一些点击操作以后,我们就可以从状态集中找到要变换的状态,也就是面板,这样从而就可以进行随意的切换。或许有同学又有疑惑了,那么你怎么隐藏呢? 这里有一个插件 DwTween,动画插件,我们每次显示的时候 直接控制它的 Scale 大小为1,当隐藏的时候直接控制 为 0,是不是感觉比较巧妙,这样我们每次连初始化的操作都能省去。

OK,不废话,上代码咯;

//==========================
// - FileName: IState.cs
// - Created: true.
// - CreateTime: 2020/05/13 00:08:51
// - Region: China WUHAN
// - Description: 抽象接口
//==========================
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface IState
{
/// <summary>
/// 状态进入
/// </summary>
void OnEnter();
/// <summary>
/// 状态更新
/// </summary>
void OnUpdate();
/// <summary>
/// 状态退出
/// </summary>
void OnExit();
/// <summary>
/// 获得状态
/// </summary>
string GetState();
}

//==========================
// - FileName: IState.cs
// - Created: true.
// - CreateTime: 2020/05/13 00:08:51
// - Region: China WUHAN
// - Description: 抽象基类
//==========================
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.Experimental.PlayerLoop;
// <summary>
/// This class represents the States in the Finite State System.该类表示有限状态系统中的状态。
/// Each state has a Dictionary with pairs (transition-state) showing 每个状态都有一个对显示(转换状态)的字典
/// which state the FSM should be if a transition is fired while this state is the current state.如果在此状态为当前状态时触发转换,则FSM应处于那种状态。
/// Method Reason is used to determine which transition should be fired .方法原因用于确定应触发哪个转换。
/// Method Act has the code to perform the actions the NPC is supposed do if it's on this state.方法具有执行NPC动作的代码应该在这种状态下执行。
/// </summary>
public abstract class BaseFSMState : MonoBehaviour
{
public Dictionary<EnumTransition, EnumStateID> map = new Dictionary<EnumTransition, EnumStateID>(); //字典 《转换,状态ID》
protected EnumStateID stateID; //私有ID
public EnumStateID ID //状态ID
{
get { return stateID; }
}

protected StateManager manager; //保证子类状态可以访问到总控 GameManager
public StateManager Manager
{
set { manager = value; }
}


/// <summary>
/// 添加转换
/// </summary>
/// <param name="trans">转换状态</param>
/// <param name="id">转换ID</param>
public void AddTransition(EnumTransition trans, EnumStateID id)
{
if (trans == EnumTransition.NullTransition) // Check if anyone of the args is invalid —— //检查是否有参数无效
{
Debug.LogError("FSMState错误:NullTransition不允许进行真正的transition");
return;
}

if (id == EnumStateID.NullStateId)
{
Debug.LogError("一个真实的transitionFSMState错误:NullStateID不允许一个真实的ID");
return;
}

if (map.ContainsKey(trans)) // Since this is a Deterministic FSM,check if the current transition was already inside the map —— 因为这是一个确定性FSM,检查当前的转换是否已经在字典中
{
Debug.LogError("FSMState ERROR: State " + stateID.ToString() + " already has transition " + trans.ToString() +
"Impossible to assign to another state");
return;
}

map.Add(trans, id);
}


/// <summary>
/// This method deletes a pair transition-state from this state's map. —— 该方法从状态映射中删除一对转换状态。
/// If the transition was not inside the state's map, an ERROR message is printed. —— 如果转换不在状态映射内,则会打印一条错误消息。
/// </summary>
public void DeleteTransition(EnumTransition trans)
{
if (trans == EnumTransition.NullTransition) // Check for NullTransition —— 检查状态是否为空
{
Debug.LogError("FSMState ERROR: NullTransition is not allowed");
return;
}

if (map.ContainsKey(trans)) // Check if the pair is inside the map before deleting —— 在删除之前,检查这一对是否在字典中
{
map.Remove(trans);
return;
}
Debug.LogError("FSMState ERROR: Transition " + trans.ToString() + " passed to " + stateID.ToString() +
" was not on the state's transition list");
}


/// <summary>
/// This method returns the new state the FSM should be if this state receives a transition and—— 如果该状态接收到转换,该方法返回FSM应该为新状态
/// 得到输出状态
/// </summary>
public EnumStateID GetOutputState(EnumTransition trans)
{
if (map.ContainsKey(trans)) // Check if the map has this transition —— 检查字典中是否有这个状态
{
return map[trans];
}
return EnumStateID.NullStateId;
}


/// <summary>
/// This method is used to set up the State condition before entering it. —— 该方法用于在进入状态条件之前设置状态条件。
/// It is called automatically by the FSMSystem class before assigning it to the current state.—— 在分配它之前,FSMSystem类会自动调用它到当前状态
/// </summary>
public virtual void DoBeforeEntering()
{
}


/// <summary>
/// 此方法用于在FSMSystem更改为另一个变量之前进行任何必要的修改。在切换到新状态之前,FSMSystem会自动调用它。
/// This method is used to make anything necessary, as reseting variables
/// before the FSMSystem changes to another one. It is called automatically
/// by the FSMSystem before changing to a new state.
/// </summary>
public virtual void DoBeforeLeaving()
{

}


/// <summary>
/// 这个方法决定状态是否应该转换到它列表上的另一个NPC是对这个类控制的对象的引用
/// This method decides if the state should transition to another on its list
/// NPC is a reference to the object that is controlled by this class
/// </summary>
public virtual void Reason()
{

}


/// <summary>
/// 这种方法控制了NPC在游戏世界中的行为。
/// NPC做的每一个动作、动作或交流都应该放在这里
/// NPC是这个类控制的对象的引用
/// This method controls the behavior of the NPC in the game World.
/// Every action, movement or communication the NPC does should be placed here
/// NPC is a reference to the object that is controlled by this class
/// </summary>
public virtual void Act()
{

}
}
//==========================
// - FileName: FSMManager.cs
// - Created: true.
// - CreateTime: 2020/05/13 00:08:27
// - Region: China WUHAN
// - Description: 状态系统
//==========================
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FSMManager
{
private List<IState> mList; //状态机维护的一组状态
public IState CurrentState { get; private set; } //当前状态

public FSMManager()
{
mList = new List<IState>();
}

public void AddState(IState _state)// 添加指定的状态
{
IState _tmpState = GetState(_state.GetState());
if (_tmpState == null)
{
mList.Add(_state);
}
else
{
Debug.LogWarningFormat("FSMSystem(容错):该状态【{0}】已经被添加!", _state.GetState().ToString());
}
}

public void RemoveState(IState _state) //删除状态
{
IState _tmpState = GetState(_state.GetState());
if (_tmpState != null)
{
mList.Remove(_tmpState);
}
else
{
Debug.LogWarningFormat("FSMSystem(容错):该状态【{0}】已经被移除!", _state.GetState().ToString());
}
}


public IState GetState(string state)//获取相应状态
{
foreach (IState _state in mList) //遍历List里面所有状态取出相应的
{
if (_state.GetState() == state)
{
return _state;
}
}
return null;
}
/// <summary>
/// 状态机状态翻转
/// </summary>
/// <param name="state">指定状态机</param>
/// <returns>执行结果</returns>
public void ChangeState(string state)
{
IState _tmpState = GetState(state); //要改变的状态不存在
if (_tmpState == null)
{
Debug.LogWarningFormat("FSMSystem(容错):该状态【{0}】不存在于状态机中!", state);
}
if (CurrentState != null) //当前状态不为空
{
CurrentState.OnExit();
}
CurrentState = _tmpState; //缓存为当前状态
CurrentState.OnEnter(); //触发当前状态的OnEnter
}
public void Update()// 更新状态机状态
{
if (CurrentState != null)
{
CurrentState.OnUpdate();
}
}
public void RemoveAllState() //移除所有状态
{
if (CurrentState != null)
{
CurrentState.OnExit();
CurrentState = null;
}
mList.Clear();
}
}
//==========================
// - FileName: FSMSystem.cs
// - Created: true.
// - CreateTime: 2020/05/12 15:27:40
// - Region: China WUHAN
// - Description: 状态集
//==========================
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// FSMSystem class represents the Finite State Machine class.FSMSystem类表示有限状态机类。
/// It has a List with the States the NPC has and methods to add, 它句有一个状态列表,NPC有添加、删除状态和更改机器当前状态的方法。
/// delete a state, and to change the current state the Machine is on.
/// </summary>
public class FSMSystem
{
private List<BaseFSMState> states; //状态集

// The only way one can change the state of the FSM is by performing a transition 改变FSM状态的唯一方法是进行转换
// Don't change the CurrentState directly 不要直接改变当前状态
private EnumStateID currentStateID;
public EnumStateID CurrentStateID
{
get { return currentStateID; }
}
private BaseFSMState currentState;
public BaseFSMState CurrentState
{
get { return currentState; }
}


/// <summary>
/// 默认构造函数
/// </summary>
public FSMSystem()
{
states = new List<BaseFSMState>();
}


/// <summary>
/// 设置当前状态
/// </summary>
/// <param name="state">初始状态</param>
public void SetCurrentState(BaseFSMState state)
{
currentState = state;
currentStateID = state.ID;
state.DoBeforeEntering(); //开始前状态切换
}


/// <summary>
/// This method places new states inside the FSM, —— 这个方法在FSM内部放置一个放置一个新状态
/// or prints an ERROR message if the state was already inside the List. —— 或者,如果状态已经在列表中,则打印错误消息。
/// First state added is also the initial state. 第一个添加的状态也是初始状态。
/// </summary>
public void AddState(BaseFSMState fsmState, StateManager manager)
{
// Check for Null reference before deleting 删除前判空
if (fsmState == null)
{
Debug.LogError("FSM ERROR: Null reference is not allowed");
}
else // First State inserted is also the Initial state, —— 插入的第一个状态也是初始状态,// the state the machine is in when the simulation begins —— 状态机是在模拟开始时
{
fsmState.Manager = manager; //给每个状态添加总控 GameManager

if (states.Count == 0)
{
states.Add(fsmState);
return;
}


foreach (BaseFSMState state in states) // Add the state to the List if it's not inside it 如果状态不在列表中,则将其添加到列表中 (添加状态ID)
{
if (state.ID == fsmState.ID)
{
Debug.LogError("FSM错误:无法添加状态 " + fsmState.ID.ToString() +
"因为state已经被添加了");
return;
}
}

states.Add(fsmState);
}
}


/// <summary>
/// This method delete a state from the FSM List if it exists, —— 这个方法从FSM列表中删除一个存在的状态,
/// or prints an ERROR message if the state was not on the List. —— 或者,如果状态不存在,则打印错误信息
/// </summary>
public void DeleteState(EnumStateID id)
{
if (id == EnumStateID.NullStateId) // Check for NullState before deleting —— 判空
{
Debug.LogError("FSM ERROR: NullStateID is not allowed for a real state");
return;
}


foreach (BaseFSMState state in states) // Search the List and delete the state if it's inside it 搜索列表并删除其中的状态
{
if (state.ID == id)
{
states.Remove(state);
return;
}
}
Debug.LogError("FSM ERROR: Impossible to delete state " + id.ToString() +
". It was not on the list of states");
}


/// <summary>
/// This method tries to change the state the FSM is in based on
/// the current state and the transition passed. If current state
/// doesn't have a target state for the transition passed,
/// an ERROR message is printed.
/// 该方法尝试根据当前状态和已通过的转换改变FSM所处的状态。如果当前状态没有传递的转换的目标状态,则输出错误消息。
/// </summary>
public void PerformTransition(EnumTransition trans)
{
if (trans == EnumTransition.NullTransition) // Check for NullTransition before changing the current state 在更改当前状态之前检查是否有NullTransition
{
Debug.LogError("FSM ERROR: NullTransition is not allowed for a real transition");
return;
}


EnumStateID id = currentState.GetOutputState(trans); // Check if the currentState has the transition passed as argument 检查currentState是否将转换作为参数传递
if (id == EnumStateID.NullStateId)
{
Debug.LogError("FSM ERROR: State " + currentStateID.ToString() + " does not have a target state " +
" for transition " + trans.ToString());
return;
}


currentStateID = id; // Update the currentStateID and currentState 更新当前状态和ID
foreach (BaseFSMState state in states)
{
if (state.ID == currentStateID)
{
currentState.DoBeforeLeaving(); // Do the post processing of the state before setting the new one 在设置新状态之前是否对状态进行后处理
currentState = state;
currentState.DoBeforeEntering(); // Reset the state to its desired condition before it can reason or act 在它推动和动作之前,重置状态到它所需的条件
break;
}
}
}
}
//==========================
// - FileName: FSMSystem.cs
// - Created: true.
// - CreateTime: 2020/05/12 15:27:40
// - Region: China WUHAN
// - Description: MVC 逻辑控制层
//==========================
using UnityEngine;


public class StateManager : MonoBehaviour
{
private static StateManager _instance;
public static StateManager Instance
{
get
{
return _instance;
}
}


public FSMSystem Fsm; //有限状态机系统对象
public View View; // 显示层


private void Start()
{
_instance = this;

View = GameObject.FindGameObjectWithTag("View").GetComponent<View>(); //这里要给 View 游戏对象设置标签 "View"
//添加所有状态到状态集(这里,我也通过修改,将 GameManager传到所有状态中,简化代码,便于调用)
Fsm = new FSMSystem(); //调用构造函数,内部会自动初始化 状态集
BaseFSMState[] states = GetComponentsInChildren<BaseFSMState>(); //找到所有 状态
foreach (BaseFSMState state in states)
{
Fsm.AddState(state, this); //将状态,逐个添加到 状态机中
}

}
}
//==========================
// - FileName: View .cs
// - Created: true.
// - CreateTime: 2020/05/12 16:33:54
// - Region: China WUHAN
// - Description: MVC视图层

using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;


public class View : MonoBehaviour
{
private RectTransform Menu_Panel; //菜单页
private RectTransform Game_Panel; //游戏页
private RectTransform Hit_Panel; //提示页

public Button Btn_Develop; //加固发展
public Button Btn_Defense;//加固防御
public Button Btn_Tower;//修筑箭塔
public Button Btn_Return;//返回


public Button Btn_Yes;
public Button Btn_No;
public Text hit_Table;
public Ease PubEase;


/// <summary>
/// 初始化函数
/// </summary>
void Awake()
{
Menu_Panel = this.transform.Find("Menu_Panel").GetComponent<RectTransform>();
Game_Panel = this.transform.Find("Game_Panel").GetComponent<RectTransform>();
Hit_Panel = this.transform.Find("Hit_Panel").GetComponent<RectTransform>();



Btn_Develop = this.transform.Find("Menu_Panel").Find("Btn_Develop").GetComponent<Button>();
Btn_Defense = this.transform.Find("Menu_Panel").Find("Btn_Defense").GetComponent<Button>();
Btn_Tower = this.transform.Find("Menu_Panel").Find("Btn_Tower").GetComponent<Button>();
Btn_Return = this.transform.Find("Menu_Panel").Find("Btn_Return").GetComponent<Button>();


Btn_Yes = this.transform.Find("Hit_Panel").Find("Btn_Yes").GetComponent<Button>();
Btn_No = this.transform.Find("Hit_Panel").Find("Btn_No").GetComponent<Button>();
hit_Table = this.transform.Find("Hit_Panel").Find("Text_Hit").GetComponent<Text>();
//Menu_Panel = (RectTransform)Find("Menu Ui");
//Game_Panel = (RectTransform)Find("Game Ui");
//StartButton = Find("Menu Ui/Menu Button").GetComponent<Button>();
//PauseButton = Find("Game Ui/Pause Button").GetComponent<Button>();
}





/// <summary>
/// 显示菜单页
/// </summary>
public void ShowMenuUi()
{
Menu_Panel.DOScale(new Vector3(0.3f, 0.3f, 0.3f), 0.1f).OnComplete(() =>
{
Menu_Panel.DOScale(Vector3.one, 0.3f);
Btn_Develop.enabled = true;
Btn_Defense.enabled = true;
Btn_Tower.enabled = true;
Btn_Return.enabled = true;
}).SetEase(PubEase);
Menu_Panel.DOAnchorPos(Vector2.zero, 0.3f).SetEase(PubEase);
}

/// <summary>
/// 隐藏菜单页
/// </summary>
public void HideMenuUi()
{
Menu_Panel.DOScale(new Vector3(0.3f, 0.3f, 0.3f), 0.1f).OnComplete(() =>
{
Menu_Panel.DOAnchorPos(new Vector2(832, 832), 0.3f);
Menu_Panel.DOScale(Vector3.zero, 0.3f).OnComplete(() =>
{
Btn_Develop.enabled = false;
Btn_Defense.enabled = false;
Btn_Tower.enabled = false;
Btn_Return.enabled = false;

}).SetEase(PubEase);
}).SetEase(PubEase);
}


/// <summary>
/// 进入提示页
/// </summary>
public void ShowGameUi()
{
Hit_Panel.DOScale(new Vector3(0.3f, 0.3f, 0.3f), 0.1f).OnComplete(() =>
{
Hit_Panel.DOScale(Vector3.one, 0.3f);
Btn_Yes.enabled = true;
Btn_No.enabled = true;
}).SetEase(PubEase);
Hit_Panel.DOAnchorPos(Vector2.zero, 0.3f).SetEase(PubEase);
}


/// <summary>
/// 隐藏提示页
/// </summary>
public void HideGameUi()
{
Hit_Panel.DOScale(new Vector3(0.3f, 0.3f, 0.3f), 0.1f).OnComplete(() =>
{
Hit_Panel.DOAnchorPos(new Vector2(832, 832), 0.3f);
Hit_Panel.DOScale(Vector3.zero, 0.3f).OnComplete(() =>
{
Btn_Yes.enabled = false;
Btn_No.enabled = false;
}).SetEase(PubEase);
}).SetEase(PubEase);
}


/// <summary>
/// 查找对Ui元素完成赋值
/// </summary>
/// <param name="uiElement">Ui名查找路径</param>
Transform Find(string uiElement)
{
return transform.Find("Canvas/" + uiElement);
}
}
//==========================
// - FileName: EnumStateID.cs
// - Created: true.
// - CreateTime: 2020/05/12 15:11:43
// - Region: China WUHAN
// - Description:
//==========================
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Place the labels for the States in this enum. —— 在此枚举中放置状态的标签。
/// Don't change the first label, NullStateID as FSMSystem class uses it.不要改变第一个标签:NullStateID,因为FSMSystem类使用它。
/// </summary>
public enum EnumStateID
{
NullStateId = 0, // Use this ID to represent a non-existing State in your system —— 使用此ID表示系统中不存在的状态
Menu, //菜单
Hit, //提示
Game //游戏
}
//==========================
// - FileName: Transition.cs
// - Created: true.
// - CreateTime: 2020/05/12 15:06:18
// - Region: China WUHAN
// - Description:
//==========================
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Place the labels for the Transitions in this enum. —— 在此枚举中放置转换的标签。
/// Don't change the first label, NullTransition as FSMSystem class uses it. —— 不要改变第一个标签:NullTransition,因为FSMSystem类使用它。
/// </summary>
public enum EnumTransition
{
NullTransition = 0, // Use this transition to represent a non-existing transition in your system —— 使用此转换表示系统中不存在的转换
Game, //转到游戏
Hit, //提示
Menu //转到菜单

}
//==========================
// - FileName: GameState .cs
// - Created: true.
// - CreateTime: 2020/05/12 15:06:18
// - Region: China WUHAN
// - Description: 游戏状态
//==========================
using UnityEngine;
public class GameState : BaseFSMState
{
void Start()
{
//stateID = EnumStateID.Game;
//AddTransition(EnumTransition.Menu, EnumStateID.Menu); //(游戏状态下:点击暂停需要转菜单)→→添加转换,转换菜单—— 对应菜单状态
//map.Add(Transition.Menu, StateID.Menu);//上边也可这么写
}


/// <summary>
/// 暂停
/// </summary>
public void OnPauseButton()
{
Debug.Log(2);
//manager.Fsm.PerformTransition(EnumTransition.Menu);
}


/// <summary>
/// 进入该状态时
/// </summary>
public override void DoBeforeEntering()
{
manager.View.ShowGameUi();
}


/// <summary>
/// 离开该状态时
/// </summary>
public override void DoBeforeLeaving()
{
manager.View.HideGameUi();
}
}
//==========================
// - FileName: MenuState .cs
// - Created: true.
// - CreateTime: 2020/05/12 15:06:18
// - Region: China WUHAN
// - Description: 游戏状态
//==========================
using UnityEngine;
/// <summary>
/// 菜单状态
/// </summary>
public class MenuState : BaseFSMState
{

private void Awake()
{
stateID = EnumStateID.Menu;
AddTransition(EnumTransition.Hit, EnumStateID.Hit); //(菜单状态下:需要转游戏)→→添加转换,转换游戏 —— 对应游戏状态
//map.Add(Transition.Game, StateID.Game);//上边也可这么写
}

void Start()
{

//manager.View.StartButton.onClick.AddListener(OnStarGameClick);
InitEvent();
}

private void InitEvent()
{
manager.View.Btn_Develop.onClick.AddListener(() =>
{
manager.View.HideMenuUi();
manager.View.ShowGameUi();

});
manager.View.Btn_Return.onClick.AddListener(() =>
{
manager.View.HideMenuUi();

});
}


/// <summary>
/// 开始游戏
/// </summary>
public void OnStarGameClick()
{
manager.Fsm.PerformTransition(EnumTransition.Hit);
}


/// <summary>
/// 进入该状态时
/// </summary>
public override void DoBeforeEntering()
{
Debug.Log("进入状态");
manager.View.ShowMenuUi();
}


/// <summary>
/// 离开该状态时
/// </summary>
public override void DoBeforeLeaving()
{
Debug.Log("离开状态");
manager.View.HideMenuUi();
}
}
//==========================
// - FileName: HitState.cs
// - Created: true.
// - CreateTime: 2020/05/12 22:59:50
// - Region: China WUHAN
// - Description: 游戏状态
//==========================
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class HitState : BaseFSMState
{
private Coroutine hideText;
private void Awake()
{
stateID = EnumStateID.Hit;
AddTransition(EnumTransition.Menu, EnumStateID.Menu); //(游戏状态下:点击暂停需要转菜单)→→添加转换,转换菜单—— 对应菜单状态

}

void Start()
{
InitEvent();
}

private void InitEvent()
{
manager.View.Btn_Yes.onClick.AddListener(() =>
{
manager.View.Btn_No.interactable = false;
manager.View.hit_Table.text = "你赢了,你个畜生";
hideText = StartCoroutine(Hide(3f));

});
manager.View.Btn_No.onClick.AddListener(() =>
{
hideText = StartCoroutine(Hide(0f));
});
}

IEnumerator Hide(float time)
{
yield return new WaitForSeconds(time);
manager.View.HideGameUi();
manager.View.hit_Table.text = "要花很多钱?";
manager.View.Btn_No.interactable = true;
StopAllCoroutines();
}

/// <summary>
/// 暂停
/// </summary>
public void OnPauseButton()
{
Debug.Log(3);
manager.Fsm.PerformTransition(EnumTransition.Menu);
}


/// <summary>
/// 进入该状态时
/// </summary>
public override void DoBeforeEntering()
{
//manager.View.ShowGameUi();
}


/// <summary>
/// 离开该状态时
/// </summary>
public override void DoBeforeLeaving()
{
Debug.Log("离开信息提示面板");
//manager.View.HideGameUi();
}
}

由于作者比较懒,MVC 中的数据层就不写了,仅为学习记录

最后就是我Unity试图 布局了:

StateMgr(FSM)_sed_02


上一波运行结果图把:

StateMgr(FSM)_sed_03


StateMgr(FSM)_sed_04


StateMgr(FSM)_List_05