本篇是的
创建游戏内核(1)续篇,并且以
游戏程序流、状态处理机、进程管理器、数据包系统的实现中介绍的状态处理机的实现为基础。
新的状态管理器引入了两个概念:调用目的以及添加一个用户自定义的数据指针,此指针指向STATE_MANAGER中的函数。调用目的是一个状态被调用的原因,“目的(purpose)”可以是INIT_PURPOSE(表明要使用函数,需要事先进行准备)、FRAME_PURPOSE(处理单独的一帧)或SHUTDOWN_PURPOSE(在处理完成时释放所有资源)。
点击下载源码和工程
以下是该类的定义:
enum PURPOSE
{
NO_PURPOSE = 0,
INIT_PURPOSE,
SHUTDOWN_PURPOSE,
FRAME_PURPOSE
};
typedef void (*FUNC_PTR)(void* func_ptr, long purpose);
//==========================================================================
// Defines for state manager.
//==========================================================================
class STATE_MANAGER
{
private:
struct STATE
{
FUNC_PTR func;
STATE* next;
STATE()
{
func = NULL;
next = NULL;
}
~STATE()
{
delete next;
next = NULL;
}
};
protected:
STATE* _state_parent;
public:
STATE_MANAGER();
~STATE_MANAGER();
void Push(FUNC_PTR func_ptr, void* data_ptr = NULL);
BOOL Pop(void* data_ptr = NULL);
void Pop_All(void* data_ptr = NULL);
BOOL Process(void* data_ptr = NULL);
};
接着是该类的实现:
//-----------------------------------------------------------------------------
// Constructor, initialize state pointer which pointer to parent state.
//-----------------------------------------------------------------------------
STATE_MANAGER::STATE_MANAGER()
{
_state_parent = NULL;
}
//-----------------------------------------------------------------------------
// Destructor, pop off all functions.
//-----------------------------------------------------------------------------
STATE_MANAGER::~STATE_MANAGER()
{
Pop_All();
}
//-----------------------------------------------------------------------------
// Push a function on to the stack.
//-----------------------------------------------------------------------------
void STATE_MANAGER::Push(FUNC_PTR func, void *data_ptr)
{
// don't push a NULL value
if(func != NULL)
{
// allocate a new state and push it on stack
STATE* state_ptr = new STATE();
state_ptr->func = func;
state_ptr->next = _state_parent;
_state_parent = state_ptr;
// call state with init purpose
state_ptr->func(data_ptr, INIT_PURPOSE);
}
}
//-----------------------------------------------------------------------------
// Pop a functoin off the stack.
//-----------------------------------------------------------------------------
BOOL STATE_MANAGER::Pop(void *data_ptr)
{
STATE* state_ptr;
// remove the head of stack (if any)
if((state_ptr = _state_parent) != NULL)
{
// first call with shutdown purpose
_state_parent->func(data_ptr, SHUTDOWN_PURPOSE);
_state_parent = state_ptr->next;
state_ptr->next = NULL;
delete state_ptr;
}
// return TRUE if more states exist, FALSE otherwise.
return (_state_parent != NULL);
}
//-----------------------------------------------------------------------------
// Pop all functions off the stack.
//-----------------------------------------------------------------------------
void STATE_MANAGER::Pop_All(void *data_ptr)
{
while(Pop(data_ptr) == TRUE)
;
}
//-----------------------------------------------------------------------------
// Process top-most function.
//-----------------------------------------------------------------------------
BOOL STATE_MANAGER::Process(void* data_ptr)
{
// return an error if no more states
if(_state_parent == NULL)
return FALSE;
// procress the top-most state
_state_parent->func(data_ptr, FRAME_PURPOSE);
return TRUE;
}
下面给出测试代码:
注意,加上一个用户自定义变量data_ptr是有根据的。因为在类中,必须将状态函数声明为静态(否则编译器会报错)。因此需要传递一个指向状态函数的指针,状态函数仍然是类的一部分,因此状态函数就可以使用指针自由地访问类的数据(甚至是私有数据)。
/*****************************************************************************
PURPOSE:
Test for class STATE_MANAGER.
*****************************************************************************/
#include "Core_System.h"
#pragma warning(disable : 4996)
class APP : public APPLICATION
{
private:
STATE_MANAGER _state_manager;
static void _Function1(void*, long);
static void _Function2(void*, long);
public:
BOOL Init()
{
_state_manager.Push(_Function1, this);
return TRUE;
}
};
void APP::_Function1(void* data_ptr, long purpose)
{
// get an instance pointer to APP
APP* app_inst = (APP*) data_ptr;
// if init purpose, show message box and push second function.
if(purpose == INIT_PURPOSE)
{
MessageBox(app_inst->Get_Hwnd(), "State1", "Message", MB_OK);
app_inst->_state_manager.Push(_Function2, app_inst);
return;
}
// if frame purpose, pop off function.
if(purpose == FRAME_PURPOSE)
app_inst->_state_manager.Pop(app_inst);
}
void APP::_Function2(void* data_ptr, long purpose)
{
APP* app_inst = (APP*) data_ptr;
if(purpose == FRAME_PURPOSE)
{
MessageBox(app_inst->Get_Hwnd(), "State 2", "Message", MB_OK);
app_inst->_state_manager.Pop(app_inst);
}
}
int PASCAL WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
APP app;
return app.Run();
}
运行截图:
阅读下篇:
创建游戏内核(3)