【个人YY--游戏中状态切换的实现模型】

来源:互联网 发布:企业软件防火墙排名 编辑:程序博客网 时间:2024/04/30 22:11

以下摘自【设计模式精解(GoF 23种设计解析附C++实现源码)】中关于状态机模式的介绍

      有限状态自动机(FSM)也是一个典型的状态不同,对输入有不同的响应(状态转移)。通常我们在实现这类系统会使用到很多的Switch/Case语句,Case某种状态,发生什么动作,Case另外一种状态,则发生另外一种状态。但是这种实现方式至少有以下两个问题:
      1)当状态数目不是很多的时候,Switch/Case可能可以搞定。但是当状态数目很多的时候(实际系统中也正是如此),维护一大组的Switch/Case语句将是一件异常困难并且容易出错的事情。
      2)状态逻辑和动作实现没有分离。在很多的系统实现中,动作的实现代码直接写在状态的逻辑当中。这带来的后果就是系统的扩展性和维护得不到保证。
State模式就是被用来解决上面列出的两个问题的,在State模式中我们将状态逻辑和动作实现进行分离。当一个操作中要维护大量的case分支语句,并且这些分支依赖于对象的状态。State模式将每一个分支都封装到独立的类中。

在这里【设计模式精解(GoF 23种设计解析附C++实现源码)】中的代码那样,我只是解释一个模型,实现一个模型,用栈来管理游戏状态。你可以称呼它为游戏状态管理栈等。
说明:
由于考虑到游戏中的状态管理一般只有一个,故这里采用单键模式模型。
由于考虑到会增加复杂度,这里不考虑模板(按道理应该采用模板,以增加代码可重用性,当然,用了模板就不再是纯单键模式了)

好了,老样子,上代码

先看看定义代码
头文件STATEMANAGER.H

 1//********************************************************************
 2//    STATEMANAGER.H    文件注释
 3//    文件名  :    STATEMANAGER.H
 4//    文件路径:    J:/CODING/游戏引擎/STATEMANAGER/
 5//    作者    :    RIPPLE
 6//    创建时间:    2009/10/3 13:44
 7//    文件描述:    游戏状态管理栈类声明
 8//*********************************************************************
 9
10#ifndef _H_STATEMANGER_H_
11#define _H_STATEMANGER_H_
12namespace ripple
13{
14    //********************************************************************
15    //    CStateManager    类注释
16    //    类名    :    CStateManager
17    //  基类名称:    NULL
18    //  命名空间:    ripple
19    //    作者    :    RIPPLE
20    //    创建时间:    2009/10/3 13:45
21    //    类描述  :    游戏状态管理类。一般游戏只会有一个状态管理,故采用单键模式管理
22    //*********************************************************************
23
24    class CStateManager
25    {
26    public:    
27        static CStateManager& getSingleton();        //返回引用,这步至关重要。
28        static CStateManager* getSingletonPtr();    //返回单键指针
29        
30        virtual ~CStateManager();
31
32        //定义状态调用函数指针类型
33        typedef void (*StateCallFunc)();
34
35        //定义状态结构
36        typedef struct tagState
37        {    
38            tagState()                
39            {
40                this->Update = NULL;
41                this->Next = NULL;
42            }

43            StateCallFunc Update;    //各个状态调用的函数指针
44            tagState* Next;            //下个函数状态的地址(如果有的话)
45        }
STATE;
46
47        void Push(StateCallFunc func);    //插入一个状态
48        BOOL Pop();                        //弹出一个状态
49        BOOL Process();                    //执行栈顶状态的更新函数
50
51    private:
52        CStateManager();
53        STATE* mp_TopState;
54        static CStateManager* ms_Singleton; 
55    }
;
56
57}

58#endif


对应的实现,源文件STATEMANAGER.CPP

 1//********************************************************************
 2//    STATEMANAGER.CPP    文件注释
 3//    文件名  :    STATEMANAGER.CPP
 4//    文件路径:    J:/CODING/游戏引擎/STATEMANAGER/
 5//    作者    :    RIPPLE
 6//    创建时间:    2009/10/3 13:47
 7//    文件描述:    CSteteManager游戏状态管理类实现
 8//*********************************************************************
 9
