一 武侠的event是个比较强的系统,个人感觉也是做的比较好的,结合lua使用起来很不错
二 实现
1 定义结构
{
typedef std::list< std::pair< FUNC_EVENT_HANDLE, UINT > > REGISTER_STRUCT;
GAME_EVENT_ID idEvent;
LPCTSTR szEvent;
BOOL delayProcess;
REGISTER_STRUCT listFuncNotify;
};
{
EVENT_DEFINE* pEventDef;
std::vector<STRING> vArg;
bool operator == (const EVENT& other)
{
if(other.pEventDef != pEventDef)
return false;
if(other.vArg.size() != vArg.size())
return false;
for(register size_t i=0; i<vArg.size(); i++)
{
if(vArg[i] != other.vArg[i])
return false;
}
return true;
}
};
变量
//通过事件名称检索表
std::map< STRING, EVENT_DEFINE* > m_mapEventIndex_AsName;
//通过事件ID检索表
std::map< GAME_EVENT_ID, EVENT_DEFINE* > m_mapEventIndex_AsID;
保存了所有注册的事件,可以通过ID和Name索引
//事件队列
std::list< EVENT > m_queueEvent;
//慢速处理队列, 每桢一个,防止过多的消息同时涌现
std::list< EVENT > m_delayQueueEvent;
保存了当前需要处理的事件
2 lua注册接口
{
LuaStack args(pState);
if(!(args[2].IsString()))
return 0;
if(m_bLayoutLoaded)
{
KLThrow("%s Must register event in \"***PreLoad\" Function ", m_strWindowName.c_str());
}
STRING strEventName
= args[2].GetString();g_pEventSys
->RegisterEventHandle(strEventName, _OnGameEvent, (DWORD)(DWORD_PTR)this);return 0;
}
VOID CEventSystem::RegisterEventHandle(const STRING& nameEvent, FUNC_EVENT_HANDLE funHandle, UINT uOwnerData)
{
if(!funHandle)
return;
EVENT_DEFINE
* pEvent = m_mapEventIndex_AsName[nameEvent];if(!pEvent)
return;
pEvent
->listFuncNotify.push_back( std::make_pair(funHandle, uOwnerData) );}
3 添加处理事件
{
if(m_mapEventIndex_AsName.find(eventName) == m_mapEventIndex_AsName.end()) return;
EVENT
event;event.pEventDef=m_mapEventIndex_AsName[eventName];
event.vArg.push_back(szArg0);
event.vArg.push_back(szArg1);
CHAR szTemp[
32];_snprintf(szTemp, 32, "%d", iArg2);
event.vArg.push_back(szTemp);
_snprintf(szTemp, 32, "%d", iArg3);
event.vArg.push_back(szTemp);
_PushEvent(
event);}
{
if(!event.pEventDef)
return;
// 如果是慢速处理的事件
if(event.pEventDef->delayProcess)
{
m_delayQueueEvent.push_back(event);
}
else
{
m_queueEvent.push_back(event);
}
}
std::vector< STRING > vParam;
CHAR szTemp[MAX_PATH];
_snprintf(szTemp, MAX_PATH,
"%d", pObject->GetID());vParam.push_back(szTemp);
vParam.push_back(
"distance");_snprintf(szTemp, MAX_PATH,
"%.3f", fDistance);vParam.push_back(szTemp);
CEventSystem::GetMe()
->PushEvent(GE_OBJECT_CARED_EVENT, vParam);
4 执行事件
{
// 处理慢速队列
if(!(m_delayQueueEvent.empty()))
{
const UINT WORK_STEP = 2;
UINT nTickCountNow = CGameProcedure::s_pTimeSystem->GetTickCount();
UINT nTickCountStep = CGameProcedure::s_pTimeSystem->CalSubTime(m_dwLastTickCount, nTickCountNow);
if(nTickCountStep >= WORK_STEP)
{
m_dwLastTickCount = nTickCountNow;
const EVENT& event = *(m_delayQueueEvent.begin());
_ProcessEvent(
event); m_delayQueueEvent.erase(m_delayQueueEvent.begin());
}
}
register std::list
< EVENT >::iterator it;for(it=m_queueEvent.begin(); it!=m_queueEvent.end(); it++)
{
const EVENT& event = *it;
// 检测是否有同样的Event已经被处理
bool bMultiPushed = false;
for(register std::list< EVENT >::iterator itPrev=m_queueEvent.begin(); itPrev !=it; itPrev++)
{
if(*itPrev == *it)
{
bMultiPushed = true;
break;
}
}
if(bMultiPushed)
continue;
_ProcessEvent(
event);}
m_queueEvent.clear();
}
{
// 查找事件定义
EVENT_DEFINE* pEventDef = event.pEventDef;
if(!pEventDef)
return;
// 调用处理函数
if(!(pEventDef->listFuncNotify.empty()))
{
EVENT_DEFINE::REGISTER_STRUCT::iterator it;
for(it=pEventDef->listFuncNotify.begin(); it!=pEventDef->listFuncNotify.end(); it++)
{
if((*it).first)
((*it).first)(&event, (*it).second);
}
}
}
另外有一个回调函数,执行具体的lua调用
{
KLAssert(pEvent);
//--------------------------------------------------------
// 分发
CUIWindowItem* pWinItem = (CUIWindowItem*)(DWORD_PTR)(dwOwnerData);
if(!pWinItem)
return;
// 加载
if(!(pWinItem->m_bLayoutLoaded))
{
pWinItem->LoadWindow();
}
//--------------------------------------------------------
// 参数
for(INT i=0; i<(INT)pEvent->vArg.size(); i++)
{
CHAR szTemp[MAX_PATH];
_snprintf(szTemp, MAX_PATH, "arg%d", i);
g_pScriptSys->GetLuaState()->GetGlobals().SetString(szTemp, pEvent->vArg[i].c_str());
}
//--------------------------------------------------------
// 调用脚本
CHAR szFunctionName[MAX_PATH];
_snprintf(szFunctionName, MAX_PATH, "%s_OnEvent", pWinItem->m_strWindowName.c_str());
CHAR szFunctionParam[MAX_PATH];
_snprintf(szFunctionParam, MAX_PATH,
pWinItem
->m_pScriptEnv->DoFunction(szFunctionName, szFunctionParam);}