状态基类:先布置好委托,继承的子类可以通过回调函数添加事件,在Enterstate这些虚函数里面写了回调,重写的时候也要触发一下

1、FSMTriggerID:条件ID枚举

1
2
3
4
5
6
7
8
9
10
11
namespace CharacterControlSystem.CharacterFSM
{
public enum FSMTriggerID
{
JumpToIdleDetection,
MoveToIdleDetection,

IdleToMoveDetection,
IdleToJumpDetection,
}
}

2、FSMStateID:状态ID枚举

1
2
3
4
5
6
7
8
9
10
namespace CharacterControlSystem.CharacterFSM
{
public enum FSMStateID
{
Default,
Idle,
Run,
Jump,
}
}

3、FSMTrigger:条件基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System;
using UnityEngine;

namespace CharacterControlSystem.CharacterFSM
{
/// <summary>
/// 有限状态机中的条件类基类
/// </summary>
public abstract class FSMTrigger
{
/// <summary>
/// 条件ID
/// </summary>
public FSMTriggerID TriggerId { get; set; }

public FSMTrigger()
{
InitId();
}
/// <summary>
/// 子类必须实现此方法来为TriggerId赋值
/// 此方法由构造函数调用
/// </summary>
protected abstract void InitId();
/// <summary>
/// 子类必须实现此方法来处理条件逻辑,
/// 状态机通过检查所有状态的所有条件来判断需要切换至什么状态
/// 检测方法内部来判断此方法
/// </summary>
public abstract bool HandleTrigger(GameObject thisGameObject);
}
}

4、FSMState:状态基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
using System;
using System.Collections.Generic;
using UnityEngine;

namespace CharacterControlSystem.CharacterFSM
{
public abstract class FSMState
{
/// <summary>
/// 状态ID
/// </summary>
public FSMStateID StateId { get; set; }
/// <summary>
/// 条件状态映射表
/// </summary>
private Dictionary<FSMTriggerID, FSMStateID> _map;
/// <summary>
/// 条件表
/// </summary>
private List<FSMTrigger> _triggers;
/// <summary>
/// 进入状态时调用的委托
/// </summary>
private Action enterStateHandler;
/// <summary>
/// 状态中持续调用的委托
/// </summary>
private Action stayStateHandler;
/// <summary>
/// 退出状态时调用的委托
/// </summary>
private Action exitStateHandler;
/// <summary>
/// 当前游戏对象
/// </summary>
protected GameObject thisGameObject;
/// <summary>
/// 用作初始化的构造函数
/// </summary>
public FSMState(GameObject thisGameObject)
{
this.thisGameObject = thisGameObject;
_map = new Dictionary<FSMTriggerID, FSMStateID>();
_triggers = new List<FSMTrigger>();
InitState();
}
protected abstract void InitState();

/// <summary>
/// 添加映射关系,由状态机调用
/// </summary>
/// <param name="triggerId">条件ID</param>
/// <param name="stateId">状态ID</param>
public void AddMap(FSMTriggerID triggerId, FSMStateID stateId)
{
_map.Add(triggerId, stateId);
CreateTrigger(triggerId);
}
/// <summary>
/// 动态创建条件对象并添加到条件列表中
/// </summary>
/// <param name="triggerId">条件ID</param>
private void CreateTrigger(FSMTriggerID triggerId)
{
Type triggerType = Type.GetType("CharacterControlSystem.CharacterFSM.SubFSM.Trigger." +triggerId+ "Trigger");
if (triggerType != null)
{
FSMTrigger trigger = Activator.CreateInstance(triggerType) as FSMTrigger;
_triggers.Add(trigger);
}
}
/// <summary>
/// 状态机通过此方法来检测是否可以切换到某个状态
/// </summary>
/// <param name="fsmBase"></param>
public void Reason(FSMBase fsmBase)
{
for (int i = 0; i < _triggers.Count; i++)
{
//如果发现条件满足的条件
if (_triggers[i].HandleTrigger(fsmBase.gameObject))
{
//返回给状态机
fsmBase.ChangeState(_map[_triggers[i].TriggerId]);
return;
}
}
}
/// <summary>
/// 为进入状态委托添加回调函数
/// </summary>
/// <param name="func"></param>
public void AddEnterStateListener(Action func)
{
enterStateHandler += func;
}
/// <summary>
/// 为持续调用委托添加回调函数
/// </summary>
/// <param name="func"></param>
public void AddStayStateListener(Action func)
{
stayStateHandler += func;
}
/// <summary>
/// 为退出状态委托添加回调函数
/// </summary>
/// <param name="func"></param>
public void AddExitStateListener(Action func)
{
exitStateHandler += func;
}
/// <summary>
/// 主要用于改变角色当前状态
/// </summary>
public virtual void EnterState()
{
enterStateHandler?.Invoke();
}
/// <summary>
/// 用于角色在状态中的一些持续操作
/// </summary>
public virtual void StayState()
{
stayStateHandler?.Invoke();
}
/// <summary>
/// 主要用于退出状态时的一些操作
/// </summary>
public virtual void ExitState()
{
exitStateHandler?.Invoke();
}
}
}

5、FSMBase:状态机基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
using System.Collections.Generic;
using CsharpBaseModule.PublicMono;
using UnityEngine;

