unity之通用FSM有限状态机(一)
什么是有限状态机:
有限状态机是一种用来进行对象行为建模的工具,作用是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。简单理解就是:状态满足条件下的一种处理机制。
有限状态机,任意时刻都处于有限状态集合中的某一状态。当获得一个输入字符时,将从当前状态转换到另一状态或仍保持当前状态。
每一个状态都有三种行为:进入、 执行、 离开。
对状态机有一个简单的了解之后,那么状态机在unity游戏开发中有哪些应用呢?
大多游戏都有以下流程:
这些流程,我们是不是可以理解为状态。
在AI 方面,游戏中的玩家行为大致有以下状态:
站立(待机)、跑、跳、普攻、技能1,技能2,技能3,受伤、控制(眩晕、禁锢)、死亡 等等
以上2种举例都可体现有限状态机在游戏中的应用。故设计通用的状态机就显得很有必要。而不是为每一个应用都写一个状态机。
废话不多说,直接上代码
状态机基类:都存在编号、当前状态 抽象到基类。
1 public abstract class TestFsmBase
2 {
3 /// <summary>
4 /// 状态机编号
5 /// </summary>
6 public int FsmId { get; private set; }
7
8 /// <summary>
9 /// 状态机当前的状态
10 /// </summary>
11 public sbyte CurrState;
12
13
14 public TestFsmBase(int fsmId)
15 {
16 FsmId = fsmId;
17 }
18
19 /// <summary>
20 /// 关闭
21 /// </summary>
22 public abstract void ShutDown();
23 }
状态机状态:进入 执行 离开 最基本的三种行为。
1 public class TestFsmState<T> where T : class
2 {
3 public TestFsm<T> 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.状态机的拥有者
2.状态机都有哪些状态
3.切换状态
4.关闭状态机
1 using System.Collections.Generic;
2
3 public class TestFsm<T> : TestFsmBase where T : class
4 {
5 /// <summary>
6 /// 状态机拥有者
7 /// </summary>
8 public T Owner { get; private set; }
9
10 public TestFsmState<T> m_CurrFsmState;
11
12 public Dictionary<sbyte, TestFsmState<T>> m_StateDic;
13
14
15 public TestFsm(int fsmId, T owner, TestFsmState<T>[] status) : base(fsmId)
16 {
17 Owner = owner;
18 m_StateDic = new Dictionary<sbyte, TestFsmState<T>>();
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 /// <summary>
28 /// 获取状态
29 /// </summary>
30 /// <returns></returns>
31 public TestFsmState<T> GetState(sbyte stateType)
32 {
33 m_StateDic.TryGetValue(stateType, out TestFsmState<T> fsmState);
34 return fsmState;
35 }
36
37 /// <summary>
38 /// 切换状态
39 /// </summary>
40 /// <param name="newState"></param>
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<T> 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 /// <summary>
66 /// 关闭状态机
67 /// </summary>
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 /// <summary>
5 /// 状态机管理器
6 /// </summary>
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 /// <summary>
18 /// 创建
19 /// </summary>
20 /// <typeparam name="T"></typeparam>
21 /// <param name="own"></param>
22 /// <param name="status"></param>
23 /// <returns></returns>
24 public TestFsm<T> CreateFsm<T>(T owner, TestFsmState<T>[] status) where T : class
25 {
26 TestFsm<T> fsm = new TestFsm<T>(m_tempFsmId++, owner, status);
27 fmsDic[m_tempFsmId] = fsm;
28 return fsm;
29 }
30
31 /// <summary>
32 /// 是否存在
33 /// </summary>
34 /// <param name="fsmId"></param>
35 /// <returns></returns>
36 public bool HasFsm(int fsmId)
37 {
38 return fmsDic.ContainsKey(fsmId);
39 }
40
41 /// <summary>
42 /// 销毁
43 /// </summary>
44 /// <param name="fsmId"></param>
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 }
接下来,讲解下状态机在流程应用方面是如何使用的。