第22節 - LibGDX: Game Menu Screen
這一節我會介紹Game Menu Screen。我在第17節 - LibGDX: Splash Screen介紹過Splash Screen的製作,現在會繼續把Splash Screen跳到Game Menu Screen,再按不同按鈕跳到不同的畫面,如下圖:

以下是LibGDX-Game Menu Screen程式執行的結果:
LibGDX的主要章節
我會用以下介紹過的主要章節,大家如果對以下任何章節有不明白地方,請閱讀多幾次:
- 第13節 - UML(Unified Modeling Language): Class Diagram
- 第16節 - LibGDX: Scene2d & Graphical User Interface(GUI)
- 第17節 - LibGDX: Splash Screen
- 第18節 - LibGDX: Texture Packer
- 第19節 - LibGDX: BitmapFonts, JSON & Skin
- 第21節 - Android: onClick事件的5種實現方式
UML - Class Diagram
我在第17節 - LibGDX: Splash Screen介紹過Splash Screen的Class Diagram。以下是Game Menu Screen的Class Diagram:

- Start Screen, Options Screen, Credits Screen和Facebook Link都是Class,Meun Screen是Class,所以它們的關係是Association。因為畫面可以向前或向後,所以是Bi-directional(雙向)
- 因為Start Screen, Options Screen, Credits Screen和Facebook Link都須要是Screen類別,它們須要實作Sceen介面。
AbstractScreen Class
大家可以在以上的Class Diagram看到,每一個Screen類別都要實作Screen介面(綠色部分),我們可以建立一個抽象類別(Abstract Class)叫AbstractScreen,它可以把畫面相同部分放在AbstractScreen類別內,這樣做就可以簡化Class Diagram和程式,我會在第23節 - LibGDX: Advanced Game Menu Screen (Using Abstract Screen)詳細介紹,這一節不會用到。

- 建立一個AbstractScreen抽象類別,再實作Screen介面。AbstractScreen抽象類別內就包含所有start Screen, Options Screen, Credits Screen和Facebook Link相同的方法。
- 把Start Screen, Options Screen, Credits Screen和Facebook Link繼承AbstractScreen抽象類別。
製作Game Menu Screen
首先我們要準備以下文件:
Assets圖片檔案:
- fonts/carterone.fnt
- fonts/carterone.png
- mainmenu.pack
- mainmenu.png
- mainmenu2.png
- mainmenu3.png
- mainmenu.json
程式檔案:
- DesktopLauncher.java
- MyDemo22.java
- SplashScreen.java
- MenuScreen.java
- LevelScreen.java
- OptionsScreen.java
- CreditsScreen.java
- Facebook Website Link
carterone.fnt和carterone.png
我在第19節 - LibGDX: BitmapFonts, JSON & Skin介紹過Bitmap Fonts的製作,這裡不會詳細介紹。
注意1-我會把carterone.fnt和carterone.png放在Android/assets/fonts/的文件夾內。
注意2-其實這一節我們只會用到Button和Image類別,不須要用到Bitmap Fonts,但因為我們要製作mainmenu.json檔案,我習慣把carterone.fnt和carterone.png放在JSON檔案內,大家可以在JSON檔案內刪除carterone.fnt和carterone.png的設定。

- carterone.png把Carter One字體的A至Z和其他字符儲存在carterone.png檔案內。
- carterone.fnt是一個文字檔案,它把carterone.png檔案內的A至Z和其他字符的資料記錄下來。
mainmenu.pack,mainmenu.png,mainmenu2.png和mainmenu3.png
我在第19節 - LibGDX: BitmapFonts, JSON & Skin介紹過Texture Packer的製作,這裡不會詳細介紹。
注意1-用Texture Packer軟件製作合併圖片時,如圖片太大,Texture Packer軟件會自動產生幾個.png檔案,例如:mainmenu.png,mainmenu2.png和mainmenu3.png。
注意2-我會把mainmenu.pack,mainmenu.png,mainmenu2.png和mainmenu3.png放在Android/assets/的文件夾內。
注意3-我加入了一個backbutton.png,它是用來把畫面跳回前一個畫面。

- 以上是mainmenu.pack,mainmenu.png,mainmenu2.png和mainmenu3.png檔案內的內容。
mainmenu.json
我在第19節 - LibGDX: BitmapFonts, JSON & Skin介紹過JSON檔案,這裡不會詳細介紹。
注意1-我會把mainmenu.json放在Android/asset/的文件夾內。

