【静态变量的初始化之一】

来源:互联网 发布:网络视频测试地址 编辑:程序博客网 时间:2024/05/23 21:53
CGameProcedure::InitStaticMemeber首先创建随机数发生器,然后调用g_theKernel.ReisgerClass来注册各种管理器及子系统。代码如下:
 

VOID CGameProcedure::InitStaticMemeber(VOID)
{
     //初始化随即变量种子
     srand( (unsigned)timeGetTime() );

    g_theKernel.ReisgerClass(GETCLASS(tNode));// 注册本地类
    g_theKernel.ReisgerClass(GETCLASS(CNetManager));//网络管理器
     g_theKernel.ReisgerClass(GETCLASS(CWorldManager)); //场景管理器
    

     //物体管理器
    g_theKernel.ReisgerClass(GETCLASS(CObjectManager));
    g_theKernel.ReisgerClass(GETCLASS(CObject));
    g_theKernel.ReisgerClass(GETCLASS(CObject_Surface));
    g_theKernel.ReisgerClass(GETCLASS(CObject_Effect));
    g_theKernel.ReisgerClass(GETCLASS(CObject_Bullet));
    //g_theKernel.ReisgerClass(GETCLASS(CObject_SkillObj));
    g_theKernel.ReisgerClass(GETCLASS(CObject_Special));
    g_theKernel.ReisgerClass(GETCLASS(CObject_Map));
    g_theKernel.ReisgerClass(GETCLASS(CObject_Static));
    g_theKernel.ReisgerClass(GETCLASS(CObject_Building));
    g_theKernel.ReisgerClass(GETCLASS(CObject_Dynamic));
    g_theKernel.ReisgerClass(GETCLASS(CObject_Character));
    g_theKernel.ReisgerClass(GETCLASS(CObject_PlayerMySelf));
    g_theKernel.ReisgerClass(GETCLASS(CObject_PlayerNPC));
    g_theKernel.ReisgerClass(GETCLASS(CObject_PlayerOther));
    g_theKernel.ReisgerClass(GETCLASS(CObject_ProjTex));
    g_theKernel.ReisgerClass(GETCLASS(CObject_ProjTex_MouseTarget));
    g_theKernel.ReisgerClass(GETCLASS(CObject_ProjTex_AuraDure));
    g_theKernel.ReisgerClass(GETCLASS(CTripperObject_Transport));
    g_theKernel.ReisgerClass(GETCLASS(CTripperObject_ItemBox));
    g_theKernel.ReisgerClass(GETCLASS(CTripperObject_Resource));
    g_theKernel.ReisgerClass(GETCLASS(CTripperObject_Platform));

    g_theKernel.ReisgerClass(GETCLASS(CInputSystem));//输入管理器
    g_theKernel.ReisgerClass(GETCLASS(tTimeSystem));//计时器
    g_theKernel.ReisgerClass(GETCLASS(CSoundSystemFMod));//声音管理器
   g_theKernel.ReisgerClass(GETCLASS(CDataBaseSystem));//数据库管理器
   g_theKernel.ReisgerClass(GETCLASS(CVariableSystem));//变量管理器
   g_theKernel.ReisgerClass(GETCLASS(CGameInterface));//UI操作接口
    g_theKernel.ReisgerClass(GETCLASS(CUIDataPool));//UI数据池
    g_theKernel.ReisgerClass(GETCLASS(CDataPool));
    g_theKernel.ReisgerClass(GETCLASS(CCursorMng));//UI鼠标操作类
    g_theKernel.ReisgerClass(GETCLASS(CScriptSystem));//脚本系统
    g_theKernel.ReisgerClass(GETCLASS(CEventSystem));//事件系统
    g_theKernel.ReisgerClass(GETCLASS(CActionSystem));//操作管理
  g_theKernel.ReisgerClass(GETCLASS(CFakeObjSystem));//UI模型显示管理
    g_theKernel.ReisgerClass(GETCLASS(CHelperSystem));//外接帮助系统
  ...//省略

}

 由上面的代码可以看到,g_theKernel是存放游戏核心数据的一个全局变量,它是在Global.cpp中声明的。我们来看一下代码:
 

#include "StdAfx.h"
#include "Global.h"

tKernel g_theKernel;//数据核心
HWND g_hMainWnd = NULL;//主窗口
HINSTANCE g_hInstance = NULL;//当前主程序模块句柄
const CHAR VERSION_INFO[] = "0.0.0005";//当前版本号
const CHAR        GAME_TITLE[]        ="武侠世界";//标题

可以看到,除了数据核心之外,还有主窗口句柄、主程序模块句柄、主窗口标题以及版本信息等全局变量。g_theKernel在这声明为tKernel类。

  我们先来了解一下tKernel类的成员变量。它定义在TDKernel.h文件中。

protected:

 std::map< STRING, tClass* >    m_ClassMap;//全局定义类检索表
 tClass*  m_pFirstClass;  //类检索表中第一个类
 tNode m_theRoot;   //根节点

//插件信息
   struct PLUGIN_INFO
    {
        HMODULE            hModule;
        STRING            strPluginFile;
        FUNC_DLLINIT    pfnDllInit;
        FUNC_DLLRELEASE pfnDllRelease;
    };
 std::vector< PLUGIN_INFO >    m_vAllPlugin;//所有插件

static tKernel* s_pMe;//指向自己的指针


