不同的硬件廠商為 Android 用戶帶來了不同尺寸和體驗的設備,因此,我們也一直努力地幫助開發(fā)者們將游戲呈現(xiàn)到盡多的 Android 設備并使得開發(fā)過程更加高效輕松。本文將向您介紹眾多新的 Android 游戲開發(fā)工具以及游戲調(diào)試、打包和分發(fā)技巧。
更高效的游戲開發(fā)工具
工欲善其事,必先利其器,我們針對開發(fā)工具做出了大量優(yōu)化。游戲引擎主要使用 C 和 C++ 語言編寫,而大多數(shù)的 Android API 都被設計成由 Kotlin 這樣的托管代碼來調(diào)用。所以我們在 Android Studio 中實現(xiàn)了同時調(diào)試 C/C++ 代碼和托管代碼的能力,這樣一來您就可以像下圖那樣在 Kotlin 及 C/C++ 代碼中分別設置斷點,然后在兩種編程環(huán)境內(nèi)分別跟蹤執(zhí)行情況。您甚至還可以在托管代碼和原生 (native) 代碼之間跳轉(zhuǎn)觀察執(zhí)行情況。
△演示通過 Android Studio 同時調(diào)試托管代碼和 C/C++
另一方面,Android Studio 可以通過自動代碼補全功能來加快您編寫代碼的速度,也支持您快速插入 JNI 函數(shù)原型在兩種不同環(huán)境之中編程。此外,構建過程中會使用 Cmake 和 Gradle,它們能讓您更好地利用可移植 build。
對于那些在 Microsoft Windows 操作系統(tǒng)上用 Visual Studio 編寫 C/C++ 跨平臺游戲的開發(fā)者來說,我們在 2021 年 7 月推出的 Android 游戲開發(fā)套件 (Android Game Development Kit) 中提供了一個 Android 游戲開發(fā)擴展 (AGDE, Android Game Development Extension)。它能夠進一步簡化您的開發(fā)進程,并且使用一系列支持 C 和 C++ 的調(diào)試器及性能分析工具幫助您在 Visual Studio 環(huán)境中直接針對 Android 設備進行構建。并且 AGDE 可以很方便地與多種構建系統(tǒng)集成起來,還能非常方便地整合進您使用虛幻引擎的工作流,如此一來,您就不需要專門分別針對桌面設備、游戲主機、Android 設備各使用一套工具集和構建系統(tǒng)了。
配置 AGDE 的過程也非常簡單。擴展安裝完成后,請切換到您的 Visual Studio 項目,然后添加 Android APK 模板。您可以在工具欄訪問到各種常用的 Android 開發(fā)工具,比如 SDK 和 NDK 管理器、虛擬設備管理器、設備文件管理器、Logcat 以及性能分析器等,如下圖所示:
△Visual Studio 中的 Android 工具欄
在項目中配置好 Android 構建目標后,您只需要像開發(fā)標準桌面 Visual Studio 目標那樣操作就行了,所有關于構建、部署、調(diào)試的操作都沒有差別。您可以很方便地在調(diào)試器中設置斷點、切換到反匯編代碼中查看寄存器和內(nèi)存塊中的值,還可以通過并行堆棧查看并發(fā)情況。
△使用 Visual Studio 調(diào)試 Android 構建目標
另外,您不僅可以在專門的 Logcat 面板搜索日志輸出、按照類型過濾,還可以通過 AGDE 快速訪問原本在 Android Studio 提供的獨立 CPU、內(nèi)存分析器,如下圖右所示:
△可供搜索的 Logcat 面板 (左);
獨立的 CPU 和內(nèi)存分析器 (右)
我們?yōu)檫@些工具設計了新的界面,增強了若干功能并支持原生內(nèi)存采樣。Android Studio 和 Android 游戲開發(fā)擴展工具的結合,為您提供了一整套豐富的工具來高效地開發(fā)游戲。
Android 游戲開發(fā)套件
俗話說,好馬配好鞍。只有這些趁手的工具其實是不夠的,我們還需要將這些工具集成到 Android 的托管代碼 API 中。為此,我們在 Android 游戲開發(fā)套件(AGDK) 中提供了全新的 C/C++ 庫供您使用。
GameActivityGameActivity 幾乎就是用原生方式實現(xiàn) (C/C++) 的 Android 標準 activity。它可以很好地與 Jetpack 庫以及各種 Android 界面庫結合使用。這樣您就可以完全使用 C/C++ 編寫游戲循環(huán),同時充分利用基于 Jetpack 構建的各種庫。另外,GameActivity 會被渲染到 SurfaceView 中,因此您可以很輕松地混用 Android 界面元素,比如 WebView、MapView 和廣告 SDK 等各種服務所需要用到的視圖。這樣一來,您只需要在托管代碼中通過一個簡單加載 C/C++ 游戲模塊的類,就能完成對游戲循環(huán)邏輯的整合了。有關代碼如下:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/username"
android:layout_width="0dp"
android:layout_height="wrap_content">
△需要顯示的視圖
△最少的托管代碼public class MyGameActivity extends GameActivity {
static {
// 加載您的游戲庫
System.loadLibrary("game");
}
}
您需要修改 AndroidManifest.xml 文件中的 meta-data,用來告知 GameActivity 需要從哪個庫開始執(zhí)行游戲循環(huán)。
△修改 AndroidManifest.xml<activity android:name=".MyGameActivity" android:label="@string/app_name">
<meta-dataandroid:name="android.app.lib_name"android:value="game"/>
GameActivity 為您提供了若干原生回調(diào)方法,它們與 Android 的生命周期事件是相匹配的,這些事件回調(diào)可以很方便地整合進您的游戲循環(huán)中,您可以查看 GameActivityCallbacks 的使用參考來了解更多信息:
https://developer.android.google.cn/reference/games/game-activity/struct/game-activity-callbacks△與 Android 生命周期對應的回調(diào)方法下面是一段非常簡單的代碼,我們會向您展示一個基于 native_app_glue 庫的案例。native_app_glue 庫提供了一種異于尋常的執(zhí)行模式。
△基于 native_app_glue 的例子void android_main(struct android_app *app) {
// 您的游戲引擎
NativeEngine *engine = new NativeEngine(app);
// 您的游戲循環(huán)
engine->GameLoop();
delete engine;
}
在這里,android_main() 函數(shù)將在一個區(qū)別于主線程的新線程中被調(diào)用。您可以從與線程關聯(lián)的 ALooper 中獲取到 Android 的生命周期事件,就像這樣:
△使用 ALooper 獲取并處理 Android 生命周期事件while(1) {
int events;
struct android_poll_source *source;
// 如果沒有動畫發(fā)生,阻塞進程直到捕獲某個事件
while ((ALooper_pollAll(IsAnimating() ? 0: -1, Null, &events, (void **) &source)) >= 0) {
// 處理事件
if (source != NULL) {
source->process(mApp, source);
}
}
}
除了捕獲生命周期事件,您還可以用這個方法監(jiān)聽文件描述符 (file descriptor)。
Frame Pacing API
幀數(shù)調(diào)步 (frame pacing) API 可以幫助開發(fā)者解決由較短游戲幀造成的拖延現(xiàn)象,以及避免較長游戲幀導致的拖延卡頓。如果設備支持選擇刷新率功能,則可以為玩家提供更靈活和流暢的顯示效果。
實現(xiàn) GameActivity 后,您可以選擇使用 OpenGL/ES 或者 Vulkan 將內(nèi)容渲染到表層。不論您選擇了哪種 API,Android Frame Pacing 庫都會幫您妥善處理渲染過程,它會將游戲的邏輯、渲染循環(huán)與 Android 的顯示子系統(tǒng)、底層顯示相關的硬件進行同步,從而實現(xiàn)更流暢的渲染。
Oboe API
△Oboe API
一款制作精良的游戲離不開出色的音效,這也是 Oboe 音頻庫所提供的能力。您可以在 Android 4.1 及更高版本的系統(tǒng)上使用它的 API。在 API 級別 27 的設備上,Oboe 會通過 AAudio 在設備上盡可能協(xié)調(diào)軟硬件而達到最低的音頻延遲。而對于較低版本的設備,Oboe 會使用 OpenSL ES 來盡可能保證兼容性。
Oboe 在引入重采樣、格式轉(zhuǎn)換、高性能的通道數(shù)轉(zhuǎn)換等多項新功能的同時,還內(nèi)置了一些已知音頻問題的解決方法。
游戲輸入
Android 游戲開發(fā)套件還提供了兩個可以與 GameActivity 互操作的庫,分別用于處理游戲中的軟鍵盤和手柄輸入信號。
游戲文本輸入
GameTextInput 在底層進行了很多復雜的工作,它能將 Android 系統(tǒng)的軟鍵盤連接到您游戲內(nèi)的文本編輯器上,還包括了顯示和隱藏軟鍵盤的操作。
△游戲中的文本輸入邏輯如果您將這個庫與 GameActivity 結合使用,那么無論有沒有使用 native_app_glue,系統(tǒng)都能自動完成相關的配置。請看下面的代碼,GameTextInput 庫會將輸入狀態(tài)傳遞給您的游戲,這樣您的文本編輯器就能正確反映 IME 的狀態(tài)。
/**
* 獲取最后收到的文本輸入狀態(tài)
*/
void GameActivity_getTextInputState(
GameActivity *activity,
GameTextInputGetStateCallback callback,
void*context);
△修改 AndroidManifest.xml 文件
游戲手柄輸入
另一種游戲中常見的輸入設備是游戲手柄 (game controller)。您可以通過使用 Game Controller 庫來充分發(fā)揮實體游戲手柄的作用。這個庫會在手柄連接到設備或斷開連接時向您的游戲發(fā)送通知,并且提供了關于按鈕布局、方向軸和其他按鍵控制器元數(shù)據(jù)的信息。
Game Controller 庫也在底層進行了封裝,讓您不需要復雜的實現(xiàn)也能無縫與各種各樣的手柄輕松連接,甚至還接受鼠標作為輸入設備。
支持大屏幕游戲
在智能電視暢玩游戲
如果您的游戲可以通過方向鍵來控制,并在橫屏模式下正常運行,那么它就可以運行在許多電視設備上。 △在智能電視暢玩游戲要支持在智能電視上運行,您需要對 AndroidManifest.xml 文件做一些修改:△修改 AndroidManifest.xml 文件// 您需要在多個 uses-feature 標簽內(nèi)聲明這些權限:
android.hardware.touchscreen
android.hardware.faketouch
android.hardware.telephony
android.hardware.camera
android.hardware.nfc
android.hardware.location.gps
android.hardware.microphone
android.hardware.sensor
//如果有必要的話,請?zhí)砑觓ndroid.required="false"
您需要在清單中聲明這些權限是非必要的,即 required="false"。這是由于很多您在 AndroidManifest 中提到的權限、功能都不是必須的,智能電視上往往不支持這些功能,比如觸摸屏、攝像頭、加速度傳感器等。您可以通過添加如下代碼,聲明游戲支持使用遙控器作為手柄:
<uses-feature
android:name="android.hardware.gamepad"
android:required="false"/>
在需要時,可以聲明 android:required="true",來表示在啟動應用前電視需要先檢查遙控器是否可用。
在 Chrome OS 運行
Chrome OS 如今已經(jīng)成為了第二大桌面操作系統(tǒng),并且擁有非常多的游戲玩家。它可以直接運行 Android 游戲,并內(nèi)置了 Google Play 商店。玩家可以在運行 Chrome OS 的設備上暢玩支持橫屏的游戲。大多數(shù)設備提供了觸摸屏供玩家操作,對于某些沒有觸摸屏的設備,通常會通過鼠標或觸控板來模擬觸摸屏操作。當然,直接支持鼠標和鍵盤輸入的游戲往往會給玩家?guī)砀玫挠螒蝮w驗。
您可以在游戲中使用類似下面的代碼捕捉鼠標或觸控板事件:
fun onClick(view: View) {
view.requestPointerCapture()
}
override fun onCapturedPointerEvent(motionEvent: MotionEvent): Boolean {
// 捕獲到的指針事件往往提供相對位置
val horizontalOffset: Float = motionEvent.x
val verticalOffset: Float = motionEvent.y
return true
}
△捕捉鼠標或觸控板事件代碼示例
您可以在 API 級別 26 或更高的 Android 上,使用上述代碼捕獲鼠標或觸控板光標,來實現(xiàn)更精準的控制。比如,大多數(shù)場景下,您可能會希望能夠讓與用戶交互的虛擬控件在尺寸更大的屏幕上也能保持合適的相對大小。這就需要您將不同的屏幕尺寸和屏幕顯示密度納入考慮,通過計算得到虛擬控件的大小。按照下面的代碼,您可以獲取當前顯示屏的顯示度量指標,然后獲取 X 軸和 Y 軸的密度以及每英寸像素數(shù),然后計算出虛擬控件的縮放比例。△在托管代碼中獲取屏幕的 DisplayMetricsval dm = resources.displayMetrics
// 用于精確縮放
val xdpi = dm.xdpi
val ydpi = dm.ydpi
// 用縮放因子計算 DPI
val densityDpi = dm.density * 160.0f
valscaledDensityDpi=dm.scaledDensity*160.0f
您還可以使用 dm.density 和 dm.scaledDensity 獲得近似的縮放系數(shù)。其中 1.0 對應著 DPI 值 160。ScaleDensity 用于根據(jù)用戶偏好縮放 Android 應用的字體,所以,當您的游戲支持這一功能,必然會給用戶帶來更佳的體驗。
有時出于性能考慮,您可能會想要設定一個顯示密度的上限。如果您愿意,可以使用 surfaceHolder.setFixedSize 來自動且經(jīng)濟地縮放界面。這樣不僅可以節(jié)省內(nèi)存 (RAM),還可以減少需要著色的像素,并進一步節(jié)省電量和減少發(fā)熱。具體參照下面這段代碼:
var width = mSurfaceView.width
var height = mSurfaceView.height
val dm = resources.displayMetrics
if (dm.density > maxDensity) {
val newScaleFactor = maxDensity / dm.density
if (newScaleFactor != scaleFactor) {
width = (newScaleFactor * width).toInt()
height = (newScaleFactor * height).toInt()
height)
}
△使用 surfaceHolder.setFixedSize 縮放界面
您還可以使用 C/C++ 代碼來自動實現(xiàn)縮放,比如下面的代碼:
int32_t ret = ANativeWindow_setBuffersGeometry(
window,width,height,0);
△使用 C/C++ 實現(xiàn)自動縮放
由于觸控事件始終發(fā)生在屏幕坐標內(nèi),所以無論是用托管代碼還是 C/C++ 實現(xiàn),您都需要調(diào)整觸控事件來匹配新的界面。
不同的游戲引擎有不同的后緩沖區(qū)縮放方式,如下圖列舉的 Unity、Unreal Engine、Godot 在這方面就有明顯的區(qū)別。
△不同游戲引擎縮放后緩沖區(qū)的方法比較Unity 可以通過多種方式縮放后緩沖區(qū)。您可以在 Android Player 設置中調(diào)整最大 DPI 值: 先選擇 Fixed DPI,并拖動選擇一個適當?shù)?DPI 閾值。Unreal Engine 4 支持移動內(nèi)容縮放系數(shù),它提供了設備原生分辨率之外的幾個額外選項。Godot 允許您通過多種方式縮放渲染的內(nèi)容,同時您可以使用基本窗口寬度 (base window width) 來避免渲染時 DPI 過高。另外,Godot 還支持通過腳本的方式獲得屏幕的 DPI 值。 如果您需要游戲支持運行在更多體系結構的 Chrome OS 設備,那么還需要在構建腳本中添加更多 ABI 項:
△在 Gradle 構建腳本中添加 x86/x86_64externalNativeBuild {
cmake {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
}
這是由于很多運行 Chrome OS 的設備都采用了 x86 或者 x86_64 架構。如果您使用某一游戲引擎來開發(fā) Android 游戲,那么您可以從圖中查看目前已知的支持 x86/x86_64 的引擎版本:△在支持 x86/x86_64 的引擎版本舉例當您準備好在 Google Play 商店分發(fā)游戲時,只需選擇這些額外的架構,然后上傳到同一個 Play 商品詳情下即可。這種統(tǒng)一分發(fā)的方式能最大程度簡化您分發(fā)游戲的流程。 Android App Bundle 是一種專門為 Android 平臺設計的應用打包發(fā)布的文件格式。它允許您在不增加文件大小的情況下,在同一個打包中包含各種體系結構的二進制庫文件。隨后 Google Play 會自動為所包含的各種平臺生成一個專門的 APK 文件用于分發(fā)下載。
處理更龐大的素材
使用 PAD 分發(fā)游戲資源
△使用基于 Android App Bundle 的 PAD 格式
很多游戲都需要加載巨量的資源、素材文件,比如 3D 模型、貼圖、音效、視頻過場等等。Play Asset Delivery (PAD) 是一種針對 Android App Bundle 的擴展格式 。有了它,您可以向 Google Play 商店發(fā)布單個工件,而其中同時包含了游戲的代碼部分和資源部分。
△使用 Play Asset DeliveryPAD 這種格式經(jīng)過大量的改進和優(yōu)化,能為您提供更高效的游戲分發(fā)體驗。當您使用 PAD 交付游戲資源時,它會確保代碼和資源的版本一致,從而讓用戶一打開游戲就能獲得最新的二進制文件和資源,不再需要等待資源更新。并且 Google Play 的自動更新功能還可以幫您自動處理增量更新,使得用戶可以在現(xiàn)有游戲版本上直接下載更新產(chǎn)生變化的部分,而不需要重新下載整個游戲。使用 PAD 的另一好處是內(nèi)容下載的優(yōu)化,也就是用戶可以在首次運行游戲時加載必要的資源,隨后需要新內(nèi)容時又繼續(xù)按需加載。
使用紋理壓縮區(qū)分設備
您可以使用紋理壓縮格式 (texture compression format) 將這些內(nèi)容進行劃分,而 Google Play 會幫助您選擇最合適的紋理分發(fā)到不同設備上,從而保證您的游戲在大部分設備上都能實現(xiàn)最高的渲染效率和最佳的渲染效果。△使用紋理壓縮劃分內(nèi)容分發(fā) 使用設備類別劃分△使用設備類別進行區(qū)分
我們當前正努力實現(xiàn)按照設備類別進行定向分發(fā)的功能,這樣一來您只需在每一套資源中分別提供不同類別所需要的資源文件即可。您可以根據(jù) RAM 大小、設備型號等信息,以及物理屏幕大小等硬件特征進行劃分,實現(xiàn)用更小的安裝包覆蓋更龐大的設備群體。
總結
提高 Android 游戲開發(fā)的效率不僅是每個開發(fā)者的期望,也是我們這些年來堅持不懈的理想。通過這篇文章我們分享了高效開發(fā) Android 游戲的一些工具和技巧: Android 游戲開發(fā)套件中新增的 Android 游戲開發(fā)擴展、Android GPU 檢查器、GameActivity、軟鍵盤、游戲手柄和高性能音頻庫及 Android 性能調(diào)優(yōu)工具;另外向您展示了 Play Asset Delivery 格式在分發(fā)游戲資源方面展示出的強大能力。希望這些內(nèi)容能加深您對 Android 開發(fā)的理解,并幫助您開發(fā)出廣受歡迎的游戲作品!歡迎您關注Google 游戲開發(fā)者峰會或在 "Android 開發(fā)者"視頻號觀看詳細中文視頻,我們?yōu)橛螒蜷_發(fā)者精選了 Android 和 Google Play 在本次峰會的重點更新,以及各種工具和服務的最新動態(tài),幫助您打造高質(zhì)量的游戲體驗,助力您的游戲業(yè)務穩(wěn)步發(fā)展。
原文標題:Android 游戲開發(fā)工具大升級
文章出處:【微信公眾號:谷歌開發(fā)者】歡迎添加關注!文章轉(zhuǎn)載請注明出處。
-
Android
+關注
關注
12文章
3936瀏覽量
127397 -
開發(fā)工具
+關注
關注
0文章
209瀏覽量
22257 -
游戲
+關注
關注
2文章
742瀏覽量
26316
原文標題:Android 游戲開發(fā)工具大升級
文章出處:【微信號:Google_Developers,微信公眾號:谷歌開發(fā)者】歡迎添加關注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論