- 第1段設定Bitmap Font的字體(carterone-font)和字體路徑。
- 第2段設定不同顏色(Color)。
- 第3段設定Button介面元件的特性,按下Mouse(down)或放開Mouse(up),都是用相同的按鈕。
Android/assets
別忘記把Asset圖片檔案放在Android/assets內:
- fonts/carterone.fnt
- fonts/carterone.png
- mainmenu.pack
- mainmenu.png
- mainmenu2.png
- mainmenu3.png
- mainmenu.json

- 建立文件夾fonts,把carterone.fnt和carterone.png傳入assets/fonts/內。
- 把mainmenu.pack,mainmenu.png,mainmenu2.png,mainmenu3.png和mainmenu.json傳入assets/內。
- 在MyDemo22-core/src/com.hkprogram.mydemo22/內建立所有.java程式檔案。
DesktopLauncher.java

- DesktopLauncher是PC Desktop的Starter Class,我們在DesktopLauncher內設定顯示的大小為500x700px。
MyDemo22.java

- 在MyDemo22.java內把MyDemo22 extends Game。
在Game類別內,create()是未定義內容,所以在MyDemo22 class內必須定義內容。 - 定義create()方法,在create()方法內用setScreen()方法把畫面跳到splashScreen。
SplashScreen.java
我在第17節 - LibGDX: Splash Screen介紹過Splash Screen的製作,Splash Screen跳到Game Menu Screen,再按不同按鈕跳到不同的畫面。

- 用Texture產生一個Texture物件(例如:texture)然後把圖片(splashScreen.png)傳入。
用Image產生一個Image物件(例如:splashImage)然後把texture物件傳入。 - 在show()方法內,把image加入Stage舞台內,再用Stage內還有一個addAction()方法把開埸畫面做出逐漸呈現的效果。
1-Actions.alpha(0)-設定alpha=0,則把image設定為全透明。
2-Actions.fadein(0.5f)-把image做出逐漸呈現的效果。
3-Actions.delay(2)-把動作延遲2秒。
4-Actions.run()-把現時splashScreen畫面跳到menuScreen畫面。 - show()方法會設定所有動作,但尚未顯示在屏幕上,我們必須在render()方法內用輪入:
1-stage.act();-更新所有Actor。
2-stage.draw();-把所有Actor顯示在屏幕上。 - 注意,Screen介面的dispose()方法和Game類別的dispose()方法不同,根據LibGDX官方文件解釋,Screen介面的dispose()方法是不會自動執行,所以我們必須在畫面轉換時在hide()執行dispose()方法,我會在第24節 - LibGDX: Disposable Interface詳細介紹。
- 最後別忘記把在dispose()方法內輸入texture.dispose();和stage.dispose()。
MainScreen.java
我們會用第17節的MenuScreen.java檔案再加入"Button Click"事件處理。
- Button "Start"會把畫面跳到Level Screen。
- Button "Options"會把畫面跳到Options Screen。
- Button "Credits"會把畫面跳到Credits Screen。
- Button "Share Facebook"會把畫面跳到Facebook網頁。
以下列出MenuScreen.java的操作原理:

- 設定所有Member Variables。
- 建立Skin物件(skin),把mainmenu.json和mainmenu.pack傳入。
- 建立Image物件(bg),把skin和bg圖片傳入。
再建立Button物件(startbutton, optionsbutton, creditsbutton和facebookbutton),把skin和(startButton, optionsButton, creditsButton和facebookButton)圖片傳入。 - 設定它們的位置。
- 用介面元件的addListener()方法監聽"Click"事件。
注意,facebookbutton按鈕會把畫面跳到一個預設的網站,我用www.hkprogram.com作例子。 - 用介面元件的addActor()方法把所有Image物件和Button物件傳入stage內。
- 用setInputProcessor()方法把stage傳入,再設定touch和key input事件。
- show()方法會設定所有動作,但尚未顯示在屏幕上,我們必須在render()方法內用輪入:
1-stage.act();-更新所有Actor。
2-stage.draw();-把所有Actor顯示在屏幕上。 - 注意,Screen介面的dispose()方法和Game類別的dispose()方法不同,根據LibGDX官方文件解釋,Screen介面的dispose()方法是不會自動執行,所以我們必須在畫面轉換時在hide()執行dispose()方法,我會在第24節 - LibGDX: Disposable Interface詳細介紹。
- 最後別忘記把在dispose()方法內輸入skin.dispose();和stage.dispose()。
LevelScreen.java
以下是LevelScreen.java程式,當"Start"按鈕被按下,程式就會跳到Game Level Selection Screen,我會在其他章節詳細介紹Game Level Selection Screen:

