纳金网

标题: 自定义状态机的实现 [打印本页]

作者: 王者再临    时间: 2015-10-13 07:24
标题: 自定义状态机的实现
        关于状态机,我想都知道它很常用,就像单例一样,我们基本上每个项目都会用到它。网上也有很多大神写的状态机,比如 PlayMaker 这样重量级的插件,功能很强大,依赖也很多。不过,程序猿的胃口有时候就是很挑剔,吃惯了大鱼大肉的东西,总想吃点清粥小菜。应该有很多朋友跟我一样,希望有一套轻量级的状态机实现,每行代码自己都了如指掌,实现我们一些简单的状态控制的需求。In hand(伸手就来的方便),你也有这种共鸣么?

        下面是我的实现,有不足或者 low的地方,希望告诉我,一起进步吧!

状态机类:
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;

  4. namespace PLY.StateMachine {
  5.         /// <summary>
  6.         /// 有限状态机基类.
  7.         /// </summary>
  8.         [System.Serializable]
  9.         public class FiniteStateMachine : MonoBehaviour {
  10.                 private object Context_;
  11.                 public string CurrentStateName = "EmptyState";

  12.                 private FiniteState CurrentState_;
  13.                 protected FiniteState CurrentState{
  14.                         get{
  15.                                 return CurrentState_;
  16.                         }
  17.                         set{
  18.                                 CurrentState_ = value;
  19.                                 CurrentStateName = CurrentState_.Name;
  20.                         }
  21.                 }

  22.                 protected FiniteState defaultState;

  23.                 private Dictionary<string, FiniteState> allStates_ = new Dictionary<string, FiniteState>();
  24.                 private List<FiniteStateTransition> allTransitions_ = new List<FiniteStateTransition>();

  25.                 protected virtual void Init(){}

  26.                 protected void AddState(FiniteState state){
  27.                         allStates_.Add(state.Name, state);
  28.                 }

  29.                 protected void RemoveState(FiniteState state){
  30.                         allStates_.Remove(state.Name);
  31.                 }

  32.                 /// <summary>
  33.                 /// 添加过渡.
  34.                 /// </summary>
  35.                 /// <param name="eventName">Event name.</param>
  36.                 /// <typeparam name="T1">源状态类型.</typeparam>
  37.                 /// <typeparam name="T2">目标状态类型.</typeparam>
  38.                 protected void AddTransition<T1,T2>(string eventName){
  39.                         string lastStateName = typeof(T1).Name;
  40.                         string nextStateName = typeof(T2).Name;
  41.                         FiniteStateTransition transition = new FiniteStateTransition(eventName, lastStateName, nextStateName );
  42.                         allTransitions_.Add(transition);
  43.                 }

  44.                 protected void AddTransition(FiniteStateTransition transition){
  45.                         allTransitions_.Add(transition);
  46.                 }

  47.                 protected void RemoveTransation(FiniteStateTransition transition){
  48.                         allTransitions_.Remove(transition);
  49.                 }
  50.                
  51.                 public void SetContext(object context){
  52.                         Context_ = context;
  53.                 }

  54.                 /// <summary>
  55.                 /// 发送事件,触发下一状态的切换
  56.                 /// </summary>
  57.                 /// <param name="eventName">事件名.</param>
  58.                 public void SendEvent(string eventName){
  59.                         for (int i = 0; i < allTransitions_.Count; i++) {
  60.                                 FiniteState nextState;
  61.                                 if (TryGetNextStateByEventName(allTransitions_[i], eventName, out nextState)){
  62.                                         ChangeState(nextState);
  63.                                         break;
  64.                                 }
  65.                         }
  66.                 }

  67.                 private bool TryGetNextStateByEventName(FiniteStateTransition transation, string eventName, out FiniteState state){
  68.                         state = null;
  69.                         if (CurrentState == null || !CurrentState.Name.Equals(transation.LastStateName)) return false;
  70.                         if (!eventName.Equals(transation.EventName)) return false;
  71.                         return (allStates_.TryGetValue(transation.NextStateName, out state));
  72.                 }

  73.                 /// <summary>
  74.                 /// 切换状态.
  75.                 /// </summary>
  76.                 /// <param name="newState">New state.</param>
  77.                 private void ChangeState(FiniteState newState){
  78.                         if (CurrentState != null){
  79.                                 CurrentState.OnExit(Context_);
  80.                         }
  81.                         else{
  82.                                 Debug.LogError("当前状态为空,退出状态失败!", gameObject);
  83.                         }

  84.                         CurrentState = newState;

  85.                         if(CurrentState != null){
  86.                                 CurrentState.OnEnter(Context_);
  87.                         }
  88.                         else{
  89.                                 Debug.LogError("当前状态为空,进入状态失败!", gameObject);
  90.                         }
  91.                 }

  92.                 private void SetDefaultToCurrent(){
  93.                         CurrentState = defaultState;
  94.                 }

  95.                 private void Awake(){
  96.                         Init();
  97.                         SetDefaultToCurrent();
  98.                 }

  99.                 private void Start () {
  100.                         if (CurrentState != null){
  101.                                 CurrentState.OnEnter(Context_);
  102.                         }               
  103.                 }

  104.                 private void Update () {
  105.                         if (CurrentState != null){
  106.                                 CurrentState.OnUpdate(Context_);
  107.                         }
  108.                 }

  109.                 private void FixedUpdate(){
  110.                         if (CurrentState != null){
  111.                                 CurrentState.OnFixedUpdate(Context_);
  112.                         }
  113.                 }

  114.                 private void LateUpdate(){
  115.                         if (CurrentState != null){
  116.                                 CurrentState.OnLateUpdate(Context_);
  117.                         }
  118.                 }
  119.         }
  120. }
