如前所述,应用是游戏辅助工具的逻辑模块。它将遵循某一需求,通过引擎层和工具包提供的接口获取游戏状态和数据,根据这些状态和数据,产生相应的策略,并控制游戏和操作游戏中的角色,从而完成赋予游戏辅助工具的任务和使命。
在游戏辅助工具中,应用模块是最能体现需求的部分,例如我们容易想到的打怪应用,挖矿应用,采药应用,跑商应用,做某一任务的应用等等。大家可以看到,对用户来说是应用模块决定了游戏辅助工具的功能和价值。
如果没有应用,引擎提供的一个个接口简直就是英雄无用武之地。正是应用通过有机的组织和调用引擎提供的这些接口,才发挥出了它们的巨大价值。
对于游戏辅助工具,任何一个应用都可以抽象为一个状态机。应用在自己的生命周期内,总是在根据游戏的状态变换着自己的状态,在每个自己的状态中又反过来控制着游戏的状态。所以,如何控制辅助工具的各种状态是应用模块的重要任务。
在游戏帮手平台上,应用管理器是应用模块的载体。
你需要把应用模块放到应用管理器的工程中实现,它将与应用管理器编译链接成同一个动态库。一个应用管理器中可以包含多个应用模块,它负责管理所有应用模块的生命周期和消息路由。参考: 系统架构。
所以在创建应用模块之前我们首先要创建一个应用管理器。
与主控引擎或嵌入引擎相似,一个应用管理器的实体也是一个动态库,它可以在主控容器上动态安装和卸载。你可以在配置文件GameBsPlatform.xml中把它添加到主控容器中,并且可以设置为是否自动安装。详细内容请参考: 产品配置文件。
应用管理器的基类CGmbsAppManager与主控引擎或嵌入引擎的基类一样,也是由类CGmbsEngine继承而来。
同样,有三种方法可以创建一个GameBs应用管理器工程,下面只介绍怎样通过GameBs工程向导创建应用管理器的方法,另外两种方法请参考: 创建引擎工程。
使用GameBs的工程向导创建应用管理器是最常用和有效的方法,下面介绍其操作:
新建项目 --> 选择GameBsAppManager AppWizard --> 选择路径(如:D:\source) --> 输入项目名TestAppManager --> 点OK按钮完成项目创建,如图1所示。

