有限状态机和封闭
本文关键字:有限状态机 | 更新日期: 2023-09-27 18:15:53
最近在我的工作中,我"强迫"学习正确的编程。我读了很多术语,DDD, TDD等等。推荐《Clean Code》和《Refactoring To Patterns》这两本书,因为它们非常好。
最后,这让我选择了一些我按时执行的游戏原型,并尝试着重新使用正确的OOP,因为当我这样做时,只是跟随我的直觉(而不是学习任何东西)。
尝试在这些游戏中实现有限状态机,我遇到了几个问题。
public class StateMachine
{
private IState _globalState;
private IState _currentState;
private readonly List<IState> _previousStates;
public StateMachine(IState globalState, IState currentState)
{
_globalState = globalState;
_currentState = currentState;
_previousStates = new List<IState>();
}
public void Execute()
{
if (_globalState != null)
_globalState.Update();
if (_currentState != null)
_currentState.Update();
}
public void ChangeState(IState state)
{
_previousStates.Add(_currentState);
_currentState.Exit();
_currentState = state;
_currentState.Enter();
}
public void BackToPreviousStates()
{
_currentState.Exit();
_currentState = _previousStates[_previousStates.Count-1];
_previousStates.Remove(_currentState);
_currentState.Enter();
}
public void SetCurrentState(IState state)
{
_currentState = state;
}
public void SetGlobalState(IState state)
{
_globalState = state;
}
}
与互联网的一些例子不同,我没有踩到玩家调用状态的Update方法,也没有在proora statemmachine中作为ViniGodoy的例子(http://sofiaia.wordpress.com/2008/07/11和…-states/)因为我不明白为什么。
是State
的一个例子public class RunAway : TargetState
{
public RunAway(IEntity entity, IEntity target)
: base(entity, target)
{
}
public override void Exit()
{
// throw new NotImplementedException();
}
public override void Enter()
{
// throw new NotImplementedException();
}
public override void Update()
{
if (Target.X > Entity.X)
{
Entity.Move(Key.Down);
}
Entity.StateMachine.BackToPreviousStates();
}
}
我对Entity. statemmachine . backtopreviousstates()这一行的第一个疑问,因为这违背了OOP的模式,我封闭了我的实体(玩家或敌人)的StateMachine。
另一个问题是,在某些情况下,我将
public override void Update()
{
var enemy;
foreach (IEntity entity in Entity.World.Entities){
if(entity .GetType() == typeOf(Enemy))
{
enemy =(Enemy) entity;
break;
}
}
if (enemy != null)
Entity.StateMachine.SetCurrentState(new RunAway(Entity, enemy));
}
我违反了几个隧道,状态在构造函数中接收一个实体类,并处理World(游戏的主要类,实体也在其构造函数中接收)和statemmachine,我仍然实例化一个新的状态,而不是像Singleton模式(http://www.ai-junkie.com/books/toc_pgaibe.html)中推荐的那样。我没有使用Static,因为我不知道如何应用各种状态,因为各种状态不仅需要玩家或StateMachine的信息,还需要特定的上下文(例如Runaway State,他需要一个敌人,他会逃跑)。
我想知道如何改进这个实现并且不违反封装....
[编辑]清晰的public abstract class State : IState
{
private readonly IEntity _entity;
protected IEntity Entity
{
get { return _entity; }
}
protected State(IEntity entidade)
{
_entity = entidade;
}
public abstract void Exit();
public abstract void Enter();
public abstract void Update();
}
public class Sleep: State
{
private int _time;
public Sleep(IEntity entidade) : base(entidade)
{
}
public override void Exit()
{
// _time = 0;
}
public override void Enter()
{
_time = 0;
}
public override void Update()
{
_time++;
if (_time == 20)
Entity.StateMachine.ChangeState(new Awake()); //<-- My Questions: Singletons ou instance?
// how to enclosing it? using Entity.ChangeState(new Awake()) ?
}
}
很难说如何以更"OO"的风格重写FSM代码,因为它一开始就不像是我所认为的有限状态机。有限状态机的结构如下:
sealed class Machine
{
public readonly static State StartState = whatever;
public State CurrentState { get; private set; }
public Machine()
{
CurrentState = StartState;
}
public void ApplyNextInput(Input input)
{
CurrentState = ApplyPolicy(CurrentState, input);
}
private static State ApplyPolicy(State state, Input input)
{
// compute the new state based on the old state and the current input
}
}
我不知道你在用以前的状态缓存做什么,以及所有这些采取行动和什么的逻辑。FSM极其简单;有有限数量的状态,有有限数量的输入,每个输入都会产生一个基于如何从一个状态转换到另一个状态的简单规则的新状态。
这段代码很难理解,因为您没有显示StateMachine
类或TargetState
类的定义。你也不知道你到底想做什么。
从数学上讲,状态机可以简单地实现为静态enum单例。
显然你想做的不止这些……你到底想干什么?
(我猜你正在实现一个角色模式)