支持大屏幕可调整大小

从手机扩展到不同的大型屏幕外形尺寸会引入一些关于游戏如何处理窗口管理的注意事项。在 ChromeOSGoogle Play 游戏在电脑上 上,您的游戏可以在主桌面界面上以窗口模式运行。在 新的 Android 平板电脑和折叠屏设备 上运行 Android 12L(API 级别 32)或更高版本,屏幕宽度 > 600dp,您的游戏可以在 分屏模式 下与其他应用程序并排运行,可以调整大小,甚至可以在 折叠屏设备 上的内屏和外屏之间移动,从而导致窗口大小配置更改,并且在某些设备上会导致方向更改。

使用 Unity 游戏调整大小

基本的大屏幕配置

声明您的游戏是否能够处理调整大小

<android:resizeableActivity="true" or "false" />

如果无法支持调整大小,请确保游戏清单显式定义了支持的最小和最大纵横比

<!-- Render full screen between 3:2 and 21:9 aspect ratio -->
<!-- Let the platform letterbox otherwise -->
<activity android:minAspectRatio="1.5">
<activity android:maxAspectRatio="2.33">

Google Play 游戏在电脑上

对于 Google Play 游戏在电脑上,平台在尊重指定纵横比的同时处理窗口调整大小。窗口大小会自动锁定到最佳尺寸。如果您游戏的主要方向是横向,则需要支持至少 16:9 的纵横比;如果您的游戏是纵向模式,则需要支持 9:16 的纵横比。为了获得最佳体验,请显式支持 21:9、16:10 和 3:2 的纵横比,以便横向游戏。这里不需要窗口调整大小,但对于其他外形尺寸的兼容性,它仍然是一个好主意。

有关更多信息和最佳实践,请参阅 为 Google Play 游戏在电脑上配置图形

ChromeOS 和 Android 大屏幕

要在 ChromeOS 和大屏幕 Android 设备上以全屏模式最大限度地提高游戏的可视区域,请支持 全屏沉浸模式 并在 decorView、系统 UI 可见性或通过 WindowInsetsCompat API 上设置标志来隐藏系统栏。您还需要优雅地处理旋转和调整大小配置事件,或者防止它们在 ChromeOS 设备上发生。

请注意,在大屏幕 Android 设备上,您的游戏可以在您可能尚未处理的配置中运行。如果您的游戏不支持所有窗口大小和方向配置,则平台会在 兼容模式 下给您的游戏加黑边,并且如果需要,会在更改为不支持的配置之前提示玩家。

图 1. 配置兼容性对话框。

在某些设备上,当玩家移动到不支持的配置时,可能会收到一个选项,提示他们重新加载游戏并重新创建活动以最适合新的窗口布局,这会破坏游戏体验。在各种多窗口模式配置(2/3、1/2、1/3 窗口大小)中测试您的游戏,并验证没有任何游戏玩法或 UI 元素被切断或无法访问。此外,测试您的游戏在折叠屏设备上从内屏移动到外屏时对折叠式连续性的响应方式。如果您看到问题,请显式处理这些配置事件并添加高级的大屏幕调整大小支持。

高级大屏幕调整大小

图 2. 桌面和折叠屏设备在桌面姿势下的不同 UI。

要退出兼容模式并避免活动重新创建,请执行以下操作

  1. 将您的主要活动声明为可调整大小

    <android:resizeableActivity="true" />
    
  2. 在游戏清单的 <activity> 元素的 android:configChanges 属性中显式声明对“orientation”、“screenSize”、“smallestScreenSize”、“screenLayout”和“density”的支持,以接收 所有大屏幕配置事件

    <android:configChanges="screenSize | smallestScreenSize | screenLayout | orientation | keyboard |
                            keyboardHidden | density" />
    
  3. 重写 onConfigurationChanged() 并处理配置事件,包括当前方向、窗口大小、宽度和高度

    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()
    
       // Configuration.ORIENTATION_PORTRAIT or ORIENTATION_LANDSCAPE
       val newScreenOrientation: Int = newConfig.orientation
    
       // 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);
    
       // Configuration.ORIENTATION_PORTRAIT or ORIENTATION_LANDSCAPE
       int newScreenOrientation = newConfig.orientation;
    
       // ROTATION_0, ROTATION_90, ROTATION_180, or ROTATION_270
       int newScreenRotation = getWindowManager().getDefaultDisplay()
               .getRotation();
    }
    