图1
与创建引擎时的情况类似,直接编译会出现一些链接错误,需要把以下库文件配置到应用管理器工程的依赖库中,
CnttUtil.lib GmbsEngine.lib wtermin.lib
在VC6.0中,如何配置工程的依赖库?请参考: 配置工程的依赖库 。
你也许已经发现,与引擎的依赖库相比,应用管理器多了一个CnttUtil.lib。CnttUtil.lib是一个工具包,其中最重要的组件是它所提供的树形状态机实现,它将是构建应用模块的基础。
#include "stdafx.h"
#include "wtermin.h"
#include "TestAppManager.h"
#include "HelloWorld.h"//Provide the external interface for container to retrieve engine instance (also add it into .def)
static CTestAppManager *m_pAppManager = NULL;
void* Gmbs_GetEngineInstance(LPCSTR strEngineName)
{
if (m_pAppManager != NULL)
return m_pAppManager;
m_pAppManager = new CTestAppManager("TestAppManager");
return m_pAppManager;
}CTestAppManager::CTestAppManager(LPCSTR lpEngineName)
: CGmbsAppManager(lpEngineName)
{
m_hHelloworldFsm = NULL;
}CTestAppManager::~CTestAppManager()
{
}BOOL CTestAppManager::InitInstance()
{
CGmbsAppManager::InitInstance();
//add your code below
return TRUE;
}int CTestAppManager::ExitInstance()
{
//add your code below
if (m_hHelloworldFsm != NULL)
{
HelloWorld_Stop(m_hHelloworldFsm);
m_hHelloworldFsm = NULL;
}
return CGmbsAppManager::ExitInstance();
}//engine message handler
int CTestAppManager::OnMessageProc(LPCSTR lpMsgName, PBYTE pMsgData, int nMsgDataLen, BOOL bNeedReturn)
{
return 0;
}//user message handler
int CTestAppManager::OnUserMessageProc(LPCSTR lpMsgName, PBYTE pMsgData, int nDataLen)
{
if (strcmp(lpMsgName, "StartApp") == 0)
{
if (m_hHelloworldFsm == NULL)
m_hHelloworldFsm = HelloWorld_Start(this);
}
else if (strcmp(lpMsgName, "StopApp") == 0)
{
if (m_hHelloworldFsm != NULL)
{
HelloWorld_Stop(m_hHelloworldFsm);
m_hHelloworldFsm = NULL;
}
}
else if (strcmp(lpMsgName, "SendEventToApp") == 0)
{
if (m_hHelloworldFsm != NULL)
{
cntt_fsm_PostEvent(m_hHelloworldFsm, EV_HELLOWORLD_TESTEVENT1, 0, 0);
}
}
return 0;
}
在该工程中,包含一个应用管理器CTestAppManager和一个状态机HelloWorld。
在应用管理器中,定义了一个状态机句柄m_hHelloworldFsm,并在构造函数中赋为空值。
在用户消息处理函数CTestAppManager::OnUserMessageProc中,
(1)当收到消息"StartApp"时,启动状态机HelloWorld,并保存返回句柄到m_hHelloworldFsm中。
(2)当收到消息"StopApp"时,如果状态机HelloWorld在运行,则关闭HelloWorld。
(3)当收到消息"SendEventToApp"时,发送消息EV_HELLOWORLD_TESTEVENT1给HelloWorld状态机。
状态机HelloWorld是在源文件HelloWorld.cpp,HelloWorld.h中实现的。在HelloWorld.h中包含了头文件cntt_fsm.h,里面提供了状态机的接口函数。
在HelloWorld中定义了两个状态:
enum
{
STATE1,
STATE2,
};
它们的模式时间分别设为为3秒和5秒,参考状态机启动函数:
//启动函数
CNTT_HANDLE HelloWorld_Start(void *pEngine)
{
CNTT_HANDLE hMachineHandle = FSM_CREATEMACHINE(m_statetb, m_transtb);
cntt_fsm_SetModeTime(hMachineHandle, STATE1, 3000);
cntt_fsm_SetModeTime(hMachineHandle, STATE2, 5000);
cntt_fsm_StartMachine(hMachineHandle);
return hMachineHandle;
}
状态STATE1在onMode的代码如下,
static CNTT_RESULT STATE1_onMode(CNTT_HANDLE smachineHandle, cntt_state state)
{
WT_Trace("------------------------STATE1_onMode------------------------\n");cntt_fsm_Wait(1000);
WT_Trace("------------------------Wait 1000ms--------------------------\n");
return CNTT_FSMR_SUCCESS;
}
先打印一行文本,然后等待1秒钟,再打印一行文本。
状态STATE2在onMode的代码如下,
static CNTT_RESULT STATE2_onMode(CNTT_HANDLE smachineHandle, cntt_state state)
{
WT_Trace("------------------------STATE2_onMode------------------------\n");cntt_fsm_PostEvent(smachineHandle, EV_HELLOWORLD_TESTEVENT2, 0, 0);
//cntt_fsm_SwitchState(smachineHandle, STATE1); //equal to the above line
return CNTT_FSMR_SUCCESS;
}
先打印一行文本,然后发出事件EV_HELLOWORLD_TESTEVENT2给本状态机,根据状态机的状态迁移表,收到该事件后,状态机将从状态STATE2切换到STATE1。该状态机迁移表如下,
//状态迁移表
static const FSM_STRANSFER_T m_transtb[] =
{
FSM_STRANS(STATE1, EV_HELLOWORLD_TESTEVENT1, STATE2, STATE1_TestEvent1_onAction ),
FSM_STRANS(STATE2, EV_HELLOWORLD_TESTEVENT2, STATE1, STATE2_TestEvent2_onAction ),
};
从迁移表中还可以看到,当状态机收到EV_HELLOWORLD_TESTEVENT1事件时,将从状态STATE1转换到STATE2,同时在事件函数STATE1_TestEvent1_onAction中打印一行文本。稍后在产品装配完成后,我们将做一个测试,通过用户界面来触发这个事件。
该工程编译成功后,会在Debug目录下生成一个动态库TestAppManager.dll,它是包含了一个应用模块HelloWorld的应用管理器,将在平台装配阶段被安装到主控容器中。