一般來說,最常用的 游戲 結構是這樣的:游戲開始后即進入一個循環,每次循環做三件事情: 1. 獲取玩家的輸入。 2. 更新游戲狀態。 3. 刷新屏幕。 理論" name="description" />
MILY: 宋體; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一般來說,最常用的游戲結構是這樣的:游戲開始后即進入一個循環,每次循環做三件事情:
1. 獲取玩家的輸入。
2. 更新游戲狀態。
3. 刷新屏幕。
理論上說,刷屏的頻率在24Hz以上,人的眼睛看到的就是動畫了。
這個例子游戲的主循環是這樣的:
public void run() {
Graphics g = getGraphics();
Thread currentThread = Thread.currentThread();
try {
while (currentThread == gameThread) {
long startTime = System.currentTimeMillis();
if (isShown()) {
if (isPlay) {
tick();
}
render(g);
}
long timeTake = System.currentTimeMillis() - startTime;
if (timeTake < MILLIS_PER_TICK) {
synchronized (this) {
wait(MILLIS_PER_TICK - timeTake);
}
} else {
currentThread.yield();
}
}
} catch (InterruptedException ex) {
// won't be thrown
}
}
說明:
1. 兩個thread。currentThread當然就是當前執行的這個線程,那么gameThread當然也就是運行這個run方法的線程(不然while一開始就不成立,游戲就沒法運行了^_^)。這里它們的作用是控制游戲的循環,當一開始運行時,currentThread==gameThread,循環下去;當游戲需要退出時,將gameThread(類成員)設置為null,那么循環結束,游戲就退出了。強制結束某個線程是很不好的方法,sun的標準庫里早就deprecate這個方法了。
2. tick方法:處理玩家的輸入以及游戲狀態的變更。
3. render方法:顧名思義,繪圖。這里MIDP2.0相對于1.0有很大的改進,后面說。
4. 幾個long型的time的用處。代碼看起來很直觀,就是考慮到tick和render方法執行時間可能不固定,用time加以計算,得到需要sleep的時間。這樣的結果就是游戲畫面以一個固定的延時刷新,FixedDelay。當然,還有另外一種控制方式,即固定頻率的刷新,FixedRate。
a) FixedDelay:固定延時的好處是畫面看起來總是很流暢,而且一定不會出現跳幀的現象。
b) FixedRate:在一種情況下和FixedDelay有差別,即tick和render方法消耗的時間比預設的時間(MILLIS_PER_TICK)還長。FixedDelay這時不再wait,直接繪制下一幅圖;而FixedRate就不能繪了,否則頻率不固定。它的選擇是不繪這一幅,而是直接進入下一個循環,更新游戲狀態,綜合計算時間,繪下一幅圖——于是產生了跳幀。
像CS或星際這樣的游戲,跳幀是必須的,因為聯機游戲必須保證各方的圖像顯示的同步,不固定刷新頻率會導致錯誤。而像仙劍之類的單機游戲倒是可以考慮用固定延時,因為不跳幀不會產生什么錯誤,同時也可以增加游戲畫面的流暢性。
繪圖:
private void render(Graphics g) {
// Set Background color to beige
g.setColor(0xF8DDBE);
g.fillRect(0, 0, width, height);
g.setColor(0x0000ff);
// LayerManager Paint Graphics
layerManager.paint(g, 0, 0);
flushGraphics();
}
在MIDP1.0里面,Canvas的繪圖只能寫在paint(Graphics g)方法里,因為一來g參數在此方法結束后就沒有意義了,保留它的副本沒有用處;二來此方法由平臺調用,而不是由Canvas這個線程調用。因此在MIDP里繪圖總是一件很痛苦的事情,特別是需要保證Canvas線程與調用paint的那個線程同步(J2me的Specification說的是,可以保證你repaint了以后,paint方法在之后的某個時刻被調用,但不能保證馬上就被調用,因為paint是個比較耗時的方法,它無法確定其他的paint是否及時完成了)。
在MIDP2.0里,有所改進了。首先是你可以通過GameCanvas的一個方法getGraphics來獲取那個g,然后這個g就永不失效了(當然是在這個GameCanvas的生命周期內)。當然,這個g和1.0里的還是有所區別。這個g實際上是畫在一塊緩沖“畫布”上,即內存里。完全畫好以后,再用flushGraphics刷到屏幕上。緩沖的好處是可以讓屏幕在畫時不顯得閃爍,很有用的東西。flushGraphics還有另外一個作用,就是強制輸出,以達到顯示的那個線程與游戲控制線程的同步(這也是為什么做時間協調時,要把顯示方法所消耗的時間也計算進來)。
Tick…………暫時先不討論。
原文轉自:http://www.anti-gravitydesign.com