再谈Unity控制逻辑一个轻量级的状态机

 

关于状态机这种设计模式不用多介绍了,特别是FSM。不了解的童鞋,请参考下面文章
Unity3d架构系列之-FSM有限状态机设计一
Unity3d架构系列之- FSM有限状态机设计二
Unity3d架构系列之- FSM有限状态机设计三
Unity3d架构系列之- FSM有限状态机设计四(总结篇)
现在是我实现一个轻量级的状态机,不废话了上代码先


using System;
using System.Collections.Generic;

namespace Gamelogic
{
/**
一个轻量级的状态机。
要使用它:
-# 定义您自己的label。枚举Enums可能是最好的选择。
-# 构造一个新的状态机state machin,通常是在 MonoBehaviour 的Start方法中。
-# 添加的各种状态和对应的delegates。
-# 从 MonoBehaviour 的Update方法调用状态机Update方法。
-# 在状态机transition转换状态时调用 ChangeState 方法(你可以调用此方法,从一个state delegates,或任何其他地方)
-# 状态发生变化时,对现有状态执行关闭 OnStop,然后OnStart开启新状态,之后新的状态每帧更新中调用 OnUpdate 方法
*/
public sealed class StateMachine<TLabel>
{
private class State
{
public readonly Action onStart;
public readonly Action onUpdate;
public readonly Action onStop;
public readonly TLabel label;

public State(TLabel label, Action onStart, Action onUpdate, Action onStop)
{
this.onStart = onStart;
this.onUpdate = onUpdate;
this.onStop = onStop;
this.label = label;
}
}

private readonly Dictionary<TLabel, State> stateDictionary;
private State currentState;

/**
Returns the label of the current state.
*/

public TLabel CurrentState
{
get { return currentState.label; }

/**@version1_2*/
set { ChangeState(value); }
}

/**
Constructs a new StateMachine.
*/

public StateMachine()
{
stateDictionary = new Dictionary<TLabel, State>();
}

/**
Adds a state, and the delegates that should run
when the state starts, stops,
and when the state machine is updated.

Any delegate can be null, and wont be executed.
*/
public void AddState(TLabel label, Action onStart, Action onUpdate, Action onStop)
{
stateDictionary[label] = new State(label, onStart, onUpdate, onStop);
}

/**
Changes the state from the existing one to the state with the given label.
*/
private void ChangeState(TLabel newState)
{
if (currentState != null && currentState.onStop != null)
{
currentState.onStop();
}

currentState = stateDictionary[newState];

if (currentState.onStart != null)
{
currentState.onStart();
}
}

/**
This method should be called every frame.
*/
public void Update()
{
if (currentState != null && currentState.onUpdate != null)
{
currentState.onUpdate();
}
}
}
}

下面是客户端调用代码


using System.Collections;
using UnityEngine;

namespace Gamelogic.Examples
{
public class Cube : MonoBehaviour
{

public enum CubeStates
{
Swivel,
MoveStraight
}

private StateMachine<CubeStates> stateMachine;
private float moveSpeed = 1;
private float switchTime = 3;
private float swivelSpeed = 2;

public void Start()
{
stateMachine = new StateMachine<CubeStates>();

stateMachine.AddState(CubeStates.Swivel, OnSwivelStart, OnSwivelUpdate, OnSwivelStop);
stateMachine.AddState(CubeStates.MoveStraight, null, OnMoveStraightUpdate, null);

stateMachine.CurrentState = CubeStates.MoveStraight;

StartCoroutine(SwitchStates());
}

public IEnumerator SwitchStates()
{
while (true)
{
stateMachine.CurrentState = CubeStates.Swivel;
yield return new WaitForSeconds(switchTime);

stateMachine.CurrentState = CubeStates.MoveStraight;
yield return new WaitForSeconds(switchTime);
}
}

public void Update()
{
stateMachine.Update();
}

public void OnGUI()
{
GUILayout.TextField(stateMachine.CurrentState.ToString());
}

public void OnMoveStraightUpdate()
{
float dx = -Time.deltaTime * moveSpeed;

transform.TranslateX(dx);
}

public void OnSwivelUpdate()
{
float dx = Time.deltaTime*moveSpeed;
float y = Mathf.Sin(swivelSpeed * transform.position.x * 2 * Mathf.PI/switchTime);

transform.TranslateX(dx);
transform.SetY(y);
}

public void OnSwivelStart()
{
GetComponent<Renderer>().material.color = Color.red;
}

public void OnSwivelStop()
{
GetComponent<Renderer>().material.color = Color.green;
transform.SetY(0); //recallibrate
}
}
}

使用的例子 很简单,cube的两种状态转换。 每种状态有不同的行为表现:

     

就是这样的很简单的状态机,欢迎围观