在为 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 应用和游戏默认可以是窗口化的并且可以调整大小。如果您的游戏应始终在全屏模式下运行,则可以在<activity>
元素之一中将android:resizeableActivity
属性设置为false
,如下面的代码片段所示
<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 测试实验室。
系统跟踪.
ChromeOS 性能分析器,在运行 ChromeOS M75 或更高版本时可用。