赞
踩
首先状态机模式是处理一个类在内部状态改变的时候,其方法处理信息的模式也会改变;
这里说一个在RTS游戏里的应用:有限状态机。
我们要赋予每个战斗单位一个智能,比如一定范围内检测到地方单位,且自身处于游荡或者Patrol状态,那么就转换为攻击状态,再比如我们给这个单位一个通往目的地的路径,那么这个单位会自动前往目的地,如果到达目的地,那么就进入Idle状态。
这里我们可以写一个状态管理类:
- class StateSystem{
- void State state;
- public:
- void Run(){
- if(state==State::Idle){
- //...
- if(传递路径){
- LeaveState();
- state==State::Path;
- InitState();
- }
- }else if(state==State::Path){
- //...
- if(//到达终点){
- LeaveState();
- state=State::Idle;
- InitState();
- }
- }else if(state==State::Patrol){
- //...
- if(周边有敌人){
- LeaveState();
- state=State::Attack;
- InitState();
- }
- }else if(state==State::Attack){
- //...
- if(敌人被消灭){
- LeaveState();
- state=Satte::Idle;
- InitState();
- }
- }
- }
-
- void InitState(){
- if(state==State::Idle){
- //...
- }else if(state==State::Path){
- //...
- }else if(state==State::Patrol){
- //...
- }else if(state==State::Attack){
- //...
- }
- }
-
- void LeaveState(){
- if(state==State::Idle){
- //...
- }else if(state==State::Path){
- //...
- }else if(state==State::Patrol){
- //...
- }else if(state==State::Attack){
- //...
- }
- }
- }
可以看到,典型的bad smell,这里我们可以将每个状态抽象出来,设计好接口,然后用多态来替代if_else。
这个就是状态机模式的精髓,因为处理的问题就是一个类的方法处理信息的模式和类的状态有关,那么换句话说技术类中的每个状态都要处理相同的信息,那么我们为什么不把这种状态抽离出来呢,然后单独考虑呢?这样我们可以在原本的类中存储这些类的抽象接口,然后通过接口来调用这些状态。
看以下代码:
- #include<unordered_map>
-
- enum State {
- Idle,Patrol,Path,Attack,None
- };
-
- class State_Ifc {
- State state;
- public:
- virtual void Init() = 0;//初始化状态
- virtual void Leave() = 0;//卸载状态
- virtual void Run() = 0;//处理信息
- virtual State Reason() = 0;//转移到其他状态
- virtual State GetState() { return state; }
- };
-
- class IdleState :public State_Ifc {
- //....重写
- };
-
- class PatrolState :public State_Ifc {
- //....重写
- };
-
- class PathState :public State_Ifc {
- //....重写
- };
-
- class AttackState :public State_Ifc {
- //....重写
- };
-
- class StateSystem {
- State_Ifc* Current;//当前的状态
- std::unordered_map<State, State_Ifc*> map;
- //
- public:
- void UpData() {
- Current->Run();
- }
- void Trans() {
- State temp = Current->Reason();
- if (temp != State::None) {
- Current->Leave();
- Current = map[temp];
- Current->Init();
- }
- }
- };
这样子的话,State不依赖于具体的状态,而是依赖于抽象接口,这样子的话,就为拓展带来了可能。
但是,这个模式也有坏处,那就是没当添加新的状态,如果这个状态有和其他状态有转换,那么我们就不得不修改源代码,这里,本菜想,可以通过中介者模式来解决这个问题,具体方法是将
Reason方法从State子类中抽离出来,这样,我们修改转换时,只需要修改Mediator类即可:
具体如下:
- #include<unordered_map>
- #include<list>
- enum State {
- Idle,Patrol,Path,Attack,None
- };
-
- class Mediator_Ifc {
- public:
- virtual State Trans(State stateS, State stateE) = 0;
- };
-
- class State_Ifc {
- std::list<State> list;
- State state;
- Mediator_Ifc* Mediator;
- public:
- virtual void Init() = 0;//初始化状态
- virtual void Leave() = 0;//卸载状态
- virtual void Run() = 0;//处理信息
- virtual State Reason() {
- for (auto t : list) {
- State temp = Mediator->Trans(state, t);
- if (temp != State::None) {
- return temp;
- }
- }
- return State::None;
- }
- virtual State GetState() { return state; }
- };
-
- class IdleState :public State_Ifc {
- //....重写
- };
-
- class PatrolState :public State_Ifc {
- //....重写
- };
-
- class PathState :public State_Ifc {
- //....重写
- };
-
- class AttackState :public State_Ifc {
- //....重写
- };
-
-
- class MediatorCenter :public Mediator_Ifc {
- State Trans(State stateS, State stateE) {
- //...实现
- }
- };
-
- class StateSystem {
- Mediator_Ifc* Mediator;
- State_Ifc* Current;//当前的状态
- std::unordered_map<State, State_Ifc*> map;
- //
- public:
- void UpData() {
- Current->Run();
- }
- void Trans() {
- State temp = Current->Reason();
- if (temp != State::None) {
- Current->Leave();
- Current = map[temp];
- Current->Init();
- }
- }
- };
这样就可以了。
总之一句话:状态机模式是处理一个类在内部状态改变的时候,其方法处理信息的模式也会改变;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。