复制代码
Transition 和状态基类:
  1. using UnityEngine;
  2. using System.Collections;

  3. namespace PLY.StateMachine{
  4.         /// <summary>
  5.         /// 状态机过渡约束基类.
  6.         /// </summary>
  7.         public class FiniteStateTransition {
  8.                 public string EventName;
  9.                 public string LastStateName;
  10.                 public string NextStateName;

  11.                 public FiniteStateTransition(string eventName, string lastStateName, string nextStateName){
  12.                         EventName = eventName;
  13.                         LastStateName = lastStateName;
  14.                         NextStateName = nextStateName;
  15.                 }
  16.         }

  17.         /// <summary>
  18.         /// 状态基类.
  19.         /// </summary>
  20.         public class FiniteState {
  21.                 public string Name {
  22.                         get {
  23.                                 return GetType().Name;
  24.                         }
  25.                 }

  26.                 public virtual void OnEnter(object context){}

  27.                 public virtual void OnExit(object context){}

  28.                 public virtual void OnUpdate(object context){}

  29.                 public virtual void OnFixedUpdate(object context){}

  30.                 public virtual void OnLateUpdate(object context){}
  31.         }
  32. }
复制代码
具体的测试状态机及状态的定义:
  1. using UnityEngine;
  2. using System.Collections;
  3. using PLY.StateMachine;

  4. public class PlayerStateMachine : FiniteStateMachine{

  5.         protected override void Init (){
  6.                 Locked state1 = new Locked();
  7.                 AddState(state1);
  8.        
  9.                 Unlocked state2 = new Unlocked();
  10.                 AddState(state2);

  11.                 defaultState = state1;

  12.                 AddTransition<Locked, Unlocked>("UNLOCK");
  13.                 AddTransition<Unlocked, Locked>("LOCK");
  14.         }

  15. }

  16. public class Locked : FiniteState{

  17.         public override void OnEnter (object target){
  18.                 Player owner = target as Player;
  19.                 owner.Show(true);
  20.         }
  21.        
  22.         public override void OnExit (object target){
  23.         }

  24.         public override void OnUpdate (object target){
  25.         }
  26. }

  27. public class Unlocked : FiniteState{
  28.        
  29.         public override void OnEnter (object target){
  30.                 Player owner = target as Player;
  31.                 owner.Show(false);
  32.         }
  33.        
  34.         public override void OnExit (object target){
  35.         }
  36.        
  37.         public override void OnUpdate (object target){
  38.         }
  39.        
  40. }
复制代码
宿主脚本:
  1. using UnityEngine;
  2. using System.Collections;
  3. using PLY.StateMachine;

  4. public class Player : MonoBehaviour{
  5.         public FiniteStateMachine StateMachine;
  6.         private bool isShowingLockedView_;
  7.        
  8.         private Texture LockTex_;
  9.         private Texture UnlockTex_;

  10.         private void Awake(){
  11.                 StateMachine.SetContext(this);

  12.                 LockTex_ = Resources.Load("tex_locked") as Texture;
  13.                 UnlockTex_ = Resources.Load("tex_unlocked") as Texture;
  14.         }

  15.         private void OnGUI(){
  16.                 if(GUI.Button(new Rect(0,0,120,30), "UNLOCK")){
  17.                         StateMachine.SendEvent("UNLOCK");
  18.                 }

  19.                 if(GUI.Button(new Rect(0,40,120,30), "LOCK")){
  20.                         StateMachine.SendEvent("LOCK");
  21.                 }

  22.                 if(isShowingLockedView_){
  23.                         GUI.Label(new Rect(Screen.width/2,50,128,128), new GUIContent(LockTex_));
  24.                 }
  25.                 else{
  26.                         GUI.Label(new Rect(Screen.width/2,50,128,128), new GUIContent(UnlockTex_));
  27.                 }
  28.         }

  29.         public void Show(bool isLocked){
  30.                 isShowingLockedView_ = isLocked;
  31.         }
  32. }
复制代码





欢迎光临 纳金网 (http://rs.narkii.com/club/) Powered by Discuz! X2.5