unity之通用FSM有限状态机(一)


什么是有限状态机:

有限状态机是一种用来进行对象行为建模的工具,作用是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。简单理解就是:状态满足条件下的一种处理机制。

有限状态机,任意时刻都处于有限状态集合中的某一状态。当获得一个输入字符时,将从当前状态转换到另一状态或仍保持当前状态。

每一个状态都有三种行为:进入、 执行、 离开。

 

对状态机有一个简单的了解之后,那么状态机在unity游戏开发中有哪些应用呢?

大多游戏都有以下流程:

这些流程,我们是不是可以理解为状态。

在AI 方面,游戏中的玩家行为大致有以下状态:

站立(待机)、跑、跳、普攻、技能1,技能2,技能3,受伤、控制(眩晕、禁锢)、死亡 等等

 

以上2种举例都可体现有限状态机在游戏中的应用。故设计通用的状态机就显得很有必要。而不是为每一个应用都写一个状态机。

 

废话不多说,直接上代码

状态机基类:

 1 public abstract class TestFsmBase
 2 {
 3     /// 
 4     /// 状态机编号
 5     /// 
 6     public int FsmId { get; private set; }
 7 
 8     /// 
 9     /// 状态机当前的状态
10     /// 
11     public sbyte CurrState;
12 
13 
14     public TestFsmBase(int fsmId)
15     {
16         FsmId = fsmId;
17     }
18 
19     /// 
20     /// 关闭
21     /// 
22     public abstract void ShutDown();
23 }

 

状态机状态

 1 public class TestFsmState where T : class
 2 {
 3     public TestFsm CurrFsm;
 4 
 5     public virtual void OnEnter()
 6     {
 7     }
 8 
 9     public virtual void OnUpdate()
10     {
11     }
12 
13     public virtual void OnLeave()
14     {
15     }
16 
17     public virtual void OnDestroy()
18     {
19 
20     }
21 }

 

状态机:

 1 using System.Collections.Generic;
 2 
 3 public class TestFsm : TestFsmBase where T : class
 4 {
 5     /// 
 6     /// 状态机拥有者
 7     /// 
 8     public T Owner { get; private set; }
 9 
10     public TestFsmState m_CurrFsmState;
11 
12     public Dictionary<sbyte, TestFsmState> m_StateDic;
13 
14 
15     public TestFsm(int fsmId, T owner, TestFsmState[] status) : base(fsmId)
16     {
17         Owner = owner;
18         m_StateDic = new Dictionary<sbyte, TestFsmState>();
19         for (int i = 0; i < status.Length; i++)
20         {
21             m_StateDic[(sbyte)i] = status[i];
22             status[i].CurrFsm = this;//状态的状态机就是Fsm本身
23         }
24         CurrState = -1;
25     }
26 
27     /// 
28     /// 获取状态
29     /// 
30     /// 
31     public TestFsmState GetState(sbyte stateType)
32     {
33         m_StateDic.TryGetValue(stateType, out TestFsmState fsmState);
34         return fsmState;
35     }
36 
37     /// 
38     /// 切换状态
39     /// 
40     /// 
41     public void ChangeState(sbyte newState)
42     {
43         //上一个状态离开 新状态进入
44         if (newState == CurrStateType) return;
45         if (m_CurrFsmState != null)
46         {
47             m_CurrFsmState.OnLeave();
48         }
49         if (m_StateDic.TryGetValue(newState, out TestFsmState newFsmState))
50         {
51             CurrState = newState;
52             m_CurrFsmState = newFsmState;
53             m_CurrFsmState.OnEnter();
54         }
55     }
56 
57     public void OnUpdate()
58     {
59         if (m_CurrFsmState != null)
60         {
61             m_CurrFsmState.OnUpdate();
62         }
63     }
64 
65     /// 
66     /// 关闭状态机
67     /// 
68     public override void ShutDown()
69     {
70         if (m_CurrFsmState != null)
71         {
72             m_CurrFsmState.OnLeave();
73         }
74         var enumerator = m_StateDic.GetEnumerator();
75         while (enumerator.MoveNext())
76         {
77             enumerator.Current.Value.OnDestroy();
78         }
79         m_StateDic.Clear();
80     }
81 }

 

状态机管理器:

 1 using System;
 2 using System.Collections.Generic;
 3 
 4 /// 
 5 /// 状态机管理器
 6 /// 
 7 public class TestFsmManager : IDisposable
 8 {
 9     private int m_tempFsmId = 1;
10     private readonly Dictionary<int, TestFsmBase> fmsDic;
11 
12     public TestFsmManager()
13     {
14         fmsDic = new Dictionary<int, TestFsmBase>();
15     }
16 
17     /// 
18     /// 创建
19     /// 
20     /// 
21     /// 
22     /// 
23     /// 
24     public TestFsm CreateFsm(T owner, TestFsmState[] status) where T : class
25     {
26         TestFsm fsm = new TestFsm(m_tempFsmId++, owner, status);
27         fmsDic[m_tempFsmId] = fsm;
28         return fsm;
29     }
30 
31     /// 
32     /// 是否存在
33     /// 
34     /// 
35     /// 
36     public bool HasFsm(int fsmId)
37     {
38         return fmsDic.ContainsKey(fsmId);
39     }
40 
41     /// 
42     /// 销毁
43     /// 
44     /// 
45     public void DestroyFsm(int fsmId)
46     {
47         if (fmsDic.TryGetValue(fsmId, out TestFsmBase fsmBase))
48         {
49             fsmBase.ShutDown();
50             fmsDic.Remove(fsmId);
51         }
52     }
53 
54     public void Dispose()
55     {
56         var enumerator = fmsDic.GetEnumerator();
57         while (enumerator.MoveNext())
58         {
59             enumerator.Current.Value.ShutDown();
60         }
61         fmsDic.Clear();
62     }
63 }

 

接下来,讲解下状态机在流程应用方面是如何使用的。