Nâng cấp AI với FSM từ bài viết trước để:
- Dễ sửa chữa, bảo trì, thêm trạng thái.
- Giảm thời gian xử lý.
Thiết kế State
Class State
Header:
// State.h // #ifndef __State_h__ #define __State_h__ class Monkey; template <class entity_type> class State { public: virtual ~State() {} //hàm này sẽ được thực hiện khi state được nhập virtual void Enter(entity_type*) = 0; //đây là hàm update của state virtual void Execcute(entity_type*) = 0; //hàm này sẽ thực hiện khi state đã thoát để chuyển state virtual void Exit(entity_type*) = 0; }; #endif // __State_h__
Các trạng thái của Monkey
bao gồm stop
, walk
, và turn
sẽ kế thừa từ class State
. Với việc thiết kế mỗi trạng thái của AI là 1 class State
, việc bảo trì, sữa chữa, hay thêm 1 trạng thái cho AI sẽ tốt hơn rất nhiều vì:
- Các đoạn code của trạng thái không liên quan gì tới các đoạn code của trạng thái khác.
- Dễ dàng tìm đến nơi muốn sửa chữa hay bảo trì.
- Nếu muốn thêm 1 trạng thái cho AI chỉ việc tạo ra 1 trạng thái mới cho AI được kết thừa từ class
State
.
Vòng đời của 1 trạng thái của AI là:
- Enter.
- Execcute.
- Exit.
Monkey states
Header
#ifndef __Monkey_State_h__ #define __Monkey_State_h__ #include "State.h" class Monkey class Stop: public State<Monkey> { private: Stop(){} Stop(const Stop&); Stop& operator=(const Stop&); protected: public: static EnterMineAndDigForNugget* Instance(); virtual void Enter(Monkey* _monkey); virtual void Execute(Monkey* _monkey); virtual void Exit(Monkey* _monkey); }; class Walk: public State<Monkey> { private: Walk(){} Walk(const Walk&); Walk& operator=(const Walk&); protected: public: static Walk* Instance(); virtual void Enter(Monkey* _monkey); virtual void Execute(Monkey* _monkey); virtual void Exit(Monkey* _monkey); }; class Turn: public State<Monkey> { private: Turn(){} Turn(const Turn&); Turn& operator=(const Turn&); protected: public: static Turn* Instance(); virtual void Enter(Monkey* _monkey); virtual void Execute(Monkey* _monkey); virtual void Exit(Monkey* _monkey); }; #endif // __Monkey_State_h__
Source
#include "MonkeyState.h" #include "State.h" #include "Monkey.h" //********************Stop***************************** Stop* Stop::Instance() { static Stop instance; return &instance; } void Stop::Enter(Monkey* _monkey) {} void Stop::Execute(Monkey* _monkey) { if (_monkey->isStopTimeout()) _monkey->GetFSM()->ChangeState(stWALK::Instance()); } void Stop::Exit(Monkey* _monkey) {} //***************************************************** //*******************Walk****************************** Walk* Walk::Instance() { static Walk instance; return &instance; } void Walk::Enter(Monkey* _monkey) {} void Walk::Execute(Monkey* _monkey) { pMiner->walk(); if (_monkey->isWalkOutBorder()) _monkey->GetFSM()->ChangeState(Turn::Instance()); else if (_monkey->isWalkTimeout()) _monkey->GetFSM()->ChangeState(Stop::Instance()); } void Walk::Exit(Monkey* _monkey) {} //***************************************************** //*********************Turn**************************** Turn* Turn::Instance() { static Turn instance; return &instance; } void Turn::Enter(Monkey* _monkey) {} void Turn::Execute(Monkey* _monkey) { _monkey->turn(); _monkey->GetFSM()->ReVertToPriviousState(); } void Turn::Exit(Monkey* _monkey) {} //*****************************************************
State Machine
Bây giờ cần 1 FSM có nhiệm vụ chạy trạng thái hiện tại và chuyển trạng thái của AI.
Header
#ifndef __State_Machine_h__ #define __State_Machine_h__ #include "State.h" template <class entity_type> class StateMachine { public: StateMachine(entity_type* m_Owner):m_pOwner(m_Owner), m_pCurrentState(NULL), m_pPreviousState(NULL), {} virtual ~StateMachine(){} void SetCurrentState(State<entity_type>* _state){m_pCurrentState = _state;} void SetPreviousState(State<entity_type>* _state){m_pPreviousState = _state;} void Update() const { m_pCurrentState->Execute(m_pOwner); } void ChangeState(State<entity_type>* _newState) { m_pPreviousState = m_pCurrentState; m_pCurrentState->Exit(m_pOwner); m_pCurrentState = _newState; m_pCurrentState->Enter(m_pOwner); } void RevertToPreviousState() { ChangeState(m_pPreviousState); } State<entity_type>* CurrentState() const{return m_pCurrentState;} State<entity_type>* PreviousState() const{return m_pPreviousState;} protected: private: entity_type* m_pOwner; State<entity_type>* m_pCurrentState; State<entity_type>* m_pPreviousState; }; #endif // __State_Machine_h__
Với class StateMachine
ở trên chỉ cần thật sự chú ý những điều sau:
- Trạng thái hiện tại của AI là
m_pCurrentState
. - Trạng thái trước đó của AI là
m_pPreviosState
.
Monkey
Header
#ifndef __Monkey_h__ #define __Monkey_h__ #include <time.h> #include "StateMachine.h" #include "State.h" #include "MonkeyState.h" #include "cocos2d.h" USING_NS_CC; #define MAX_STOP_TIME 10 #define MAX_WALK_TIME 20 #define MAX_WALK_DIST 100 class Monkey : public Node { public: Monkey() { log("Monkey()"); } ~Monkey() { delete m_monkeyFSM; } CREATE_FUNC(Monkey); virtual bool init() { _curPos = 0; _step = 1; m_monkeyFSM = new StateMachine<Monkey>(this); m_monkeyFSM->SetCurrentState(Stop::Instance()); this->scheduleUpdate(); return true; } void stop() { cocos2d::log("stop()"); } void walk() { _curPos += _step; cocos2d::log("walk(): pos=%d", _curPos); } void turn() { _step *= -1; cocos2d::log("turn(): step=%d", _step); } void update(float dt) { m_monkeyFSM->update(); } protected: private: StateMachine * m_monkeyFSM; time_t _curTime; int _curPos; int _step; public: bool isStopTimeout() { return (time(0) - _curTime > MAX_STOP_TIME); } bool isWalkTimeout() { return (time(0) - _curTime > MAX_WALK_TIME); } bool isWalkOutBorder() { return (_curPos > MAX_WALK_DIST || _curPos < -MAX_WALK_DIST); } }; #endif // __Monkey_h__
Trong class Monkey
lúc này gồm có:
- Monkey FSM: Là FSM dùng để chuyển qua lại giữa các trạng thái
stop
,walk
,turn
và execcute trạng thái hiện tại củaMonkey
. - Các sự kiện và quy luật.
Tham khảo
- https://www.cocos2d-x.org
- https://www.en.wikipedia.org