如何為我的遊戲實現一個UI系統,這個問題我想了很久,不過我現在可不像開始的時候那樣一點思路也沒有。如果你也被這個問題所困擾,我十分樂意與你分享這幾天來的學習成果。嘿嘿,我是不是有點得意忘形了?
在開始之前,我要提醒你,學而不思則惘。在看這篇文章的時候,請時刻保持頭腦清醒,如果有什麼不太明白的話,請停下一兩分鐘,好好想想,這篇文章可不是囫圇吞棗就能看懂的哦!此外這篇文章是建立在部分執行個體和猜測的基礎上的,可能存在著大量的不科學的想法和嚴重的錯誤,如果你在實踐的過程中出現了問題歡迎提問,如果你發現了其中的錯誤請你指出來,如果將來你發現被誤導了(當然我會儘力減小這種可能),請不要埋怨,因為是否繼續往下看是你自己的決定。
1、視窗
UI系統的表現形式是什嗎?在開始前我們有必要弄清這個問題。
我們需要對話方塊、按鈕、選項按鈕、複選按鈕、捲軸、下拉式清單……好了好了,想不到你一口氣竟能說出這麼多種視窗。是的,這些都是不同形式的視窗,UI系統正是靠著形形色色的視窗展示自己,請記住這一點。如果你還是不明白,就看一看MSDN中的Hierarchy Chart。
2、理解windows的UI系統
windows這樣一套經典的圖形作業系統,我如果不拿它做例子,實在是有點兒對不住比爾大叔啊。
視窗都是矩形的,不要跟我說不規則視窗,其實那也是一個矩形的,只不過有些地方沒有畫而已。既然是矩形,只要知道它的長和寬(Width,Height,有點兒不一樣是吧?windows裡叫寬和高),它就確定了。然後,你把它放在某個位置上,所以它又有了座標(xPos,yPos)。你的UI系統至少也要有這些資料,不然就沒法畫了。
然後是各式各樣的事件,當滑鼠經過的時候,按鈕變亮了;當你按下Alt+F的時候,彈出了一個菜單。不管在windows裡是哪個裝置驅動把這些資訊告訴了UI系統,我們的確需要它,不是嗎?
一個菜單被按下然後一個對話方塊彈了出來,是誰的結果?是滑鼠嗎?怎麼可能!當然是UI系統乾的。UI系統不僅要接受各種輸入裝置的資訊改變相應的外觀,它還要根據不同的操作產生訊息。菜單按下時,windows會主動地往訊息佇列裡發送一個WM_COMMAND訊息。至於對話方塊是否會彈出來,就要看你是否對這個訊息進行處理了。
還有別的什麼嗎?
當然有啦,只是我也不很清楚,畢竟才研究了三四天嘛。不過我可以告訴你是什麼:那麼多不同類型的視窗,windows是怎麼區分的?這個問題很關鍵啦,表單如何繪製,事件如何激發全都需要判斷的。比如說一個普通按鈕和一個選項按鈕,一個按下之後要彈起來,另一個要有一個圓點,明顯的不同。既然都是視窗,windows是怎麼做到的呢?我在winuser.h裡面看到了大量關於STYLE的宏,我猜是用了CASE判斷,可是為每一個視窗都作判斷也太麻煩了吧,還在研究中...
3、視窗類別的封裝
封裝是為了更好的使用,但不是必需的。就像使用MFC我們可以方便開發項目。(不要跟我討論你對MFC的感情,那是你自己的事)然而如果沒有他,只用SDK我們一樣可以完成上司的任務。但是為了方便我建議你這樣做,封裝你的視窗類別。我沒有對此作太多的研究,我想把更多的時間放到研究UI系統本身上。如果你想瞭解得更多,請看這裡http://blog.csdn.net/mythma
4、訊息映射及命令繞行
和封裝視窗類別一樣,這也只是一個輔助性的工作。這也是MFC的做法,如果你的遊戲不需要如此複雜的方法,或是你對此方法有成見的話就不要做了。也許,我真的有點偏離我的初衷,不像是在給我的遊戲實現一個UI系統了。如果你想為類似DOS的系統添加一個GUI的話,嘿嘿,X-Window那樣子的。按本文的UI系統做也許會有點小用。
對於訊息映射和命令繞行,我說不好,看了兩天《深入淺出MFC》,才稍微有點明白,建議你自己去看。我只說一點不同之處,遊戲中MFC的方法不是完全適用的。MFC是一個應用程式架構,MFC命令繞行的過程式控制制的是程式的全部,而遊戲的UI系統只是一個輔助部分,不是全部,甚至可以去掉(我是說做到遊戲裡去,我猜95仙劍的菜單就是和遊戲一體的)。UI系統要根據滑鼠鍵盤做出不同的反應,繪製不同的介面,它又不是程式的全部,所以你需要把每一個可用(有用)的訊息都傳給UI系統。(不一定是全部的訊息,比如說我的UI只使用滑鼠操作,那就只傳遞WM_LBUTTONDOWN、WM_LBUTTONUP、WM_MOUSEMOVE、WM_LBUTTONDBLCLK等等)
while(1)
{
if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)
{
if(!GetMessage(&msg,NULL,0,0))
break;
if(!TranslateAccelerator(msg.hwnd,hAccelTable,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// 在這裡添加你向UI系統傳遞訊息的代碼
UI_DecipherMessage(&msg);
}
else
{
// 在這裡添加你遊戲的主要邏輯代碼
GameMain();
}
}
然後,做一個僅使用在UI系統內部的訊息映射和命令繞行,它處理的是UI系統自己產生的訊息,或是改變一些視窗的顯示與關閉,或是向遊戲主要邏輯做出如使用物品、離開遊戲之類的訊號。是的,UI系統需要自己產生很多訊息,不要指望windows會主動因為你的控制項被按下而向訊息佇列裡傳送WM_COMMAND訊息,你得自己做這些,使用PostMessage函數就可以了。有時候工作會更多,因為你面對的是windows的訊息佇列和UI系統自身的訊息佇列。
5、一個例子
HOHOv5中的UI系統作為這篇文章的例子再合適不過了,可以說我的思路可能是被它幹擾了。
在下一篇中,我可能會講講本文未能說清楚的問題和一個不用訊息映射及命令繞行的執行個體。
參考:
(1)HOHOv5的UI系統標頭檔(沒辦法,我沒有任何一個版本的源檔案,也沒厚著臉皮去找人家要。嘿嘿,關鍵是沒法要。寫這篇文章的時候我的網還沒有辦下來,怎麼到我這裡就預留介面不足,氣死了)
(2)《深入淺出MFC》第一章的訊息映射的雛形、第三章的訊息映射和命令繞行、第九章的全部
(3)MSDN和winuser.h
(4)視窗之父CXWnd的封裝