通常情況下,游戲開發的基本框架中,一般包括以下模塊:
窗口管理(Window management):該模塊負責在Android平台上創建、運行、暫停、恢復游戲界面等功能。
輸入模塊(Input):該模塊和視窗管理模塊是密切相關的,用來監測追蹤用戶的輸入(比如觸摸事件、按鍵事件、加速計事件等)。
文件輸入輸出(File I/O):此模塊用來讀取assets文件下圖片、音頻等資源。
圖像模塊(Graphics):在實際游戲開發中,這個模塊或許是最復雜的部分。它負責加載圖片並把它們繪制到屏幕上。
音頻模塊(Audio):這個模塊負責在不同的游戲界面加載音各類頻。
網絡(networking):如果游戲提供多人游戲聯網功能,此模塊就是必須的。
游戲框架(Game framework):該模塊把以上各種模塊整合起來,提供一個易用的框架,來輕松地實現我們的游戲。
下面對每一個模塊進行詳細的描述。
1. 窗口管理
我們可以把游戲的窗口想象成一個可以在它上面繪制內容的畫布。窗口管理模塊負責定制窗口、添加各種UI組建、接受各類用戶的輸入事件。這些UI組件或許可以通過GPU等硬件加速(比如使用了OpenGL ES)。
該模設計時不是提供接口,而是和游戲框架整合在一起,之后會有相關的代碼貼出。我們需要記住的是應用程序狀態和窗口事件是該模塊必須處理的事情:
Create: 當窗口被創建時被調用的方法。
Pause: 當應用程序由於默寫原因暫停時調用的方法。
Resume: 當應用程序恢復到前台時調用的方法。
2.輸入模塊
大部分操作系統中,輸入事件( 比如觸屏事件、按鍵事件)是通過當前的窗口調度(dispatched)的,窗口再進一步把這些事件派發給當前選中的組件。因此我們只需要關注組件的事件即可。操作系統提供的UI APIs提供了事件分發機制,我們可以很容易地注冊和監聽事件,這也是輸入模塊的主要職責。有兩種處理事件的做法:
輪詢(Polling):在這種機制下,我們僅檢查輸入設備的當前狀態,之前和之后的狀態並無保存。這種輸入事件處理適合處理諸如觸屏按鈕事件,而不適合跟蹤文本的輸入,因為按鍵事件的順序並未保存。
基於事件的處理(Event-based handling):這種機制提供了記憶功能的事件處理,比較適合處理文本輸入或者其他需要按鍵次序的操作。
在Android平台中,主要有三種輸入事件:觸屏事件、按鍵事件和加速計事件,前兩種時間使用輪詢機制和基於事件處理的機制都適合,加速計事件通常是輪詢機制。
觸屏事件有三種:
Touch down: 手機觸屏時發生。
Touch drag: 手指拖動時發生,此前有Touch down事件產生。
Touch up: 手指抬起時發生。
每種觸摸事件有相關的輔助信息:觸屏的位置、指針索引(多點觸摸時用來追蹤識別不同的觸點)
鍵盤事件包括兩種:
Key down: 按下鍵盤時觸發。
Key up: 釋放鍵盤時觸發。
每種按鍵事件也有相關的輔助信息:Key-down事件存儲按鍵碼,Key-up事件存儲按鍵碼和實際的Unicode字符。
加速計事件,系統不停的輪詢加速劑的狀態,並以三位坐標標識。
基於以上介紹,下面定義輸入模塊的一些接口,用來輪詢觸屏事件、按鍵事件和加速計事件。代碼如下:
Input.java
package com.badlogic.androidgames.framework;
import java.util.List;
public interface Input {
public static class KeyEvent {
public static final int KEY_DOWN = 0;
public static final int KEY_UP = 1;
public int type;
public int keyCode;
public char keyChar;
}
public static class TouchEvent {
public static final int TOUCH_DOWN = 0;
public static final int TOUCH_UP = 1;
public static final int TOUCH_DRAGGED = 2;
public int type;
public int x, y;
public int pointer;
}
public boolean isKeyPressed(int keyCode);
public boolean isTouchDown(int pointer);
public int getTouchX(int pointer);
public int getTouchY(int pointer);
public float getAccelX();
public float getAccelY();
public float getAccelZ();
public List<KeyEvent> getKeyEvents();
public List<TouchEvent> getTouchEvents();
}
上述定義包括兩個靜態類:KeyEvent 和 TouchEvent。KeyEvent類和TouchEvent類都定義了相關事件的常量。KeyEvent同時定義了幾個存儲事件信息的變量:類型(type)、按鍵碼(keyCode)和Unicode字符(keyChar)。TouchEvent也一樣,定義了位置信息(x,y)、某個出觸摸點的ID。比如第一個手指按下,ID是0,第二個手指按下 ID是1;如果兩個手指按下,手指0釋放,手指1保持,又一個手指按下時,ID為已經釋放的0.
下面是輸入接口中的輪詢方法:Input.isKeyPressed()輸入參數是 keyCode,返回相應的按鍵是否按下的布爾值;Input.isTouchDown(),Input.getTouchX()和Input.getTouchY()返回給定指針索引是否按下、對應的橫豎坐標值,注意當對應的指針索引不存在時坐標值是未定義的。Input.getAccelX(), Input.getAccelY(), and Input.getAccelZ() 返回各自的加速計的坐標值;最后兩個方法用作基於事件處理機制的,他們返回KeyEvent和TouchEvent實例,用於記錄上次事件觸發的信息,最新的事件在列表的最后。
通過這些簡單的接口和類的,我們構建了我們的輸入接口。下節繼續分析文件處理的內容(File I/O)。
3. 文件讀寫(File I/O)
讀寫文件在游戲開發中是一項十分重要的功能。在Java開發中,我們主要關注InputStream和OutputStream及其實例,它們是Java中讀寫文件的標准方法。游戲開發中,比較多的是讀取資源文件,比如配置文件、圖片、音頻文件等;寫入文件的操作一般在保存用戶進度和配置信息時使用。
下面是文件讀寫的接口:
FileIO.java
package com.badlogic.androidgames.framework;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public interface FileIO {
public InputStream readAsset(String fileName) throws IOException;
public InputStream readFile(String fileName) throws IOException;
public OutputStream writeFile(String fileName) throws IOException;
}
上述代碼中,我們傳遞一個文件名作為參數,返回一個流,具體的執行會在接口的實現中體現。同時我們會拋出一個IOException異常以防止讀寫文件出錯。當我們完成讀寫后,需要關閉輸入輸出流。Asset 文件從應用程序的APK文件中讀取,其他文件一般從內置存儲器或者SDCard上讀取,分別對應上述代碼中的三個方法。
PS: 歡迎關注公眾號"Devin說",會不定期更新Java相關技術知識。