namespace CharacterControlSystem.CharacterFSM
{
/// <summary>
/// 状态机,表示一个角色所拥有的所有的状态
/// </summary>
public abstract class FSMBase : MonoBehaviour
{
/// <summary>
/// 状态列表
/// </summary>
protected Dictionary<FSMStateID,FSMState> _states;
/// <summary>
/// 默认状态ID
/// </summary>
[Tooltip("请选择默认状态")]
public FSMStateID defaultStateId;
/// <summary>
/// 默认状态
/// </summary>
protected FSMState _defaultState;
/// <summary>
/// 当前状态
/// </summary>
public FSMState currentState;
/// <summary>
/// 这里我将Update提到了一个公共Mono中,也可以不提
/// </summary>
protected virtual void Awake()
{
ConfigFSM();
InitDefaultState();
MonoManager.GetInstance.AddUpdateListener(BaseUpdate);
}
/// <summary>
/// 配置状态机,基类只初始化一下就好,具体配置留给子类状态机实现
/// </summary>
protected virtual void ConfigFSM()
{
_states = new Dictionary<FSMStateID, FSMState>();
}
/// <summary>
/// 初始化状态,会将默认状态赋给当前状态变量
/// </summary>
protected virtual void InitDefaultState()
{
_defaultState = _states[defaultStateId];
currentState = _defaultState;
currentState.EnterState();
}
/// <summary>
/// 每帧调用当前状态逻辑和检测是否满足其他状态的切换条件
/// </summary>
protected virtual void BaseUpdate()
{
currentState.Reason(this);
currentState.StayState();
}
/// <summary>
/// 改变当前状态,改变之前先调用条件退出的方法,之后调用新条件进入的方法
/// </summary>
/// <param name="stateId">状态ID</param>
public void ChangeState(FSMStateID stateId)
{
currentState.ExitState();
currentState = stateId == FSMStateID.Default
? _defaultState
: _states[stateId];
currentState.EnterState();
}
/// <summary>
/// 添加状态,在状态机配置中进行调用
/// </summary>
/// <param name="stateId">状态ID</param>
/// <param name="state">状态,配置时new一个</param>
/// <returns></returns>
protected FSMState AddState(FSMStateID stateId, FSMState state)
{
_states.Add(stateId, state);
return state;
}
/// <summary>
/// 寻找相应的状态
/// </summary>
/// <param name="stateId">状态ID</param>
/// <returns></returns>
protected FSMState FindState(FSMStateID stateId)
{
if (_states.ContainsKey(stateId))
{
return _states[stateId];
}

return null;
}

}
}

案例

总结:

1、添加好状态枚举和条件枚举

2、条件需要添加好InitId和HandleTrigger

3、状态需要添加好InitId和AddMap转化

  1. 定义FSMTriggerID和FSMStateID枚举:
1
2
3
4
5
6
7
8
9
10
11
12
13
public enum PlayerFSMTriggerID
{
Walk,
Run,
Stop,
}

public enum PlayerFSMStateID
{
Idle,
Walking,
Running,
}
  1. 实现FSM触发器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
namespace CharacterControlSystem.CharacterFSM.SubFSM.Trigger
{
public class WalkTrigger : FSMTrigger
{
protected override void InitId()
{
TriggerId = PlayerFSMTriggerID.Walk;
}

public override bool HandleTrigger(GameObject thisGameObject)
{
// 实现检查行走条件是否满足的逻辑
return Input.GetKey(KeyCode.W); // 例如,按下W键触发行走
}
}

public class RunTrigger : FSMTrigger
{
protected override void InitId()
{
TriggerId = PlayerFSMTriggerID.Run;
}

public override bool HandleTrigger(GameObject thisGameObject)
{
// 实现检查奔跑条件是否满足的逻辑
return Input.GetKey(KeyCode.LeftShift); // 例如,按住Shift键触发奔跑
}
}

public class StopTrigger : FSMTrigger
{
protected override void InitId()
{
TriggerId = PlayerFSMTriggerID.Stop;
}

public override bool HandleTrigger(GameObject thisGameObject)
{
// 实现检查停止条件是否满足的逻辑
return !Input.GetKey(KeyCode.W) && !Input.GetKey(KeyCode.LeftShift);
}
}
}
  1. 实现FSM状态:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
namespace CharacterControlSystem.CharacterFSM.SubFSM
{
public class IdleState : FSMState
{
protected override void InitState()
{
StateId = PlayerFSMStateID.Idle;
// 添加转换
AddMap(PlayerFSMTriggerID.Walk, PlayerFSMStateID.Walking);
AddMap(PlayerFSMTriggerID.Run, PlayerFSMStateID.Running);
}
}

public class WalkingState : FSMState
{
protected override void InitState()
{
StateId = PlayerFSMStateID.Walking;
// 添加转换
AddMap(PlayerFSMTriggerID.Run, PlayerFSMStateID.Running);
AddMap(PlayerFSMTriggerID.Stop, PlayerFSMStateID.Idle);
}
}

public class RunningState : FSMState
{
protected override void InitState()
{
StateId = PlayerFSMStateID.Running;
// 添加转换
AddMap(PlayerFSMTriggerID.Stop, PlayerFSMStateID.Idle);
}
}
}
  1. 实现PlayerFSM:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
namespace CharacterControlSystem.CharacterFSM
{
public class PlayerFSM : FSMBase
{
protected override void ConfigFSM()
{
// 创建状态
var idleState = AddState(PlayerFSMStateID.Idle, new IdleState());
var walkingState = AddState(PlayerFSMStateID.Walking, new WalkingState());
var runningState = AddState(PlayerFSMStateID.Running, new RunningState());

// 设置默认状态
defaultStateId = PlayerFSMStateID.Idle;
}
}
}