相信在手機遊戲開發這塊是J2ME的天下,一是因為它簡單容易學,二是因為關於它的資料多.
而J2ME畢竟是運行在Symbian OS的內核之上的,速度慢也是必然的了,更不能忍受的是它把很多與底層的交互封裝了起來,並且不提供讓你訪問.
這對於我這樣喜歡刨根問低的人來說,是實在無法忍受的!
其實真正了解了Symbian OS和相應的Series 60,如果在這個平台上做遊戲開發的話,Series 60並不比J2ME高深多少.因為它提供了一個AppArc,同樣把一些底層的東西封裝了起來,但是至少我們可以有介面可用來訪問低層的東西.
下面我就把最近一段時間的學習總結一下:
(一)關於開發
原本是沒有必要寫這個的,不過看到網上五花八門的工具配置、工具安裝的文章,實在覺得有必要出來澄清一下.
其實,完全沒必要為選擇什麼IDE來煩惱,無論是Moblie Borland C 、VC、VC.NET、CodeWarrior還是Nokia最近力推的Carbide.C ,他們都存在著這樣那樣的問題.沒有一個是的開發工具,series的SDK還為每一種開發工具提供了不同的版本,真是感覺有點"光了屁股系褲腰帶——多那麼一道子".IDE只能用來看源或者寫代碼,真正有用的還是SDK下的command命令行,不要怕麻煩,這些往往是最重要的.
命令也就是常用的那麼幾個:
bldmake bldfiles
abld build wins udeb
epoc
makesis
devices
(二)關於交互
無論做什麼樣的遊戲,都少不了與用戶的交互,而對於手機設備來說.與用戶交互的無非是鍵盤,事件是系統事件的一種,一旦設備鍵盤上的鍵被按下、按住或釋放的時候即會產生按鍵事件.
Symbian的Window通過控制項棧把按鍵事件傳遞到應用程序.然後通過調用控制項的OfferKeyEventL()方法把按鍵事件通知相應的控制項.這和我們在J2ME里通過KeyPressed(int keyCode)把相應的按鍵事件通知相應的Canvas類一樣.
OK,我們現在有了第一個類比的關係:
Symbian的OfferKeyEventL()和J2ME的KeyPressed(int keyCode)
當然,Symbian里這個方法還有一些需要特別說明的不同之處.
Symbian里的控制項棧是一個結構,負責維護控制項.當有按鍵事件發生的時候,這個按鍵事件會從控制項棧的頂部依次傳遞到最底端,直至得到了某個控制項的處理.默認情況下,控制項是不在棧中的,應該使用相應的函數CAknAppUi::AddToStackL()把控制項添加到控制項棧中,使它能夠處理按鍵事件.
這和我們的J2ME里不一樣,J2ME里KeyPressed(int keyCode)是和相應的Canvas里關聯在一起的.試著想象一下,如果從一個From高級UI切換到Canvas的低級UI,是不是需要用Command命令來控制?
然後就可以通過調用控制項的OfferKeyEventL()把按鍵事件傳遞給該控制項.控制項可以自己決定是否處理某個按鍵事件,如果處理事件,則返回值EKeyWasConsumed,否則返回EKeyWasNotConsumed.按鍵事件會按次序傳遞給控制項棧中的每個控制項,直至其中某個控制項返回EKeyWasConsumed或沒有剩餘控制項為止.
OfferKeyEventL()有兩個參數:按鍵事件(const EKeyEvent& aKeyEvent)、按鍵類型(TEventCode aType).前者表明按鍵是哪一個鍵等信息,後者則是一個emnu類型,說明按鍵事件的種類.
和我們在J2ME里不同的是,J2ME里用三個方法來分別表示Pressed、Released、Repeated.而Symbian里用一個emnu類型的參數來說明按鍵事件的種類,分別是:EEventKeyDwon、EEventKey、EEventKeyUp.
用以下代碼來做為事例恐怕更能說明問題:
TKeyReponse CMyControl::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType){ if(aType == EEventKeyUp){ switch(aKeyEvent.iCode){ case EKeyUpArrow: //producing return EKeyWasConsumed; case EKeyDownArrow: //producing return EKeyWasConsumed; default: return EKeyWasNotConsumed; } } return EKeyWasNotConsumed; } |
前面我們講到了「按鍵事件」在J2me和Symbian中的類似處理過程,其實這些東西都是一個遊戲里必須做的處理,無論是在任何平台.那麼在手機遊戲里,菜單也是必不可少的.而在Symbian里是不分什麼高級UI和低級UI的,只有系統控制項和自定義控制項之分.
那麼界面交互部分我們一樣可以和J2ME做個對比:J2ME里的高級UI CommandAction()、 Symbian里的系統控制項 HandleCommandL()、J2ME里的低級UI KeyPressed()和Symbian里的自定義控制項 OfferKeyEventL()
(三)系統菜單和J2ME里不一樣的是,Symbian里的系統控制項是通過在資源文件中編輯,在源代碼之外獨立地指定應用程序的可見控制項.在資源中可以定義的系統控制項包括菜單、對話框、列表等.
應用程序框架在應用程序啟動時會打開資源文件,並根據在.rsg中創建的資源標識符,根據需要把各個資源載入到C 代碼中.
這樣的架構有一定的好處就是:資源文件和C 源文件之間可以共享資源文件中定義的數據.
通常在一個後綴名為.hrh的文件中定義命令菜單中使用的標識符.
如下實例摘自SDK自帶的Graphics實例:
#ifndef __GRAPHICS_HRH__ #define __GRAPHICS_HRH__ // Graphics enumerate command codes enum TGraphicsIds { EGaphicsNoOffScreenDemo = 1, EGaphicsOffScreenDemo, EGaphicsStopDemo }; #endif // __GRAPHICS_HRH__ |
可見資源文件的處理使用的是C的預處理器,以避免多重包含.而.hrh文件也只能包含emnu和預處理語句,其它的C 語法都會導致資源編輯器編輯失敗,這點需要特別注意.
下面是和這個.hrh文件相對應的.rss文件的內容:
NAME GRAP #include <eikon.rh> #include <avkon.rh> #include <avkon.rsg> #include "Graphics.hrh" // --------------------------------------------------------- // // Define the resource file signature // This resource should be empty. // // --------------------------------------------------------- // RESOURCE RSS_SIGNATURE { } // --------------------------------------------------------- // // Default Document Name // // --------------------------------------------------------- // RESOURCE TBUF { buf=""; } // --------------------------------------------------------- // // Define default menu and CBA key. // // --------------------------------------------------------- // RESOURCE EIK_APP_INFO { menubar = r_graphics_menubar; cba = R_AVKON_SOFTKEYS_OPTIONS_EXIT; } // --------------------------------------------------------- // // r_graphics_menubar // Menubar for Graphics example // // --------------------------------------------------------- // RESOURCE MENU_BAR r_graphics_menubar { titles = { MENU_TITLE { menu_pane = r_graphics_menu; } }; } // --------------------------------------------------------- // // r_graphics_menu // Menu for "Options" // // --------------------------------------------------------- // RESOURCE MENU_PANE r_graphics_menu { items = { MENU_ITEM { command = EGaphicsNoOffScreenDemo; txt = "No off screen bmp"; }, MENU_ITEM { command = EGaphicsOffScreenDemo; txt = "Off screen bmp"; }, MENU_ITEM { command = EGaphicsStopDemo; txt = "Stop Animation"; }, MENU_ITEM { command = EAknSoftkeyExit; txt = "Exit"; } }; } |
下面對這個文件的內容做一些說明
RESOURCE RSS_SIGNATURE { } RESOURCE TBUF { buf=""; } |
這兩個一般情況下是不允許做改動的,前者是資源的簽名,後者是默認文檔名.
RESOURCE EIK_APP_INFO { menubar = r_graphics_menubar; cba = R_AVKON_SOFTKEYS_OPTIONS_EXIT; } |
用來標識菜單和快捷鍵的ID,就是給菜單和相應的快捷鍵起個名字而已,以便於程序後面的使用.
RESOURCE MENU_PANE r_graphics_menu { items = { MENU_ITEM { command = EGaphicsNoOffScreenDemo; txt = "No off screen bmp"; }, MENU_ITEM { command = EGaphicsOffScreenDemo; txt = "Off screen bmp"; }, MENU_ITEM { command = EGaphicsStopDemo; txt = "Stop Animation"; }, MENU_ITEM { command = EAknSoftkeyExit; txt = "Exit"; } }; } |
這個才是實際定義的菜單的真正內容,也就是我們能在界面上看得到的Menu_Item的標識和內容.
OK了,資源定義已經完成,下面只需要在Ui類的HandleCommandL()方法中針對相應的Command做相應的處理即可.
void CGraphicsAppUi::HandleCommandL(TInt aCommand) { switch(aCommand) { case EEikCmdExit: case EAknSoftkeyExit: Exit(); break; case EGaphicsNoOffScreenDemo: iAppView->StartNoOffScreenDemo(); break; case EGaphicsOffScreenDemo: iAppView->StartOffScreenDemo(); break; case EGaphicsStopDemo: iAppView->StopDemo(); break; default: User:anic (_L("Graphics"), EGraphicsBasicUi); break; } } |
現在你也學了和J2ME里的高級UI響應相對應的Symbian里的處理方法,現在和用戶交互應該沒問題了.無論是按鍵事件的OfferKeyEventL()方法、還是菜單命令的HandleCommandL()方法.
[火星人 ] 從J2ME學Symbian遊戲開發已經有715次圍觀