第31節 - LibGDX: Lifecycle (Render() Method)
這一節我會介紹LibGDX生命週期(Lifecycle)的一個主要部分 - Render()方法。
Android和LibGDX都有自己的生命週期,因為如果我們在Android手機上運行LibGDX遊戲程式,Android的生命週期就用來控制手機的不同狀態,例如正常執行手機程式、換頁、按HOME鍵、接電話等等,而LibGDX的生命週期就用來控制遊戲的不同狀態,例如正常執行遊戲程式(create)、改變屏幕尺寸(resize)、渲染(render)、暫停(pause)、恢復(resume)和清理(dispose)。
Android和LibGDX生命週期的比較。
以下是Android和LibGDX生命週期的比較:

Android Lifecycle
Android有幾個特殊的callback methods來處理對應的Activity的狀態,Activity的狀態處理method有以下幾種:
- onCreate()
- onStart()
- onPause()
- onResume()
- onRestart()
- onDestroy()

1) 當Activity正常執行時,會先進入onCreate() -> onStart() -> onResume()。

2) 當按下手機HOME按鈕時,會進入onPause() -> onStop()。

3) 當先前已經按過HOME鈕,再次點APP,會進入到 onRestart() -> onStart() -> onResume()。

4) 當先前換頁,再按下返回鈕,也會進入到 onRestart() -> onStart() -> onResume()。

5) 當先前按下返回鈕,再點APP,則會再進入到 onCreate() -> onStart() -> onResume()。

6) 當Activity結束時,會進入onPause -> onStop() -> onDestroy(),釋放資源。

LibGDX Lifecycle
Libgdx擁有自己的生命週期,它管理應用的各個狀態,例如,正常執行遊戲程式(create)、改變屏幕尺寸(resize)、渲染(render)、暫停(pause)、恢復(resume)和清理(dispose):
- create()
- resize()
- render()
- pasue()
- resume()
- dispose()

1) 當遊戲正常執行時,會先進入create() -> resize() -> render()。
注意,render()方法會不斷循環,一秒30至80次(通常60 Frame per Second, FPS),根據手機硬件速度而正。

2) 當按HOME鍵或接電話時,會先進入pause()。

3) 當回復遊戲時,會進入pause() -> resume()。

4) 當遊戲畫面結束時,會進入pause() -> dispose(),釋放資源。

為甚麼要學LibGDX的Render()方法?
在遊戲執行時,Render()方法會不斷循環執行,一秒30至80次(通常60 Frame per Second, FPS),根據手機硬件速度而正,Render()方法用來渲染(render)遊戲。而遊戲的邏輯通常也會放在這個方法裡執行。
我們就可以用Render()方法不斷循環執行的特性,不斷更新畫面的圖片,這樣做就可以做出動畫效果,我會在下一部分加以說明。
例子1 - 生命週期和Render()方法執行次數

- 建立一個deltaTime變數 (float type)。
- 如果create()方法有被呼叫,在系統上顯示出來。
- 如果resize()方法有被呼叫,在系統上顯示出來。
- Render()方法會不斷循環執行,一秒30至80次(通常60 Frame per Second, FPS),根據手機硬件速度而正,Render()方法用來渲染(render)遊戲。
用Gdx.graphics.getDeltaTime()方法敢得 兩格(two frames)動畫之間的時間,再傳入deltaTime變數內。 - 如果pause()方法有被呼叫,在系統上顯示出來。
- 如果resume()方法有被呼叫,在系統上顯示出來。
- 如果dispose()方法有被呼叫,在系統上顯示出來。
執行結果:

- 首先create()方法會被呼叫一次。
- 再被呼resize()方法,如果屏幕尸吋有改變就會在這樣執行。
- Render()方法會不斷循環執行,1/60 = 0.01667s(大約 60 Frame per Second, FPS)。
- 程式結束前會呼叫pause()方法。
- 最後呼叫dispose()方法,釋放資源。
例子2 - 簡單動畫

- 建立一個xPosition變數 (float type)。
- 在create()方法內設定開始時xPosition的值為(-1920/2),則是屏幕寬度的一半。
- 在Render()方法內設定sprite的位置。
- xPosition = xPosition + 5; 是大部分程式的一種最簡單寫法,把現時xPosition的值加上5,再傳入給新的xPosition。
- 最後別忘記把在dispose()方法內輸入batch.dispose();和hero1.dispose();,釋放資源。
執行結果:

- hero1圖片就會已大約60FPS向右移動。
注意
以上例子2是一個簡單的動畫程式,它把hero1圖片由左至右移動,但這個例子有一個很大的缺點,就是動畫的速度會根據手機硬件速度而正。
如果你的手機是新型號,Render()方法會已大約一秒60次(60FPS)執行,每次加5px,則是一秒後向右移動了60x5=300px。
如果你的手機是舊型號,Render()方法會已大約一秒30次(30FPS)執行,每次加5px,則是一秒後向右移動了30x5=15px,則是比60FPS行慢了一半。
主要部分如下:

- xPosition = xPosition + 5;是不依靠時間的(Time independent),所以動畫的速度會根據手機硬件速度而正。
要解決以上速度問題,我們可以用LibGDX的Gdx.graphics.getDeltaTime(),它可以敢得兩格(two frames)動畫之間的時間,用來控制動畫的速度,我會在下一節詳細介紹。
主要部分如下:

- xPosition = xPosition + (150*deltaTime); 是依靠時間的(Time dependent),deltaTime在60FPS會是30FPS的一半,所以動畫的速度不會受手機硬件速度影響。
60FPS - 150 x 0.01667s x 60次 = 150。
30FPS - 150 x 0.03333s x 30次 = 150。
結果相同!