10#include <windows.h>
11#include "StateManager.h"
12//引用ripple命名空间
13using namespace ripple;
14//初始化静态指针
15CStateManager* CStateManager::ms_Singleton = NULL;
16//返回单键引用,必须返回引用,否则,会在返回时复制一次对象,将导致出错
17CStateManager& CStateManager::getSingleton()
18{
19    if (NULL == CStateManager::ms_Singleton)
20    {
21        new CStateManager();
22    }

23    return *CStateManager::ms_Singleton;
24}

25//返回单键指针
26CStateManager* CStateManager::getSingletonPtr()
27{
28    if (NULL == CStateManager::ms_Singleton)
29    {
30        new CStateManager();
31    }

32    return CStateManager::ms_Singleton;
33}

34//构造函数
35CStateManager::CStateManager()
36{
37    this->mp_TopState = NULL;
38    CStateManager::ms_Singleton = this;
39}

40//析构函数
41CStateManager::~CStateManager()
42{
43    STATE* tmp;
44    while ((tmp = this->mp_TopState) != NULL)
45    {
46        this->mp_TopState = this->mp_TopState->Next;
47        delete tmp;
48    }

49    if (NULL != CStateManager::ms_Singleton)
50    {
51        delete CStateManager::ms_Singleton;
52        CStateManager::ms_Singleton = NULL;
53    }

54}

55//插入一个状态
56void CStateManager::Push(StateCallFunc func)
57{
58    if(NULL != func)
59    {
60        STATE* tmp = new STATE;
61        tmp->Next = this->mp_TopState;
62        tmp->Update = func;
63        this->mp_TopState = tmp;
64    }

65}

66//弹出一个状态
67BOOL CStateManager::Pop()
68{
69    STATE* tmp = this->mp_TopState;
70    if (NULL != tmp)
71    {
72        this->mp_TopState = this->mp_TopState->Next;
73        delete tmp;
74    }

75
76    if (NULL == this->mp_TopState)
77    {
78        return FALSE;
79    }

80
81    return TRUE;
82}

83//执行栈顶状态的更新函数
84BOOL CStateManager::Process()
85{
86    if (NULL != this->mp_TopState)
87    {
88        this->mp_TopState->Update();
89        return TRUE;
90    }

91    return FALSE;
92}

测试代码 TEST.CPP

 1//********************************************************************
 2//    TEST.CPP    文件注释
 3//    文件名  :    TEST.CPP
 4//    文件路径:    J:/CODING/游戏引擎/STATEMANAGER/
 5//    作者    :    RIPPLE
 6//    创建时间:    2009/10/3 13:59
 7//    文件描述:    测试CStateManager类是否可以正常使用
 8//*********************************************************************
 9
10#include <iostream>
11#include <Windows.h>
12#include "StateManager.h"
13using namespace std;
14using namespace ripple;
15//分别定义三个函数,在具体实现时,可以是个状态对象之类的。
16//每个函数中都会将自己弹出,已使得其他函数有机会执行
17void fun1()
18{
19    cout<<"call fun1"<<endl;
20    CStateManager::getSingleton().Pop();
21}

22void fun2()
23{
24    cout<<"call fun2"<<endl;
25    CStateManager::getSingleton().Pop();
26}

27
28void fun3()
29{
30    cout<<"call fun3"<<endl;
31    CStateManager::getSingleton().Pop();
32}

33
34
35int main()
36{
37    //将三个函数压入栈内
38    //使用指针
39    CStateManager::getSingletonPtr()->Push(fun1);
40    //使用引用
41    CStateManager::getSingleton().Push(fun2);
42    //使用指针
43    CStateManager::getSingletonPtr()->Push(fun3);
44    //循环调用,当栈空是返回FALSE
45    while (FALSE != CStateManager::getSingleton().Process())
46    {
47    }

48    return 0;
49}


运行结果:

1call fun3
2call fun2
3call fun1
4请按任意键继续. .


这只是个模型,大家可以在此基础上,编写更多更灵活的代码。

版权所有,转载请注明出处!
如果对本文有不解之处,可以联系本人(yeduwu@163.com)。或在此博客留言。
有不同见解者,亦可以通过上述通道联系本人。。欢迎指教。