在为 Android 开发游戏时,务必预测各种可能的玩家体验,并适应玩家的实时交互需求。通过支持不同的玩家体验,你可以提高游戏玩法的灵活性,从而扩大游戏的覆盖范围。
玩家体验的具体差异包括:
- 设备外形尺寸:虽然手机提供了传统的 Android 设备体验,但也可以在其他外形尺寸上与游戏进行交互。ChromeOS 设备可以运行显示游戏的 Android 容器。可以运行 Android 的平板电脑支持多个不同的保真度级别。Android TV 设备支持更细节丰富、更身临其境的体验。玩家可以使用显示扩展工具模拟多窗口环境。使用折叠屏时,玩家可以在游戏过程中更改屏幕大小。
- 交互方式:玩家可以通过触摸设备屏幕来提供输入,但他们也可以使用鼠标、触控板、键盘或控制器。此外,显示扩展工具和折叠屏设备的可用性允许玩家在大屏幕上体验你的游戏,从而使更长的游戏会话和更复杂的界面更可行。
- 硬件支持:一些 Android 设备没有手持设备中更常见的硬件,例如后置摄像头、GPS 和网络连接。你的游戏应该适应可用的硬件,并优雅地处理某些功能不可用的情况。
本指南介绍了与为不同类型的屏幕和用户交互开发游戏相关的最佳实践。本指南还提供了有关游戏设计和制定有效测试策略的建议。
游戏设计最佳实践
在规划游戏的设计和架构时,请遵循以下部分中描述的最佳实践。
手动响应配置更改
当 Android 系统检测到配置更改(例如屏幕大小、屏幕方向或输入方法的更改)时,系统默认会重新启动当前活动。为了在应用或游戏中保留状态,活动默认会在重新启动之前调用onSaveInstanceState()
,并在重新启动之后调用onRestoreInstanceState()
。但是,此过程需要活动重新加载所有关联的服务和资源。要了解有关此默认行为的更多信息,请参阅有关处理配置更改的指南。
典型的游戏会话会经历多次配置更改。如果你的游戏让系统处理每个配置更改,你的游戏的场景会一遍遍地被销毁和重新启动,从而降低游戏的性能。因此,我们强烈建议你在游戏中自行处理这些配置更改。
要了解如何将此配置更改逻辑添加到你的游戏中,请参阅有关如何创建自定义配置更改处理程序的部分。
创建灵活的架构
要尽可能多地在设备上添加对你的游戏的支持,请遵循以下最佳实践:
- 部署 Android 应用包而不是单个 APK。Android 应用包 允许你将不同分辨率和不同架构模型(例如 x86、ARM)的工件打包到单个工件中。更好的是,Android 应用包支持更高的游戏大小限制;每个基本 APK 的大小可达 150 MB,而包本身的大小可以为几 GB。
- 添加对 x86 架构的支持。此步骤提高了游戏在不支持 ARM 的设备上的性能,因为这些设备现在可以执行指令,而无需先进行转换。
添加对 Vulkan 的支持
通过支持Vulkan,你的游戏可以获得更高的图形性能。大多数设备都支持此图形 API。
创建自定义配置更改处理程序
要声明你的游戏自行处理的配置更改类型,请将android:configChanges
属性添加到清单中表示屏幕或复杂界面的每个<activity>
元素。
以下代码片段演示了如何声明你的游戏负责屏幕大小、屏幕方向和输入方法更改:
<activity ... android:configChanges="screenSize|orientation|keyboard|keyboardHidden"> </activity>
发生声明的配置更改时,系统现在会调用不同的方法,onConfigurationChanged()
。在此方法中,添加逻辑以更新游戏 UI。
- 更新屏幕的比例因子和方向。请记住,出于性能考虑,有时最好仅沿一个维度缩放游戏 UI。
- 确定玩家使用的最佳输入方法。
处理屏幕配置更改
当您在`android:configChanges
` 属性中分别包含`screenSize
` 和 `orientation
` 值时,您的游戏会手动处理屏幕尺寸和屏幕方向的变化。您可以使用这些新值来更新场景的内容和玩家输入区域。有关如何设计游戏布局以使其更容易更新的指导,请参阅有关支持不同屏幕尺寸的指南。
在您游戏对`onConfigurationChanged()
` 的实现中,使用传入的 Configuration
对象和窗口管理器的 Display
对象分别确定屏幕尺寸和屏幕方向的更新值。
以下代码片段显示了如何获取游戏更新后的屏幕尺寸和方向
Kotlin
override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) val density: Float = resources.displayMetrics.density val newScreenWidthPixels = (newConfig.screenWidthDp * density).toInt() val newScreenHeightPixels = (newConfig.screenHeightDp * density).toInt() // Get general orientation; either Configuration.ORIENTATION_PORTRAIT or // Configuration.ORIENTATION_LANDSCAPE. val newScreenOrientation: Int = newConfig.orientation // Get general rotation; one of: ROTATION_0, ROTATION_90, ROTATION_180, // or ROTATION_270. val newScreenRotation: Int = windowManager.defaultDisplay.rotation }
Java
@Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); float density = getResources().getDisplayMetrics().density; int newScreenWidthPixels = (int) (newConfig.screenWidthDp * density); int newScreenHeightPixels = (int) (newConfig.screenHeightDp * density); // Get general orientation; either Configuration.ORIENTATION_PORTRAIT or // Configuration.ORIENTATION_LANDSCAPE. int newScreenOrientation = newConfig.orientation; // Get general rotation; one of: ROTATION_0, ROTATION_90, ROTATION_180, // or ROTATION_270. int newScreenRotation = getWindowManager().getDefaultDisplay() .getRotation(); }
请注意,即使您的应用在全屏模式下运行,更改折叠式设备的姿势也会更改配置。因此,如果用户在游戏运行时折叠或展开设备,您的应用可能需要处理屏幕尺寸或像素密度的变化。
游戏特定的屏幕特性
以下部分描述了如何根据游戏的特性调整游戏对屏幕尺寸或屏幕方向变化的反应方式
全屏模式
在某些平台(例如 ChromeOS)上,Android 应用和游戏默认情况下可以窗口化和调整大小。如果您的游戏应该始终在全屏模式下运行,您可以将`android:resizeableActivity
` 属性设置为`false
`,在您的`<activity>
` 元素之一中,如下面的代码片段所示
<activity ... android:resizeableActivity="false"> </activity>
您也可以将`android:resizeableActivity
` 属性设置为`false
` 以防止发生基于大小的配置更改。但是,除非您的游戏始终在全屏模式下运行,否则您应该仅将其作为临时修复程序用于测试目的。
屏幕方向
如果您的游戏依赖于设备的传感器具有特定的方向,请在游戏的 activity 中为`android:screenOrientation
` 指定一个值,如下面的代码片段所示。此设置有助于防止游戏中的场景意外翻转。
<activity ... android:screenOrientation="landscape"> </activity>
设备特定的屏幕特性
以下部分描述了如何在某些设备具有的特定特性下处理基于屏幕的配置更改。
纵横比
某些设备支持不同的纵横比。例如,折叠式设备设计为在折叠状态下支持 21:9 的纵横比。为了处理纵横比的这种潜在差异,请至少执行以下操作之一
- 目标 Android 8.0(API 级别 26)或更高版本。
- 使游戏的场景和界面可调整大小。在 Android 7.0(API 级别 24)和更高版本的设备上,将`
android:resizeableActivity
` 设置为`true
`。 声明最大支持的纵横比。在与您的游戏关联的`
<meta-data>
` 属性中,将`android.max_aspect
` 设置为`2.4
`,如下面的代码片段所示。但是,请记住,大于您指定的值的纵横比会导致游戏在显示器中出现黑边。<application> <meta-data android:name="android.max_aspect" android:value="2.4" /> </application>
同时显示多个 activity
许多现代设备支持各种屏幕布局,包括分屏、画中画和大型显示区域。使用这些布局之一时,系统可以同时显示多个 activity。
在运行 Android 9(API 级别 28)或更高版本的设备上,所有顶部可见的 activity 都可能同时恢复。但是,为了使此行为有效,您的游戏和设备的 OEM 都需要选择加入此功能。您可以通过在游戏的清单中将`android.allow_multiple_resumed_activities
` 设置为`true
` 来在游戏中添加支持,如下面的代码片段所示
<application> <meta-data android:name="android.allow_multiple_resumed_activities" android:value="true" /> </application>
然后,您可以在不同的设备上测试您的游戏,以查看哪些设备提供了多恢复正常运行所需的 OEM 支持。
有关将游戏配置为显示为多窗口显示一部分的更多信息,请参阅有关如何添加多窗口支持的指南。
处理不同类型的交互模型
当您分别在`android:configChanges
` 属性中包含`keyboard
` 和 `keyboardHidden
` 值时,您的游戏会手动处理键盘的存在和可用性。您可以使用这些新值来更新游戏的首要输入方法。
配置游戏以支持多种类型的用户输入时,请记住以下几点
- 检测输入方法而不是单个设备。这种思维方式使改进玩家体验变得更容易,而无需过多关注玩家可能拥有的特定设备。
- 在手动处理的配置更改列表中包含`
keyboardHidden
` 属性。这样,您的游戏可以跟踪键盘何时物理连接到设备但不可用。 确定当前可用的输入方法。为此,请在游戏启动和每次配置更改后,在`
getInputDeviceIds()
` 上调用。您通常可以根据玩家的首选输入设备确定玩家计划如何与您的游戏互动
- 玩家通常使用键盘或游戏控制器执行快速按键序列。
- 玩家通常使用触摸屏或触控板执行更复杂的动作。
- 玩家通常使用鼠标执行更高精度的输入。
以下部分提供了特定类型输入设备的最佳实践。
键盘
创建游戏的键盘布局时,请考虑玩家如何浏览给定场景以及如何与游戏的设置进行交互。
WASD 键或箭头键通常最适合控制角色移动。最好为可控角色在游戏中可以执行的每个重要动作或技能分配一个特定的键。为了最大限度地提高玩家体验,请考虑在游戏中添加对自定义按键绑定的支持。
玩家还应该能够使用键盘打开游戏的菜单并在菜单中导航。`Esc
` 键是暂停场景并显示游戏菜单的常用映射。
有关在游戏中支持键盘输入的更多信息,请参阅有关如何支持键盘导航的指南以及有关如何处理键盘操作的指南。
游戏控制器
有关在游戏中处理控制器输入的更多信息,请参阅有关如何支持游戏控制器的指南。
鼠标或触控板
如果您的游戏支持来自鼠标或触控板的玩家输入,请记住,玩家与设备的交互方式不仅仅是玩游戏。务必注意,通过请求指针捕获,所有鼠标输入都会定向到您的游戏。因此,在您的游戏获得所需信息后,请释放指针捕获,以便玩家恢复对设备的标准鼠标控制。
在 Android 8.0(API 级别 26)和更高版本的设备上,您可以使用鼠标捕获 API 来辅助指针捕获过程。在对高精度输入做出反应的游戏中,您可以通过调用getX()
和getY()
方法来获取指针的当前坐标。
有关在游戏中添加对鼠标输入和触控板输入支持的更多信息,请参阅有关如何跟踪触摸和指针移动的指南以及有关如何处理多点触控手势的指南。
测试你的游戏
在启动游戏之前,请通过完成以下部分中描述的步骤来测试游戏对配置更改的响应方式。
更新您的测试计划
验证游戏的各项功能时,请包含以下测试用例
- 最小化和最大化包含游戏的窗口。(如果游戏始终处于全屏模式,则不适用。)
- 更改屏幕尺寸。
- 更改屏幕方向。(如果游戏具有固定方向,则不适用。)
- 连接和断开输入设备,例如键盘和鼠标。
- 执行多恢复(如果您的游戏支持)。
此外,请考虑更新游戏的质量控制系统,以便您可以针对更广泛的玩家体验进行优化。
有关游戏测试的最佳实践,请参阅测试基础指南。
使用测试和调试工具
您可以使用平台支持的各种工具执行测试
模拟器,包括Android 模拟器和Firebase Test Lab。
系统跟踪.
ChromeOS 性能分析器,在运行 ChromeOS M75 或更高版本时可用。