C#数据结构-有限状态机
发表于2018-09-20
有限状态机FSM的要点是:
1.拥有一组状态,并且可以在这组状态之间进行切换。
2.状态机同时只能在一个状态。
3.一连串的输入或事件被发送给机器。
4.每个状态都有一系列的转换,转换与输入和另一状态相关。当输入进来,如果它与当前状态的某个转换匹配,机器转为转换所指的状态。
目前而言,游戏编程中状态机的实现方式,有两种可以选择:
1.用枚举配合switch case语句。
2.实现多态(也就是状态模式)。
状态模式的经典定义:允许对象在当内部状态改变时改变其行为,就好像此对象改变了自己的类一样。
状态模式的实现要点,主要有三点:
1.为状态定义一个接口。
2.为每个状态定义一个类。
3.恰当地进行状态委托。
注:下面的代码在unity中用C#实现,不过只是借用了unity的输入操作,对于理解有限状态机,没有阻碍。
初始化是站立状态;
1.按下向上的方向键,可以跳跃;在跳跃的状态,按向下的方向键,可以下斩,按向上的方向键,不做处理;
2.按下向下的方向键,可以下蹲;在下蹲的状态,按向下的方向键,不做处理,按向上的方向键,恢复站立状态;
状态接口实现:
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); } } } }
来自:https://blog.csdn.net/qq826364410/article/details/79827022