1. 程式人生 > >設計模式篇:狀態模式(二)

設計模式篇:狀態模式(二)

完整工程:https://gitee.com/NKG/DesignPatterns/blob/master/DesignPatterns.unitypackage

首先在Unity下面建立如下檔案

首先是場景都要繼承的

ISceneState

其中包括了場景的生命週期函式,場景名稱,場景控制器的引用。

using System.Collections;
using System.Collections.Generic;
using Scenes.Scripts.StatePattern.RealSample;
using UnityEngine;

public class ISceneState
{
    private string m_StateName = "ISceneState";

    public string StateName
    {
        get { return m_StateName; }
        set { m_StateName = value; }
    }

    protected SceneStateController m_Controller = null;

    public ISceneState(SceneStateController Controller)
    {
        m_Controller = Controller;
    }

    /// <summary>
    /// 進入場景時呼叫的函式
    /// </summary>
    public virtual void StateBegin()
    {
    }

    /// <summary>
    /// 場景結束時呼叫的函式
    /// </summary>
    public virtual void StateEnd()
    {
    }

    /// <summary>
    /// 場景更新
    /// </summary>
    public virtual void StateUpdate()
    {
    }
}

 

場景控制器

using UnityEngine;
using UnityEngine.SceneManagement;


    public class SceneStateController
    {
        private ISceneState m_State;
        private bool m_bRunBegin = false;
        private AsyncOperation _asyncOperation;
        public SceneStateController(){}

        public void SetState(ISceneState state, string LoadSceneName)
        {
            m_bRunBegin = false;
            LoadScene(LoadSceneName);

            if (m_State != null)
            {
                m_State.StateEnd();
            }

            m_State = state;
        }
        
        

        private void LoadScene(string loadSceneName)
        {
            if (string.IsNullOrEmpty(loadSceneName))
            {
                return;
            }
            _asyncOperation = SceneManager.LoadSceneAsync(loadSceneName);
        }

        public void StateUpdate()
        {
            //如果上一個場景還沒有載入完,那就讓他繼續載入
            if (_asyncOperation!=null)
            {
                if(!_asyncOperation.isDone)
                    return;
            }
            if (m_State != null && m_bRunBegin == false)
            {
                m_State.StateBegin();
                m_bRunBegin = true;
            }

            if (m_State != null)
            {
                m_State.StateUpdate();
            }
        }
    }

遊戲入口

using System;
using System.Collections;
using System.Collections.Generic;
using Scenes.Scripts.StatePattern.RealSample;
using UnityEngine;

public class GameEntry : MonoBehaviour {

	SceneStateController m_SceneStateController=new SceneStateController();

	private void Awake()
	{
		GameObject.DontDestroyOnLoad(this.gameObject);
	}

	// Use this for initialization
	private void Start () {
		//設定起始場景
		m_SceneStateController.SetState(new StartState(m_SceneStateController),"StartState");
	}
	
	// Update is called once per frame
	//更新狀態
	void Update () {
		m_SceneStateController.StateUpdate();
	}
}

開始場景

using UnityEngine;

    public class StartState : ISceneState
    {
        public StartState(SceneStateController Controller) : base(Controller)
        {
            this.StateName = "StartState";
        }

        public override void StateBegin()
        {
            Debug.Log("進入開始場景");
        }


        /// <summary>
        /// 更換場景
        /// </summary>
        public override void StateUpdate()
        {
            //按下滑鼠左鍵來切換場景
            if (Input.GetMouseButtonDown(0))
            {
                m_Controller.SetState(new MainMenuState(m_Controller), "MainMenuState");
            }

        }
    }

選單場景中我們需要一個按鈕來進入戰鬥,開啟選單場景,新建Button

using UnityEngine;
using UnityEngine.UI;

    public class MainMenuState : ISceneState
    {
        /// <summary>
        /// 獲取改變場景按鈕的引用
        /// </summary>
        public Button ChangeState;

        public MainMenuState(SceneStateController Controller) : base(Controller)
        {
            this.StateName = "MainMenuState";
        }

        public override void StateBegin()
        {
            ChangeState = GameObject.Find("Button").GetComponent<Button>();
            ChangeState.onClick.AddListener(ToChangestate);
            Debug.Log("進入選單場景");
        }

        private void ToChangestate()
        {
            Debug.Log("開始戰鬥的按鈕被點選,正在切換到戰鬥場景");
            m_Controller.SetState(new BattleState(m_Controller), "BattleState");
        }
    }

戰鬥場景

using UnityEngine;

    public class BattleState:ISceneState
    {
        public BattleState(SceneStateController Controller) : base(Controller)
        {
            this.StateName = "BattleState";
        }

        public override void StateBegin()
        {
            Debug.Log("進入戰鬥場景");
        }

        public override void StateEnd()
        {
            Debug.Log("戰鬥結束,回到選單場景");
        }

        public override void StateUpdate()
        {
            if (Input.GetMouseButtonDown(0))
            {
                m_Controller.SetState(new MainMenuState(m_Controller),"MainMenuState");
            }
        }
    }

回到Unity,在GameEntry裡建立一個空的GameObject,將GameEntry指令碼掛載上去。

把這幾個場景Build

點選執行