- 設定所有Member Variables。
- 建立Skin物件(skin),把mainmenu.json和mainmenu.pack傳入。
- 建立Image物件(levelScreen),把skin和levelScreen圖片傳入。
再建立Button物件(backButton),把skin和backbutton圖片傳入。 - 設定它們的位置。
- 用介面元件的addListener()方法監聽"Click"事件。
- 用介面元件的addActor()方法把Image物件和Button物件傳入stage內。
- 用setInputProcessor()方法把stage傳入,再設定touch和key input事件。
- show()方法會設定所有動作,但尚未顯示在屏幕上,我們必須在render()方法內用輪入:
1-stage.act();-更新所有Actor。
2-stage.draw();-把所有Actor顯示在屏幕上。 - 注意,Screen介面的dispose()方法和Game類別的dispose()方法不同,根據LibGDX官方文件解釋,Screen介面的dispose()方法是不會自動執行,所以我們必須在畫面轉換時在hide()執行dispose()方法,我會在第24節 - LibGDX: Disposable Interface詳細介紹。
- 最後別忘記把在dispose()方法內輸入skin.dispose();和stage.dispose()。
OptionsScreen.java
以下是Options.java程式,當"Options"按鈕被按下,程式就會跳到Game Options Screen,我會在其他章節詳細介紹Game Opitons Screen:

- 設定所有Member Variables。
- 建立Skin物件(skin),把mainmenu.json和mainmenu.pack傳入。
- 建立Image物件(optionsScreen),把skin和optionsscreen圖片傳入。
再建立Button物件(backButton),把skin和backbutton圖片傳入。 - 設定它們的位置。
- 用介面元件的addListener()方法監聽"Click"事件。
- 用介面元件的addActor()方法把Image物件和Button物件傳入stage內。
- 用setInputProcessor()方法把stage傳入,再設定touch和key input事件。
- show()方法會設定所有動作,但尚未顯示在屏幕上,我們必須在render()方法內用輪入:
1-stage.act();-更新所有Actor。
2-stage.draw();-把所有Actor顯示在屏幕上。 - 注意,Screen介面的dispose()方法和Game類別的dispose()方法不同,根據LibGDX官方文件解釋,Screen介面的dispose()方法是不會自動執行,所以我們必須在畫面轉換時在hide()執行dispose()方法,我會在第24節 - LibGDX: Disposable Interface詳細介紹。
- 最後別忘記把在dispose()方法內輸入skin.dispose();和stage.dispose()。
CreditsScreen.java
以下是Credits.java程式,當"Credits"按鈕被按下,程式就會跳到Game Credits Screen,我會在其他章節詳細介紹Game Credits Screen:

- 設定所有Member Variables。
- 建立Skin物件(skin),把mainmenu.json和mainmenu.pack傳入。
- 建立Image物件(creditsScreen),把skin和creditsScreen圖片傳入。
再建立Button物件(backButton),把skin和backbutton圖片傳入。 - 設定它們的位置。
- 用介面元件的addListener()方法監聽"Click"事件。
- 用介面元件的addActor()方法把Image物件和Button物件傳入stage內。
- 用setInputProcessor()方法把stage傳入,再設定touch和key input事件。
- show()方法會設定所有動作,但尚未顯示在屏幕上,我們必須在render()方法內用輪入:
1-stage.act();-更新所有Actor。
2-stage.draw();-把所有Actor顯示在屏幕上。 - 注意,Screen介面的dispose()方法和Game類別的dispose()方法不同,根據LibGDX官方文件解釋,Screen介面的dispose()方法是不會自動執行,所以我們必須在畫面轉換時在hide()執行dispose()方法,我會在第24節 - LibGDX: Disposable Interface詳細介紹。
- 最後別忘記把在dispose()方法內輸入skin.dispose();和stage.dispose()。
FacebookScreen.java
以下是Facebook.java程式,當"Share to Facebook"按鈕被按下,程式就會跳到Facebook指定的網頁:

- 建立Texture物件(texture),把facebookScreen.png圖片傳入。
- 建立SpriteBatch物件(batch),把texture傳入。
- 再用batch.draw(),把texture傳入和設定顯示位置,最後顯示在屏幕上。
- 注意,Screen介面的dispose()方法和Game類別的dispose()方法不同,根據LibGDX官方文件解釋,Screen介面的dispose()方法是不會自動執行,所以我們必須在畫面轉換時在hide()執行dispose()方法,我會在第24節 - LibGDX: Disposable Interface詳細介紹。
- 最後別忘記把在dispose()方法內輸入texture.dispose();和batch.dispose()。
圖片的座標位置
注意,我們用的是Actor類別的setPosition()方法,沒有用到Camera Viewport,所以用的座標系統是(左X,上Y),而中心(0,0)是設在左下角。
Main Menu Screen

Level Screen

Options Screen
