状态模式包括以下几种角色:
Context(状态持有类): 它定义了客户程序需要的接口并维护一个具体状态角色的实例,将与状态相关的操作委托给当前的Concrete State对象来处理。
State(抽象状态类): 定义一个接口以封装使用上下文环境的的一个特定状态相关的行为。
ConcreteState(具体状态类): 实现抽象状态定义的接口。
状态模式的原型
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StateModePrototype : MonoBehaviour
{
void Start()
{
Context context = new Context();
context.SetState(new StateA(context));
context.Execute(-1);
context.Execute(1);
context.Execute(-2);
}
}
/// <summary>
/// 状态持有者
/// </summary>
public class Context
{
private Istate state;
public void SetState(Istate _state)
{
this.state = _state;
}
public void Execute(int arg)
{
state.Execute(arg);
}
}
/// <summary>
/// 状态接口
/// </summary>
public interface Istate
{
void Execute(int arg);//这个参数需要根据实际确认
}
public class StateA : Istate
{
private Context context;
public StateA(Context _context)
{
context = _context;
}
public void Execute(int arg)
{
if (arg<=0)
{
context.SetState(new StateB(context));
Debug.Log("A->B");
}
}
}
public class StateB : Istate
{
private Context context;
public StateB(Context _context)
{
context = _context;
}
public void Execute(int arg)
{
if (arg>0)
{
context.SetState(new StateA(context));
Debug.Log("B->A");
}
}
}
一个简单状态模式的demo
demo:利用状态模式实现场景的跳转管理
state: StartScene(开始场景),MainScene(主场景),BatterScene(战斗场景)
枚举类
public enum SceneName
{
StartScene,
MainScene,
BatterScene,
}
状态父类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ISceneState
{
protected SceneController sceneController;//状态所属的管理者
private string sceneName = string.Empty;//跳转场景的名字
public string SceneName { get => sceneName; }
public ISceneState(SceneController _sceneController,SceneName _sceneName)
{
sceneController = _sceneController;
sceneName = _sceneName.ToString();
}
public virtual void SceneEnter() { }//进入场景时执行的方法 执行一次
public virtual void SceneStay() { }//在场景中会一直执行 每一帧都会执行
public virtual void SceneExit() { }//退出当前场景时执行 执行一次
}
具体的开始游戏的场景(一波播放开始的加载动画界面)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StartScene : ISceneState
{
private float nextTime = 2;
private float waitTimer=0;
public StartScene(SceneController _sceneController) : base(_sceneController, global::SceneName.StartScene)
{
}
public override void SceneEnter()
{
base.SceneEnter();
Debug.Log("进入StartScene");
}
public override void SceneStay()
{
base.SceneStay();
Debug.Log("处于StartScene");
//2s后进入MainScene
waitTimer += Time.deltaTime;
if (waitTimer>=nextTime)
{
sceneController.SetSceneState(new MainScene(sceneController), true);
}
}
public override void SceneExit()
{
base.SceneExit();
Debug.Log("退出StartScene");
}
}
具体的主场景类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MainScene : ISceneState
{
private Button enterBatterBut;
public MainScene(SceneController _sceneController) : base(_sceneController, global::SceneName.MainScene)
{
}
public override void SceneEnter()
{
base.SceneEnter();
Debug.Log("进入MainScene");
enterBatterBut = GameObject.Find("EnterBatterButton").GetComponent<Button>();
enterBatterBut.onClick.AddListener(OnClickEnterBatterBut) ;
}
public override void SceneStay()
{
base.SceneStay();
Debug.Log("处于MainScene");
}
public override void SceneExit()
{
base.SceneExit();
Debug.Log("退出MainScene");
}
private void OnClickEnterBatterBut()
{
sceneController.SetSceneState(new BatterScene(sceneController), true);
}
}
具体战斗场景类
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class BatterScene : ISceneState
{
public BatterScene(SceneController _sceneController) : base(_sceneController, global::SceneName.BatterScene)
{
}
public override void SceneEnter()
{
base.SceneEnter();
Debug.Log("进入BatterScene");
}
public override void SceneStay()
{
base.SceneStay();
Debug.Log("处于BatterScene");
}
public override void SceneExit()
{
base.SceneExit();
Debug.Log("退出BatterScene");
}
}
状态的持有(控制)类Context
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneController
{
private ISceneState sceneState;
private AsyncOperation ao;
private bool isFirstEnterScene=true;
public void SetSceneState(ISceneState _sceneState,bool isLoadScene)
{
if (sceneState!=null)
{
sceneState.SceneExit();//执行上一个状态的退出时函数
}
sceneState = _sceneState;
if (isLoadScene)
{
ao = SceneManager.LoadSceneAsync(sceneState.SceneName);
isFirstEnterScene = true;
}
else
{
sceneState.SceneEnter();//刚加入场景时执行进入场景的方法
isFirstEnterScene = false;
}
}
public void SceneStateUpdate()
{//isFirstEnterScene 防止进入场景后 一直调用enter中的方法
if (isFirstEnterScene &&ao != null&&ao.isDone)
{
sceneState.SceneEnter();//刚加入场景时执行进入场景的方法
isFirstEnterScene = false;
}
if (sceneState!=null)
{
sceneState.SceneStay();//在状态中 每一帧都执行SceneStay
}
}
}
调用类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameLoop : MonoBehaviour
{
private SceneController sceneController;
private void Awake()
{
DontDestroyOnLoad(gameObject);
}
void Start()
{
sceneController = new SceneController();
sceneController.SetSceneState(new StartScene(sceneController),false);
}
// Update is called once per frame
void Update()
{
if (sceneController!=null)
{
sceneController.SceneStateUpdate();
}
}
}
效果演示