消息處理: 我把Quake的消息分為兩類,一種是常用輸入設備產生的消息,譬如KeyBoard,Mouse,JoyStick等. 另一種就是網絡或本地傳輸數據包時引發的消息. 引擎中Com_EventLoop()函數負責將抓獲到的消息根據事件的類型分發給對應的處理函數, Com_GetEvent()可以從com_eventQueue和eventqueue數組隊列中獲取到所有的未處理消息, typedef enum sysEventType_s { SE_NONE, // evTime is still valid SE_KEY, // evValue is a key code, evValue2 is the down flag SE_CHAR, // evValue is an ascii char SE_MOUSE, // evValue and evValue2 are reletive signed x / y moves SE_JOYSTICK_AXIS, // evValue is an axis number and evValue2 is the current state (-127 to 127) SE_CONSOLE, // evPtr is a char* SE_PACKET // evPtr is a netadr_t followed by data bytes to evPtrLength } sysEventType_t; typedef struct { int evTime; sysEventType_t evType; int evValue, evValue2; int evPtrLength; // bytes of data pointed to by evPtr, for journaling void *evPtr; // this must be manually freed if not NULL } sysEvent_t; static sysEvent_t com_eventQueue[COM_MAX_EVENTS]; static sysEvent_t eventqueue[SYS_MAX_EVENTS]; 從以上的聲明部分我們可以看到com_eventQueue和eventqueue其實就是一個sysEvent_t結構的數組. 這裡你可能要會問了,com_eventQueue裡面的數據又是從何而來的呢?當Com_GetEvent()函數發現com_eventQueue裡面沒有數據的時候,例如程序剛啟動時,它會調用Com_GetRealEvent()來蒐集未處理的消息.然後再從eventqueue中讀出事件.
Com_GetRealEvent()àSys_GetEvent()àSys_PumpEvents()
Sys_PumpEvents()使用消息循环體( while( PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE ) ) { if( !GetMessage( &msg, NULL, 0, 0 ) ) { Sys_Quit(); } TranslateMessage( &msg ); DispatchMessage( &msg ); }) 先将消息交由WndProc()处理,然后WndProc()再把诸如按键,鼠標移動等外部设备输入信息通过调用Sys_QueEvent()函数存储到全局队列eventqueue中。
另外Sys_PumpEvents()還會調用Sys_GetPacket(),將從Socket讀到的網絡數據也通過Sys_QueEvent()函数存放到eventqueue中. com_eventQueue隊列事件其實是通過Com_PushEvent()函數把eventqueue中的事件壓入到com_eventQueue中.Quake採用這種雙隊列的方式來保存消息. 
|