原文来自:https://github.com/TYJia/GameDesignPattern_U3D_Version
- SwitchCase版本,用按键控制一盏冷暖灯,关灯状态下,按一次打开暖光,再按切换为白光,再按变为暖白光,再按关闭
- 状态类版本,交通灯 停止、通行、闪烁、等待的切换
基本思想:
现在状态和条件决定对象的新状态,状态决定行为(Unity内AnimationController就是状态机)
为什么要使用它:
- 使流程清晰化、结构化
- 简化判断逻辑,比如嘴的状态是洗牙,那就不应该做出咀嚼的行为;必须是在憋气,那就不应该做出呼吸的行为
缺点:
当状态量较大时,代码量激增,可读性也很差,状态变化和状态行为都需要大量的信息传递,十分不便
代码示例:
LightStateClass.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LightStateClass : MonoBehaviour
{
public GameObject GreenLightObj;
public GameObject YellowLightObj;
public GameObject RedLightObj;
private Material GreenLight;
private Material YellowLight;
private Material RedLight;
private TrafficState TrafficLight;
void Start()
{
GreenLight = GreenLightObj.GetComponent<Renderer>().material;
YellowLight = YellowLightObj.GetComponent<Renderer>().material;
RedLight = RedLightObj.GetComponent<Renderer>().material;
SetState(new Pass());
}
void Update()
{
TrafficLight.ContinousStateBehaviour(this, GreenLight, YellowLight, RedLight);
}
public void SetState(TrafficState state)
{
TrafficLight = state;
TrafficLight.StateStart(GreenLight, YellowLight, RedLight);
}
}
public abstract class TrafficState
{
public float Duration;
public float Timer;
public virtual void StateStart(Material GreenLight, Material YellowLight, Material RedLight)
{
Timer = Time.time;
}
public abstract void ContinousStateBehaviour(LightStateClass mLSC, Material GreenLight, Material YellowLight, Material RedLight);
}
public class Pass : TrafficState
{
public Pass()
{
Duration = 2;
}
public override void StateStart(Material GreenLight, Material YellowLight, Material RedLight)
{
base.StateStart(GreenLight, YellowLight, RedLight);
GreenLight.SetColor("_EmissionColor", Color.green);
YellowLight.SetColor("_EmissionColor", Color.black);
RedLight.SetColor("_EmissionColor", Color.black);
}
public override void ContinousStateBehaviour(LightStateClass mLSC, Material GreenLight, Material YellowLight, Material RedLight)
{
if (Time.time > Timer + Duration)
{
mLSC.SetState(new PassBlink());
}
}
}
public class PassBlink : TrafficState
{
private bool On = true;
private float BlinkTimer = 0;
public PassBlink()
{
Duration = 1;
}
public override void StateStart(Material GreenLight, Material YellowLight, Material RedLight)
{
base.StateStart(GreenLight, YellowLight, RedLight);
}
private static void SwitchGreen(Material GreenLight, bool open)
{
Color color = open ? Color.green : Color.black;
GreenLight.SetColor("_EmissionColor", color);
}
public override void ContinousStateBehaviour(LightStateClass mLSC, Material GreenLight, Material YellowLight, Material RedLight)
{
if (Time.time > Timer + Duration)
{
mLSC.SetState(new Wait());
}
if (Time.time > BlinkTimer + 0.2f)
{
On = !On;
BlinkTimer = Time.time;
SwitchGreen(GreenLight,On);
}
}
}
public class Wait : TrafficState
{
public Wait()
{
Duration = 1;
}
public override void StateStart(Material GreenLight, Material YellowLight, Material RedLight)
{
base.StateStart(GreenLight, YellowLight, RedLight);
GreenLight.SetColor("_EmissionColor", Color.black);
YellowLight.SetColor("_EmissionColor", Color.yellow);
RedLight.SetColor("_EmissionColor", Color.black);
}
public override void ContinousStateBehaviour(LightStateClass mLSC, Material GreenLight, Material YellowLight, Material RedLight)
{
if (Time.time > Timer + Duration)
{
mLSC.SetState(new Stop());
}
}
}
public class Stop : TrafficState
{
public Stop()
{
Duration = 1;
}
public override void StateStart(Material GreenLight, Material YellowLight, Material RedLight)
{
base.StateStart(GreenLight, YellowLight, RedLight);
GreenLight.SetColor("_EmissionColor", Color.black);
YellowLight.SetColor("_EmissionColor", Color.black);
RedLight.SetColor("_EmissionColor", Color.red);
}
public override void ContinousStateBehaviour(LightStateClass mLSC, Material GreenLight, Material YellowLight, Material RedLight)
{
if (Time.time > Timer + Duration)
{
mLSC.SetState(new Pass());
}
}
}
LightSwitchCase.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LightSwitchCase : MonoBehaviour {
public LightState CurrentState = LightState.Off;
private Light mLight;
private Material mMat;
public enum LightState
{
Off,
Warm,
White,
WarmWhite
}
private void Awake()
{
mLight = GetComponent<Light>();
mMat = GetComponentInChildren<Renderer>().material;
}
public void OnChangeState()
{
//状态转换
switch (CurrentState)
{
case LightState.Off:
CurrentState = LightState.Warm;
break;
case LightState.Warm:
CurrentState = LightState.White;
break;
case LightState.White:
CurrentState = LightState.WarmWhite;
break;
case LightState.WarmWhite:
CurrentState = LightState.Off;
break;
default:
CurrentState = LightState.Off;
break;
}
//状态行为
switch (CurrentState)
{
case LightState.Off:
mLight.color = Color.black;
mMat.SetColor("_EmissionColor", mLight.color);
break;
case LightState.Warm:
mLight.color = new Color(0.8f, 0.5f, 0);
mMat.SetColor("_EmissionColor", mLight.color);
break;
case LightState.White:
mLight.color = new Color(0.8f, 0.8f, 0.8f);
mMat.SetColor("_EmissionColor", mLight.color);
break;
case LightState.WarmWhite:
mLight.color = new Color(1, 0.85f, 0.6f);
mMat.SetColor("_EmissionColor", mLight.color);
break;
default:
mLight.color = Color.black;
mMat.SetColor("_EmissionColor", mLight.color);
break;
}
}
}