- 先写一个enum枚举类State用来存储状态:
public enum State {
Idle,
Move,
Attack,
Dead
}
- 创建一个状态机类,并在其中定义状态转换的条件和行为:
public class StateMachine {
private State currentState;
private Dictionary<State, List<Transition>> graph;
public StateMachine() {
graph = new Dictionary<State, List<Transition>>();
}
public void AddTransition(State fromState, State toState, Func<bool> condition, Action onTransition) {
var transition = new Transition(toState, condition, onTransition);
if (!graph.ContainsKey(fromState)) {
graph[fromState] = new List<Transition>();
}
graph[fromState].Add(transition);
}
public void SetState(State state) {
if (state != currentState) {
currentState = state;
Debug.Log($"Current state: {currentState}");
}
}
public void Update() {
if (graph.ContainsKey(currentState)) {
foreach (var transition in graph[currentState]) {
if (transition.Condition()) {
transition.OnTransition();
SetState(transition.To);
break;
}
}
} else {
Debug.LogWarning($"No transition available for state {currentState}");
}
}
private class Transition {
public State To { get; }
public Func<bool> Condition { get; }
public Action OnTransition { get; }
public Transition(State to, Func<bool> condition, Action onTransition) {
To = to;
Condition = condition;
OnTransition = onTransition;
}
}
}
-
AddTransition
方法:添加一个状态转移。4个参数:
-
fromState
:要从哪种状态开始转换。
-
toState
:目标状态。
-
condition
:转换条件的执行结果将决定是否开始转换。它是一个Func类型的委托,它需要返回一个bool类型的值。
-
onTransition
:表示当转换发生时需要执行的行为。它是一个Action类型的委托,它没有返回值。
-
SetState
方法:设置当前状态。
-
Update
方法:每帧执行该方法,它执行当前状态的行为并检查是否需要转移状态。
-
Transition
内部类:定义了一个状态转移,包含三个公共属性:
-
To
:目标状态。
-
Condition
:用于检查是否满足状态转换条件。
-
OnTransition
:表示转换发生时要执行的行为。
- 创建一个状态机实例,并添加状态转换条件和行为:
public class MyGameObject : MonoBehaviour {
private StateMachine stateMachine;
void Start() {
stateMachine = new StateMachine();
stateMachine.AddTransition(State.Idle, State.Move, () => Input.GetKey(KeyCode.W), () => Debug.Log("Start moving"));
stateMachine.AddTransition(State.Move, State.Idle, () => !Input.GetKey(KeyCode.W), () => Debug.Log("Stop moving"));
stateMachine.AddTransition(State.Idle, State.Attack, () => Input.GetMouseButtonDown(0), () => Debug.Log("Start attacking"));
stateMachine.AddTransition(State.Attack, State.Idle, () => Input.GetMouseButtonUp(0), () => Debug.Log("Stop attacking"));
stateMachine.AddTransition(State.Attack, State.Dead, () => GetComponent<Health>().IsDead, () => Debug.Log("Dead"));
}
void Update() {
stateMachine.Update();
}
}