本篇是的
創建游戲內核(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)