现在的位置: 首页 > 综合 > 正文

武侠-event

2013年01月02日 ⁄ 综合 ⁄ 共 5618字 ⁄ 字号 评论关闭

一 武侠的event是个比较强的系统,个人感觉也是做的比较好的,结合lua使用起来很不错

二 实现

1 定义结构

 

struct EVENT_DEFINE
{
    typedef std::list
< std::pair< FUNC_EVENT_HANDLE, UINT > > REGISTER_STRUCT;

    GAME_EVENT_ID        idEvent;
    LPCTSTR                szEvent;
    BOOL                delayProcess;
    REGISTER_STRUCT        listFuncNotify;
};

struct EVENT
{
    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注册接口

 

INT CUIWindowItem::LUA_RegisterEvent(LuaPlus::LuaState* pState)
{
    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 添加处理事件

 

VOID CEventSystem::PushEvent(STRING& eventName, LPCTSTR szArg0, LPCTSTR szArg1, INT iArg2, INT iArg3)
{
    
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);
}

 
void CEventSystem::_PushEvent(const EVENT& 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 执行事件

 

VOID CEventSystem::ProcessAllEvent(VOID)
{
    
// 处理慢速队列
    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();
}

void CEventSystem::_ProcessEvent(const EVENT& event)
{
    
// 查找事件定义
    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调用

 

VOID WINAPI    CUIWindowItem::_OnGameEvent(const EVENT* pEvent, UINT dwOwnerData)
{
    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, "\"%s\"", pEvent->pEventDef->szEvent);

    pWinItem->m_pScriptEnv->DoFunction(szFunctionName, szFunctionParam);
}

 

抱歉!评论已关闭.