有限状态机FSM的要点是:
- 拥有一组状态,并且可以在这组状态之间进行切换。
- 状态机同时只能在一个状态。
- 一连串的输入或事件被发送给机器。
- 每个状态都有一系列的转换,转换与输入和另一状态相关。当输入进来,如果它与当前状态的某个转换匹配,机器转为转换所指的状态。
目前而言,游戏编程中状态机的实现方式,有两种可以选择:
- 用枚举配合switch case语句。
- 实现多态(也就是状态模式)。
状态模式的经典定义:允许对象在当内部状态改变时改变其行为,就好像此对象改变了自己的类一样
状态模式的实现要点,主要有三点:
- 为状态定义一个接口。
- 为每个状态定义一个类。
- 恰当地进行状态委托。
注:下面的代码在unity中用C#实现,不过只是借用了unity的输入操作,对于理解有限状态机,没有阻碍。
- 初始化是站立状态;
- 按下向上的方向键,可以跳跃;在跳跃的状态,按向下的方向键,可以下斩,按向上的方向键,不做处理;
- 按下向下的方向键,可以下蹲;在下蹲的状态,按向下的方向键,不做处理,按向上的方向键,恢复站立状态;
代码来自于这里超链接
状态接口实现:
-
public interface HeroineBaseState -
{ -
void HandleInput(); -
}
站立状态实现:
-
using UnityEngine; -
public class StandingState : HeroineBaseState -
{ -
private Heroine _heroine; -
public StandingState(Heroine heroine) -
{ -
_heroine = heroine; -
Debug.Log("进入站立状态!"); -
} -
public void HandleInput() -
{ -
if (Input.GetKeyDown(KeyCode.UpArrow)) -
{ -
Debug.Log("get KeyCode.UpArrow!"); -
_heroine.SetHeroineState(new JumpingState(_heroine)); -
} -
if (Input.GetKeyDown(KeyCode.DownArrow)) -
{ -
Debug.Log("get KeyCode.DownArrow!"); -
_heroine.SetHeroineState(new DuckingState(_heroine)); -
} -
} -
}
跳跃状态实现:
-
using UnityEngine; -
public class JumpingState : HeroineBaseState -
{ -
private Heroine _heroine; -
public JumpingState(Heroine heroine) -
{ -
_heroine = heroine; -
Debug.Log("进入跳跃状态!"); -
} -
public void HandleInput() -
{ -
if (Input.GetKeyDown(KeyCode.UpArrow)) -
{ -
Debug.Log("已经在跳跃状态中!"); -
return; -
} -
if (Input.GetKeyDown(KeyCode.DownArrow)) -
{ -
Debug.Log("get KeyCode.DownArrow!"); -
_heroine.SetHeroineState(new DrivingState(_heroine)); -
} -
} -
}
下蹲状态实现:
-
using UnityEngine; -
public class DuckingState : HeroineBaseState -
{ -
private Heroine _heroine; -
public DuckingState(Heroine heroine) -
{ -
_heroine = heroine; -
Debug.Log("进入下蹲躲避状态!"); -
} -
public void HandleInput() -
{ -
if (Input.GetKeyDown(KeyCode.DownArrow)) -
{ -
Debug.Log("已经在下蹲躲避状态中!"); -
return; -
} -
if (Input.GetKeyUp(KeyCode.UpArrow)) -
{ -
Debug.Log("get GetKeyUp.UpArrow!"); -
_heroine.SetHeroineState(new StandingState(_heroine)); -
} -
} -
}
下斩状态实现:
-
using UnityEngine; -
public class DrivingState : HeroineBaseState -
{ -
private Heroine _heroine; -
public DrivingState(Heroine heroine) -
{ -
_heroine = heroine; -
Debug.Log("进入下斩状态!"); -
} -
public void HandleInput() -
{ -
if (Input.GetKeyDown(KeyCode.UpArrow)) -
{ -
Debug.Log("get KeyCode.UpArrow!"); -
_heroine.SetHeroineState(new StandingState(_heroine)); -
} -
} -
}
女主角实现:
-
public class Heroine -
{ -
HeroineBaseState _state; -
public Heroine() -
{ -
_state = new StandingState(this); -
} -
public void SetHeroineState(HeroineBaseState newState) -
{ -
_state = newState; -
} -
public void Update() -
{ -
_state.HandleInput(); -
} -
}
测试代码,在Unity里要挂在一个GameObject上执行。
-
using UnityEngine; -
public class TestHeroine : MonoBehaviour -
{ -
private Heroine _heroine; -
// 初始化调用,先执行 -
void Start() -
{ -
_heroine = new Heroine(); -
} -
// 每帧调用一次 -
void Update() -
{ -
_heroine.Update(); -
} -
}
上面用的接口,还可以用虚函数或者抽象函数来实现多态。下面模拟了银行存款取款,账户的状态的变化。
C#代码实现:
-
using System; -
namespace StructScript -
{ -
public class StateScript -
{ -
static void Main(string[] args) -
{ -
Account account = new Account(); -
account.Add(500); -
account.Add(3000); -
account.Remove(1000); -
account.Remove(10000); -
Console.ReadLine(); -
} -
} -
public class Account -
{ -
private State state; -
public Account() -
{ -
state = new RedState(0.0, this); -
} -
public State State -
{ -
get { return state; } -
set { state = value; } -
} -
public void Add(int amount) -
{ -
Console.WriteLine("Add " + amount); -
state.Add(amount); -
Console.WriteLine("Balance: " + state.Balance); -
Console.WriteLine("State: " + state.GetType().Name); -
} -
public void Remove(int amount) -
{ -
Console.WriteLine("Remove " + amount); -
state.Remove(amount); -
Console.WriteLine("Balance: " + state.Balance); -
Console.WriteLine("State: " + state.GetType().Name); -
} -
} -
/// <summary> -
/// 状态基类 -
/// </summary> -
public abstract class State -
{ -
protected Account account; -
protected double balance; -
protected double lowerLimit; -
protected double upperLimit; -
public Account Account -
{ -
get { return account; } -
set { account = value; } -
} -
public double Balance -
{ -
get { return balance; } -
set { balance = value; } -
} -
public abstract void Add(int amount); -
public abstract void Remove(int amount); -
} -
/// <summary> -
/// 红色账户状态 -
/// </summary> -
public class RedState : State -
{ -
public RedState(State state) : this(state.Balance, state.Account) { } -
public RedState(double balance, Account account) -
{ -
this.balance = balance; -
this.account = account; -
lowerLimit = -100.0; -
upperLimit = 0.0; -
} -
public override void Add(int amount) -
{ -
balance += amount; -
StateChangeCheck(); -
} -
public override void Remove(int amount) -
{ -
Console.WriteLine("余额不足"); -
} -
private void StateChangeCheck() -
{ -
if (balance > upperLimit) -
{ -
account.State = new SilverState(this); -
} -
} -
} -
/// <summary> -
/// 银色账户状态 -
/// </summary> -
public class SilverState : State -
{ -
public SilverState(State state) : this(state.Balance, state.Account) { } -
public SilverState(double balance, Account account) -
{ -
this.balance = balance; -
this.account = account; -
lowerLimit = 0.0; -
upperLimit = 1000.0; -
} -
public override void Add(int amount) -
{ -
balance += amount; -
StateChangeCheck(); -
} -
public override void Remove(int amount) -
{ -
double remain = balance - amount; -
if (remain < -100) -
{ -
Console.WriteLine("余额不足"); -
} -
else -
{ -
balance = remain; -
StateChangeCheck(); -
} -
} -
private void StateChangeCheck() -
{ -
if (balance < lowerLimit) -
{ -
account.State = new RedState(this); -
} -
else if (balance > upperLimit) -
{ -
account.State = new GoldState(this); -
} -
} -
} -
/// <summary> -
/// 金色账户状态 -
/// </summary> -
public class GoldState : State -
{ -
public GoldState(State state) : this(state.Balance, state.Account) { } -
public GoldState(double balance, Account account) -
{ -
this.balance = balance; -
this.account = account; -
lowerLimit = 1000.0; -
upperLimit = 10000000.0; -
} -
public override void Add(int amount) -
{ -
balance += amount; -
StateChangeCheck(); -
} -
public override void Remove(int amount) -
{ -
double remain = balance - amount; -
if (remain < -100) -
{ -
Console.WriteLine("余额不足"); -
} -
else -
{ -
balance = remain; -
StateChangeCheck(); -
} -
} -
private void StateChangeCheck() -
{ -
if (balance < 0.0) -
{ -
account.State = new RedState(this); -
} -
else if (balance < lowerLimit) -
{ -
account.State = new SilverState(this); -
} -
} -
} -
}