StateMgr(FSM)

基于FSM 有限状态机

最近在做一款大型的商业项目,多个面板之间的切换以及 显示隐藏,很明显,这里如果说使用 禁用或者激活游戏物体的方法是不可行的,因为你无法保证一定是有多少种面板,另外一个就是你也不发保证每次要打开的是谁?隐藏的是谁?也许有同学会说到使用对象池技术,用的时候取,不用的时候回收自身, 这样的话乍一听虽然没问题,但是真正做的时候会很烧脑。下面将一个一个的进行列举:
首先比如说 场景中 n 个对象,那么我们第一次打开的时候 肯定就是 n+0,第二次打开的按照正常逻辑肯定就是n+1个面板了,以此类推,那么这个时候比如说我们的玩家比较调皮。第一次打开的为 n+0,第二次打开的面板为 n+5,那么你是该显示那个面板呢?也有比较倔强的朋友,我写判断啊,OK,即使你写判断,你算算多少 if else 或者他说 switch,OK,那么你依然可以想想有多少枚举?
so,这里我们引入了 FSM 有限状态机,它的原理是神马样子的呢?
在这里插入图片描述
假如说上面的 正方形是我们游戏中不同的面板,那么这里我们从当前的状态可以改变到任一状态,只需要中间牵出一条线即可,不会影响我们整个面板 UI 的业务,相当于我们永远持有一个当前状态,我们默认让它的状态为 null,也就是玩家没有作任何的操作的时候,然后还有一个状态集。那么当我们用户进行一些点击操作以后,我们就可以从状态集中找到要变换的状态,也就是面板,这样从而就可以进行随意的切换。或许有同学又有疑惑了,那么你怎么隐藏呢? 这里有一个插件 DwTween,动画插件,我们每次显示的时候 直接控制它的 Scale 大小为1,当隐藏的时候直接控制 为 0,是不是感觉比较巧妙,这样我们每次连初始化的操作都能省去。
OK,不废话,上代码咯;

//==========================
// - FileName:      IState.cs         
// - Created:       true.	
// - CreateTime:    2020/05/13 00:08:51
// - Email:         1670328571@qq.com
// - 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
// - Email:         1670328571@qq.com
// - 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	
// - Email:         1670328571@qq.com		
// - 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	
// - Email:         1670328571@qq.com		
// - 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	
// - Email:         1670328571@qq.com		
// - 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	
// - Email:         1670328571@qq.com		
// - 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	
// - Email:         1670328571@qq.com		
// - 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	
// - Email:         1670328571@qq.com		
// - 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	
// - Email:         1670328571@qq.com		
// - 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	
// - Email:         1670328571@qq.com		
// - 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	
// - Email:         1670328571@qq.com		
// - 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试图 布局了:

在这里插入图片描述
上一波运行结果图把:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值