有限状态机,(英语:Finite-state machine, FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
设计者可以让角色持有一个有限状态机管理角色的不同状态,这个有限状态机也持有拥有它的角色。
有限状态机保存了当前状态、上一个状态、全局状态(全局状态总是长期存在于角色中,例如总是可以从任意状态切换到如厕状态),切换状态的方法、返回上一个状态的方法等。
每个状态都有进入、执行、退出方法,需要传进持有该状态的角色,以便状态可以达到某个状态让角色的有限状态机切换状态。
#ifndef STATEMACHINE_H
#define STATEMACHINE_H
//------------------------------------------------------------------------
//
// Name: StateMachine.h
//
// Desc: State machine class. Inherit from this class and create some
// states to give your agents FSM functionality
//
// Author: Mat Buckland 2002 (fup@ai-junkie.com)
//
//------------------------------------------------------------------------
#include <cassert>
#include <string>
#include "State.h"
template <class entity_type>
class StateMachine
{
private:
//a pointer to the agent that owns this instance
entity_type* m_pOwner;
State<entity_type>* m_pCurrentState;
//a record of the last state the agent was in
State<entity_type>* m_pPreviousState;
//this is called every time the FSM is updated
State<entity_type>* m_pGlobalState;
public:
StateMachine(entity_type* owner):m_pOwner(owner),
m_pCurrentState(NULL),
m_pPreviousState(NULL),
m_pGlobalState(NULL)
{}
virtual ~StateMachine(){}
//use these methods to initialize the FSM
void SetCurrentState(State<entity_type>* s){m_pCurrentState = s;}
void SetGlobalState(State<entity_type>* s) {m_pGlobalState = s;}
void SetPreviousState(State<entity_type>* s){m_pPreviousState = s;}
//call this to update the FSM
void Update()const
{
//if a global state exists, call its execute method, else do nothing
if(m_pGlobalState) m_pGlobalState->Execute(m_pOwner);
//same for the current state
if (m_pCurrentState) m_pCurrentState->Execute(m_pOwner);
}
//change to a new state
void ChangeState(State<entity_type>* pNewState)
{
assert(pNewState &&
"<StateMachine::ChangeState>: trying to change to NULL state");
//keep a record of the previous state
m_pPreviousState = m_pCurrentState;
//call the exit method of the existing state
m_pCurrentState->Exit(m_pOwner);
//change state to the new state
m_pCurrentState = pNewState;
//call the entry method of the new state
m_pCurrentState->Enter(m_pOwner);
}
//change state back to the previous state
void RevertToPreviousState()
{
ChangeState(m_pPreviousState);
}
//returns true if the current state's type is equal to the type of the
//class passed as a parameter.
bool isInState(const State<entity_type>& st)const
{
return typeid(*m_pCurrentState) == typeid(st);
}
State<entity_type>* CurrentState() const{return m_pCurrentState;}
State<entity_type>* GlobalState() const{return m_pGlobalState;}
State<entity_type>* PreviousState() const{return m_pPreviousState;}
};
#endif
#ifndef STATE_H
#define STATE_H
//------------------------------------------------------------------------
//
// Name: State.h
//
// Desc: abstract base class to define an interface for a state
//
// Author: Mat Buckland 2002 (fup@ai-junkie.com)
//
//------------------------------------------------------------------------
template <class entity_type>
class State
{
public:
virtual ~State(){}
//this will execute when the state is entered
virtual void Enter(entity_type*)=0;
//this is the states normal update function
virtual void Execute(entity_type*)=0;
//this will execute when the state is exited. (My word, isn't
//life full of surprises... ;o))
virtual void Exit(entity_type*)=0;
};
#endif
#ifndef MINER_OWNED_STATES_H
#define MINER_OWNED_STATES_H
//------------------------------------------------------------------------
//
// Name: MinerOwnedStates.h
//
// Desc: All the states that can be assigned to the Miner class
//
// Author: Mat Buckland 2002 (fup@ai-junkie.com)
//
//------------------------------------------------------------------------
#include "State.h"
class Miner;
//------------------------------------------------------------------------
//
// In this state the miner will walk to a goldmine and pick up a nugget
// of gold. If the miner already has a nugget of gold he'll change state
// to VisitBankAndDepositGold. If he gets thirsty he'll change state
// to QuenchThirst
//------------------------------------------------------------------------
class EnterMineAndDigForNugget : public State<Miner>
{
private:
EnterMineAndDigForNugget(){}
//copy ctor and assignment should be private
EnterMineAndDigForNugget(const EnterMineAndDigForNugget&);
EnterMineAndDigForNugget& operator=(const EnterMineAndDigForNugget&);
public:
static EnterMineAndDigForNugget* Instance();
public:
virtual void Enter(Miner* miner);
virtual void Execute(Miner* miner);
virtual void Exit(Miner* miner);
};
//------------------------------------------------------------------------
//
// Entity will go to a bank and deposit any nuggets he is carrying. If the
// miner is subsequently wealthy enough he'll walk home, otherwise he'll
// keep going to get more gold
//------------------------------------------------------------------------
class VisitBankAndDepositGold : public State<Miner>
{
private:
VisitBankAndDepositGold(){}
//copy ctor and assignment should be private
VisitBankAndDepositGold(const VisitBankAndDepositGold&);
VisitBankAndDepositGold& operator=(const VisitBankAndDepositGold&);
public:
static VisitBankAndDepositGold* Instance();
virtual void Enter(Miner* miner);
virtual void Execute(Miner* miner);
virtual void Exit(Miner* miner);
};
//------------------------------------------------------------------------
//
// miner will go home and sleep until his fatigue is decreased
// sufficiently
//------------------------------------------------------------------------
class GoHomeAndSleepTilRested : public State<Miner>
{
private:
GoHomeAndSleepTilRested(){}
//copy ctor and assignment should be private
GoHomeAndSleepTilRested(const GoHomeAndSleepTilRested&);
GoHomeAndSleepTilRested& operator=(const GoHomeAndSleepTilRested&);
public:
static GoHomeAndSleepTilRested* Instance();
virtual void Enter(Miner* miner);
virtual void Execute(Miner* miner);
virtual void Exit(Miner* miner);
};
//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
class QuenchThirst : public State<Miner>
{
private:
QuenchThirst(){}
//copy ctor and assignment should be private
QuenchThirst(const QuenchThirst&);
QuenchThirst& operator=(const QuenchThirst&);
public:
static QuenchThirst* Instance();
virtual void Enter(Miner* miner);
virtual void Execute(Miner* miner);
virtual void Exit(Miner* miner);
};
#endif
#ifndef MINER_H
#define MINER_H
//------------------------------------------------------------------------
//
// Name: Miner.h
//
// Desc: A class defining a goldminer.
//
// Author: Mat Buckland 2002 (fup@ai-junkie.com)
//
//------------------------------------------------------------------------
#include <string>
#include <cassert>
#include "BaseGameEntity.h"
#include "Locations.h"
#include "MinerOwnedStates.h"
#include "StateMachine.h"
//the amount of gold a miner must have before he feels comfortable
const int ComfortLevel = 5;
//the amount of nuggets a miner can carry
const int MaxNuggets = 3;
//above this value a miner is thirsty
const int ThirstLevel = 5;
//above this value a miner is sleepy
const int TirednessThreshold = 5;
class Miner : public BaseGameEntity
{
private:
//an instance of the state machine class
StateMachine<Miner>* m_pStateMachine;
location_type m_Location;
//how many nuggets the miner has in his pockets
int m_iGoldCarried;
int m_iMoneyInBank;
//the higher the value, the thirstier the miner
int m_iThirst;
//the higher the value, the more tired the miner
int m_iFatigue;
public:
Miner(int id):BaseGameEntity(id),
m_Location(shack),
m_iGoldCarried(0),
m_iMoneyInBank(0),
m_iThirst(0),
m_iFatigue(0)
{
m_pStateMachine = new StateMachine<Miner>(this);
m_pStateMachine->SetCurrentState(GoHomeAndSleepTilRested::Instance());
}
~Miner(){delete m_pStateMachine;}
//this must be implemented
void Update();
StateMachine<Miner>* GetFSM()const{return m_pStateMachine;}
location_type Location()const{return m_Location;}
void ChangeLocation(const location_type loc){m_Location=loc;}
int GoldCarried()const{return m_iGoldCarried;}
void SetGoldCarried(const int val){m_iGoldCarried = val;}
void AddToGoldCarried(const int val);
bool PocketsFull()const{return m_iGoldCarried >= MaxNuggets;}
bool Fatigued()const;
void DecreaseFatigue(){m_iFatigue -= 1;}
void IncreaseFatigue(){m_iFatigue += 1;}
int Wealth()const{return m_iMoneyInBank;}
void SetWealth(const int val){m_iMoneyInBank = val;}
void AddToWealth(const int val);
bool Thirsty()const;
void BuyAndDrinkAWhiskey(){m_iThirst = 0; m_iMoneyInBank-=2;}
};
#endif