由上面的代码可以看出,tKernel类存放了三种数据,一是全局类的信息,二是插件的信息,三是指向自己的指针。我们重点看一下前两种。由于插件信息的数据结构比较简单,我们先来看一下。PLUGIN_INFO结构中记录了dll句柄,dll文件名,以及dll初始化以及释放的两个函数指针。所有的插件,都以PLUGIN_INFO的结构存放在vector容器之中。

  至于全局类信息的存储,利用了tClass和tNode两种类型以及类名到类指针的映射表std::map< STRING, tClass* >。

class tNode
{
public:
    tNode(VOID);
    tNode(LPCTSTR szName);
    virtual ~tNode() { Release(); }

virtual INT  GetChildNum(VOID) const    

{ return (INT)m_ChildBuf.size(); }   //返回子节点数目
virtual const STRING& GetNodeName(VOID) const    

{ return m_strName; }               //返回节点名

virtual std::list< tNode* >&  GetChildBuf(VOID)        

{ return m_ChildBuf; }             //返回子节点列表

virtual tNode* GetParent(VOID)            

{ return m_pParentNode; }              //返回父节点

virtual VOID  Initial(VOID*) { }      //节点初始化
virtual VOID  Tick(VOID);              //逻辑轮循函数

//查找子节点,如果没有找到,返回NULL;
virtual tNode*    LookUpChild(LPCTSTR szNodeName);
virtual VOID AddChild(tNode *pNewNode);//添加子节点到该节点上

//删除某个子节点,当该节点存在时返回TRUE,否则返回FALSE
virtual BOOL EraseChild(tNode* pNode);
virtual VOID EraseAllChild( VOID ); //删除所有子节点
virtual VOID Release(VOID); //释放自己所所拥有的资源

protected:
    typedef std::list< tNode * > ChildList;
    STRING  m_strName;//节点名
    ChildList  m_ChildBuf;//子节点列表
    tNode* m_pParentNode; //父节点指针
    friend struct tClass;
    WX_DECLARE_DYNAMIC(tNode);
};

  tNode类里有一个非常重要的宏WX_DECLARE_DYNAMIC。这个宏,在很多管理类当中都使用了。它与WX_IMPLEMENT_DYNAMIC搭配使用,动态的声明并定义tClass类型的成员对象。

//类定义声明宏

#define WX_DECLARE_DYNAMIC(className) \
public: \
    static tClass                m_class##className; \
    virtual const tClass*        GetClass(VOID) const; \
    static tNode* __stdcall    CreateObject();

c++在宏展开的时候##会作为连接操作。\表示下一行也是宏的展开,只不过为了方便阅读换行的。这下读者应该明白它展开后的样子了。为了直观一些展开WX_DECLARE_DYNAMIC(tNode)。


class tNode
{
 public:
   static tClass m_classtNode;
   virtual const tClass* GetClass(VOID) const;
   static tNode* __stdcall CreateObject();
}


这里声明的类于函数在TDNode.cpp一开始便使用WX_IMPLEMENT_DYNAMIC(tNode, NULL)进行了实现。WX_IMPLEMENT_DYNAMIC宏是如下定义的:

//类定义实现宏
#define WX_IMPLEMENT_DYNAMIC(className, baseClass) \
    static TCHAR sz##className[] = _T(#className); \
    tClass className::m_class##className = \
    { sz##className, sizeof(className), className::CreateObject, baseClass, NULL }; \
    const tClass* className::GetClass() const \
        { return &className::m_class##className; } \
    tNode* className::CreateObject() \
        { return new className; }


 展开WX_IMPLEMENT_DYNAMIC(tNode, NULL);我们得到:

static TCHAR sztNode[]=_T("tNode");


tClass tNode::m_classtNode=

{sztNode,

 sizeof(tNode),

tNode::CreateObject,

NULL,

NULL};


const tClass* tNode::GetClass()const
{ return &tNode::m_classtNode;}


tNode* tNode::CreateObject()
{ return new tNode;}

我们返回游戏的执行流程,看一下g_theKernel.ReisgerClass如何注册各种管理器及子系统。我们以
g_theKernel.ReisgerClass(GETCLASS(tNode)); 这句为例。首先,展开GETCLASS宏。
 

//根据类名取得定义类
#define GETCLASS(className) (&className::m_class##className)

我们得到语句:

g_theKernel.ReisgerClass(&tNode::m_classtNode);


tNode::m_classtNode是我们在tNode类中通过WX_DECLARE_DYNAMIC与WX_IMPLEMENT_DYNAMIC声明并实现的。然后我们看一下ReisgerClass所做的工作:

//将某个类注册到全局类检索表函数

VOID tKernel::ReisgerClass(tClass* pNewClass)
{
    TDAssert(pNewClass);
    if(m_ClassMap[STRING(pNewClass->szClassName)] != NULL)
    {
        TDThrow(_T("Multi register class:%s"), pNewClass->szClassName);
    }
    pNewClass->pNextClass = m_pFirstClass;
    m_pFirstClass = pNewClass;
    //将新的类加入到类检索表
    (m_ClassMap)[pNewClass->szClassName] = pNewClass;
}

它首先检查一下,在类检索表中是否已经存在这个类,如果没有注册过,把这个类链入m_pFirstClass指向的链表开始之处。最后更新类检索表m_ClassMap.