出处:http://blog.youkuaiyun.com/u010019717
author:孙广东 时间:2015.3.25
关于状态机这种设计模式不用多介绍了,网上有很多这方面的介绍,特别是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();
- }
- }
- }
- }
使用的例子 很简单,cube的两种状态转换。 每种状态有不同的行为表现:
- 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
- }
- }
- }
就是这样的很简单的状态机。