有限状态机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);
-
}
-
}
-
}
-
}