遊戲的基本結構遊戲是什麼呢?在遊戲中,往往是顯示各種各樣的畫面,玩家可以做一些設定好的控制,畫面根據玩家的控制有所變化。從這兒可以看出,遊戲至少需要三個功能-顯示畫面,接受玩家輸入和對輸入產生反饋。這就是常說的渲染,輸入輸出和邏輯三個模組。將這三個模組組合在一起有很多方法。比如事件驅動-畫面保持不變直到接受到輸入事件,程式進行邏輯運算然後改變畫面。而遊戲往往不是這樣,遊戲是時間驅動的。也就是說無論有沒有輸入,遊戲都在不停的迴圈-檢查是否有輸入,執行邏輯,渲染畫面。這裡我多說一句,其實什麼樣的結構並不能區別乙個程式是不是遊戲,其實只要可以互動娛樂的程式就可以稱為遊戲,也不一定要用時間驅動,但採用時間驅動是專業遊戲的普遍做法,也是很容易接受的方法-因為從一定程度上講,遊戲很像電影,隨著時間流逝畫面在改變。
0 初始化遊戲
1 是否結束遊戲(yes:轉到6)
2 蒐集玩家輸入資訊
3 執行遊戲邏輯
4 更新下一幀,顯示下一幀
5 回到1
6 清理,結束遊戲
這是乙個最基本的結構,特別對於比較簡單的j2me遊戲來說,這個結構更加有代表性。下面我們將分別講述專業手機遊戲如何實現這個結構中的各個內容。
遊戲迴圈的實現
我們需要乙個進入後就一直迴圈下去直到遊戲結束的結構。執行緒正好可以實現。最通常的做法是讓canvas實現runnable介面。於是我們就可以實現run方法。下面是乙個run方法簡化版:
public void run()
catch (interruptedexception ex) {}
}endmidlet() ;
}看到我們的
while
迴圈了嗎?除非在程式邏輯中設定
exitmidlet
為true
-那是當玩家選擇了退出遊戲,我們的遊戲將一直執行下去。在
while
迴圈之前,
gameinit
方法的作用是進行遊戲初始化-比如初始化變數值,載入全域性資料,生成全域性物件等。在
while
迴圈中,我們先是呼叫了
acquirekey
方法,這個方法將鍵盤輸入資訊進行緩衝以便邏輯中判斷按鍵狀態,下面講會講到鍵盤緩衝。
gameloop
是我們遊戲的主體,每幀中的邏輯運算,圖形處理都在這裡面進行。然後是
repaint
和servicerepaints
,重新整理螢幕-新的一幀呈現在螢幕上。最後當跳出
while
之後,我們執行
endmidlet
結束這個
midlet
。endmidlet
的內容只是呼叫了
和notifydestroyed
方法。好了整個遊戲迴圈就是這樣了,下面講分別講述鍵盤緩衝和
gameloop
如何組織。不過再這之前先讓我解釋下
lock fps
。fps
就是frame per second
。為了防止遊戲在不同的機器上速度變化太大,我們設定乙個最大的
fps值,或者說設定乙個每幀至少要花費的時間(這裡的
min_delay
)。比如我們設定
min_delay=50
,那麼max fps = 1000/50 = 20 幀/
秒。鎖定
fps有多種方法,這裡的方法是判斷如果一幀所有的時間還沒達到最大時間,那麼就讓執行緒
sleep
一會兒。順便在說一下
fps的計算,顧名思義用
1000
除以一幀所有時間即可,不過要注意的是,一般計算的
fps是平均
fps,所以
fps=
累計幀數
*1000/
累計花費時間。
鍵盤緩衝
蒐集玩家輸入資訊是乙個很重要的內容,我們知道
j2me
中可以在
keypressed
和keyreleased
事件中處理按鍵內容,但這樣勢必將邏輯**分散與
gameloop
和keypressed
中。如果你說將所有邏輯**放在
keypressed
中,那可不行,因為
keypressed
只有在按鍵的時候才產生,而即使沒有按鍵遊戲也有很多邏輯運算要做。所以專業遊戲開發中採用鍵盤緩衝將按鍵資訊存起來,然後在
gameloop
中就可以判斷這一幀按鍵的狀態,利用按鍵緩衝,除了可以判斷乙個鍵是否按下鬆開,還可以判斷乙個鍵是否一直被按住了,甚至可以判斷組合鍵。不過在這裡,我只介紹一種最簡單的按鍵緩衝。由於篇幅所限,只講述原理並不給出具體**。
首先我們需要乙個資料結構儲存按鍵資訊。你可以為每個鍵用乙個
bool
值儲存它的狀態,不過專業一點的做法是用乙個位表示乙個鍵的狀態,乙個
int有
32個位,足夠表示大多數手機的所有按鍵了。因為我們要判斷鍵是否按下或鬆開,為了方便,我們再用
2個整數記錄這兩種狀態。所以現在我們一共有三個
int了
: static int key , pressedkey, releasedkey ;
ok! 有了儲存的地方,我們還需要一些常量表示每個位,我們設定
key中某個位為
0表示某鍵沒有按下,為
1表示按下。如果用第
1位表示
0鍵,第
2位表示
1鍵,那麼可以這樣設定常量:
final static int gkey_0=1<<0, gkey_1=1<<1 ;
明白了嗎?這些常量是用來指定某個位用的,比如
gkey_1
其實就是第2為
1其它位均為
0的乙個整數。如果還不明白,先看下面的。
keypressed
和keyreleased
裡將分別將按下的鍵和鬆開的鍵進行記錄。
public void keypressed(int keycode)
public void keyreleased(int keycode) 在
keypressed
裡面,我們先將
keycode
轉換成我們的按鍵常量,就是上面的
gkey_0
等。因為
keycode
可不是像我們的常量那樣可以用某個位表示的,而且不同手機的
keycode
是有可能不一樣的,所以我們必須用乙個函式
getkeyvalue
進行轉化。得到常量後
key|=value
的作用是將
key裡面常量所代表的位置
1,現在你應該明白常量的作用了吧!
pressedkey|=value
同理。不過
keyreleased
有些不同,由於
releasedkey
只記錄這一幀裡哪些鍵「被鬆開」了,所以仍然用或運算。但
key是記錄整個按鍵的狀態,所以用異或。
接下來就是如何判斷按鍵狀態了:
private static void acquirekey()
public static boolean keyhold(int gamekey)
public static boolean keydown(int gamekey)
public static boolean keyup(int gamekey)
還記得acquirekey
吧,我們在
while
迴圈中首先要呼叫它,其作用就是記錄下這一幀的按鍵狀態,所有我們用了三個新
int變數記錄他們,分別是
framekey
,framepressedkey
和framereleasedkey
。acquirekey
所做的就是將按鍵狀態記錄在這
3個變數中,其實
framepressedkey
和framereleasedkey
不是必須的,只是這樣看上去比較清楚。記錄完後我們將
pressedkey
和releasedkey
清空,以便下次有鍵按下或鬆開時記錄新的資訊。關鍵的三個函式登場了,
keydown
判斷某個鍵是否在這一幀裡被按下,引數
gamekey
是我們定義的按鍵常量中的某個值。如果對位運算還算明白的話,很容易看懂這
3個函式。唯一要說明的就是
keyhold
和keydown
的區別,
keyhold
表示某個鍵一直被按著,也就是至少從前一幀開始它就被按下了,而不是在這一幀裡被按下的。現在你應該明白我們為什麼要清空
pressedkey
和releasedkey了。
說到這裡也差不多了,有了這個按鍵緩衝我們就可以在
gameloop
中呼叫keydown
等方法判斷按鍵的狀態了。不過我還是要說一句,這只是最簡單的按鍵緩衝,只能緩衝一次按鍵,如果乙個鍵被多次按下就不行啦。更專業的內容需要你在實際工作中探索。
J2ME開發之手機鍵值適配
本來不想寫j2me開發的時候要根據不同手機平台適配各種鍵值這個問題,覺得沒撒意思,也沒什麼技術含量,但是今天看到了乙個讓我很無語的東西,所以我決定要寫出來。稍候再說這個讓我不爽的東西,先不要影響我們分享技術的心情。now begin 很多人都說,要適配所有手機的鍵值是不可能的。因為,已是j2me中沒...
j2me 遊戲開發 背景篇 TiledLayer
在 中背景是個有意思的東東,先前沒做過應用開發,發覺這個背景開發 有點和其他的應用開發一樣,幾個小圖合成乙個圖,遊戲用的時候再去分開,重複組成背景。其主要常用的函式有 建構函式 tiledlayer int column,int row,image img,int width,int height ...
J2ME 開發工具
j2me wireless toolkit 手機廠商sdk wtk 的全稱是sun j2me wireless toolkit sun的無線開發工具包。這一工具包的設計目的是為了幫助開發人員簡化j2me的開發過程。該工具箱包含了完整的生成工具 實用程式以及裝置 器。a.wtk 2.2 目前各大手機廠...