您还可以查询 WindowManager 以检查当前设备旋转。使用此元数据,检查新的窗口尺寸并渲染到完整的窗口大小。由于纵横比差异,这可能并非在所有情况下都适用,因此,作为替代方法,请将您的游戏 UI 锚定到新的窗口大小,并为您的核心游戏玩法内容加黑边。如果存在技术或设计限制阻止这两种方法,请进行您自己的引擎内加黑边以保持纵横比,并按最佳尺寸进行缩放,同时声明 resizeableActivity = false 并避免配置模式。

无论您采取哪种方法,在各种配置(折叠和展开、不同的旋转更改、分屏模式)中测试您的游戏,并确保没有游戏内 UI 元素被切断或重叠、触控目标可访问性问题或导致游戏被拉伸、压缩或以其他方式扭曲的纵横比问题。

此外,更大的屏幕通常意味着更大的像素,因为您在更大的区域中具有相同数量的像素。这会导致缩小的渲染缓冲区或较低分辨率资产出现像素化。在大屏幕设备上使用您的最高质量资产,并 对您的游戏进行性能分析 以确保没有问题。如果您的游戏支持多个质量级别,请确保它考虑了大屏幕设备。

多窗口模式

多窗口模式 使多个应用程序能够同时共享同一个屏幕。多窗口模式不会更改 活动生命周期;但是,在不同版本的 Android 上,处于多个窗口中的应用程序的恢复状态不同(请参阅 多窗口模式下的活动生命周期,在 支持多窗口模式 中)。

当玩家将应用程序或游戏放入多窗口模式时,系统会通知活动发生配置更改,如 高级大屏幕调整大小 部分中所述。当玩家调整游戏大小或将游戏放回全屏模式时,也会发生配置更改。

不能保证应用程序在放入多窗口模式时会重新获得焦点。因此,如果您使用任何应用程序状态事件来暂停您的游戏,请不要依赖于获取焦点事件 (onWindowFocusChanged(),焦点值为 true) 来恢复游戏。相反,请使用其他事件处理程序或状态更改处理程序,例如 onConfigurationChanged()onResume()。请注意,您始终可以使用 isInMultiWindowMode() 方法来检测当前活动是否正在多窗口模式下运行。

在 ChromeOS 上使用多窗口模式时,初始窗口尺寸是一个重要的考虑因素。游戏不必是全屏的,您需要声明在这种情况下窗口的大小应该是什么。有两种推荐的方法来解决这个问题。

第一个选项通过在 Android 清单中的 <layout> 标签上使用特定属性来实现。 defaultHeightdefaultWidth 属性控制初始尺寸。还要注意 minHeightminWidth 属性,以防止玩家将游戏窗口调整为不支持的尺寸。最后,还有 gravity 属性,它决定窗口启动时在屏幕上的显示位置。以下是用这些属性的布局标签示例。

<layout android:defaultHeight="500dp"
        android:defaultWidth="600dp"
        android:gravity="top|end"
        android:minHeight="450dp"
        android:minWidth="300dp" />

第二个设置窗口大小的选项是通过使用动态启动边界来实现。通过使用 setLaunchBounds(Rect)⁠⁠,可以定义启动窗口的尺寸。如果指定了空矩形,则活动将以最大化状态启动。

此外,如果您使用的是 Unity 或 Unreal 游戏引擎,请确保您使用的是最新版本(Unity 2019.4.40 和 Unreal 5.3 或更新版本),这些版本提供对多窗口模式的良好支持。

可折叠姿势支持

使用 Jetpack WindowManager 布局库 来支持可折叠姿势,例如桌面姿势,以增强玩家的沉浸感和参与度。

图 3. 游戏在桌面姿势下,主视图在显示器的垂直部分,控件在水平部分。

Kotlin

fun isTableTopPosture(foldFeature : FoldingFeature?) : Boolean {
    contract { returns(true) implies (foldFeature != null) }
    return foldFeature?.state == FoldingFeature.State.HALF_OPENED &&
            foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL
}

Java

boolean isTableTopPosture(FoldingFeature foldFeature) {
    return (foldFeature != null) &&
           (foldFeature.getState() == FoldingFeature.State.HALF_OPENED) &&
           (foldFeature.getOrientation() == FoldingFeature.Orientation.HORIZONTAL);
}