Поддержка изменения размера большого экрана

Переход с телефонов на различные форм-факторы больших экранов требует рассмотрения того, как ваша игра обрабатывает управление окнами. В ChromeOS и Google Play Games for PC ваша игра может работать в оконном режиме через основной интерфейс рабочего стола. На новых планшетах и ​​складных устройствах Android под управлением Android 12L (уровень API 32) или выше с шириной экрана > 600 точек ваша игра может работать параллельно в режиме разделенного экрана с другими приложениями, изменять ее размер и даже перемещаться между внутренней и внешней частью экрана. отображение на складных устройствах , что приводит к изменению конфигурации размера окна и, на некоторых устройствах, ориентации.

Изменение размера в играх 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 Games для ПК платформа обрабатывает изменение размера окна с соблюдением указанного соотношения сторон. Размер окна автоматически фиксируется до оптимального размера. Вам необходимо поддерживать соотношение сторон не менее 16:9, если ваша основная ориентация — альбомная, и соотношение сторон 9:16, если ваша игра — портретный режим. Для достижения наилучших результатов явно поддерживайте соотношения сторон 21:9, 16:10 и 3:2 для ландшафтной игры. Изменение размера окна здесь не требуется, но его все равно полезно иметь для совместимости с другими форм-факторами.

Дополнительную информацию и рекомендации см. в разделе Настройка графики для Google Play Games на ПК.

Большие экраны ChromeOS и Android

Чтобы максимизировать область просмотра вашей игры в полноэкранном режиме на устройствах ChromeOS и Android с большим экраном, поддержите полноэкранный режим погружения и скройте системные панели, установив флаги в decorView , видимости системного пользовательского интерфейса или с помощью API WindowInsetsCompat . Вам также понадобится корректно обрабатывать события конфигурации вращения и изменения размера или предотвращать их возникновение на устройствах ChromeOS.

Обратите внимание, что на устройствах Android с большим экраном ваша игра может работать в конфигурациях, с которыми вы, возможно, еще не справились. Если ваша игра не поддерживает все конфигурации размера и ориентации окна, платформа переводит вашу игру в режим совместимости и, при необходимости, предлагает игроку перейти на неподдерживаемую конфигурацию.

Рисунок 1. Диалоговое окно совместимости конфигурации.

На некоторых устройствах, когда игрок переходит к неподдерживаемой конфигурации, ему может быть предложено перезагрузить игру и воссоздать действие, чтобы оно лучше всего соответствовало новому макету окна, что нарушает игровой процесс. Протестируйте свою игру в различных конфигурациях многооконного режима (размер окна 2/3, 1/2, 1/3) и убедитесь, что ни один элемент игрового процесса или пользовательского интерфейса не обрезается и не становится недоступным. Кроме того, проверьте, как ваша игра реагирует на непрерывность складывания при перемещении между внутренним и внешним экраном на складных устройствах. Если вы видите проблемы, явно обрабатывайте эти события конфигурации и добавьте расширенную поддержку изменения размера большого экрана.

Расширенные возможности изменения размера большого экрана

Рис. 2. Различные пользовательские интерфейсы на рабочем столе и в сложенном положении на столе.

Чтобы выйти из режима совместимости и избежать повторной активности, сделайте следующее:

  1. Объявите свою основную деятельность как изменяемую по размеру:

    <android:resizeableActivity="true" />
    
  2. Объявите явную поддержку «orientation», «screenSize», «smallestScreenSize», «screenLayout» и «density» в атрибуте android:configChanges элемента <activity> манифеста игры, чтобы получать все события конфигурации большого экрана :

    <android:configChanges="screenSize | smallestScreenSize | screenLayout | orientation | keyboard |
                            keyboardHidden | density" />
    
  3. Переопределите onConfigurationChanged() и обработайте событие конфигурации, включая текущую ориентацию, размер, ширину и высоту окна:

    Котлин

    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
    }
    

    Ява

    @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 , чтобы проверить текущее вращение устройства. Используя эти метаданные, проверьте размеры нового окна и выполните рендеринг до полного размера окна. Это может работать не во всех случаях из-за различий в соотношении сторон, поэтому в качестве альтернативы привяжите игровой пользовательский интерфейс к новому размеру окна и почтовому ящику основного игрового контента. Если существуют технические или дизайнерские ограничения, препятствующие любому подходу, создайте собственный почтовый ящик в движке, чтобы сохранить соотношение сторон, и масштабируйте его до максимально возможных размеров, объявив resizeableActivity = false и избегая режима конфигурации.

Независимо от выбранного вами подхода, протестируйте свою игру в различных конфигурациях (складывание и развертывание, различные изменения поворота, режим разделенного экрана) и убедитесь, что в игровом пользовательском интерфейсе нет обрезанных или перекрывающихся элементов, проблем с доступностью сенсорных целей, или проблемы с соотношением сторон, из-за которых игра растягивается, сжимается или иным образом искажается.

Кроме того, большие экраны обычно означают большие пиксели, поскольку у вас одинаковое количество пикселей на гораздо большей площади. Это может привести к пикселизации уменьшенных буферов рендеринга или ресурсов с более низким разрешением. Используйте ресурсы высочайшего качества на устройствах с большим экраном и настраивайте профиль производительности своей игры, чтобы убедиться в отсутствии проблем. Если ваша игра поддерживает несколько уровней качества, убедитесь, что она рассчитана на устройства с большим экраном.

Многооконный режим

Многооконный режим позволяет нескольким приложениям одновременно использовать один и тот же экран. Многооконный режим не меняет жизненный цикл активности ; однако возобновленное состояние приложений в нескольких окнах различается в разных версиях Android (см. Жизненный цикл активности в многооконном режиме в разделе Поддержка многооконного режима ).

Когда игрок переводит приложение или игру в многооконный режим, система уведомляет об изменении конфигурации, как указано в разделе «Расширенные возможности изменения размера большого экрана» . Изменение конфигурации также происходит, когда игрок меняет размер игры или переводит игру обратно в полноэкранный режим.

Нет никакой гарантии, что приложение восстановит фокус при переводе в многооконный режим. Поэтому, если вы используете какое-либо событие состояния приложения для приостановки игры, не полагайтесь на событие получения фокуса ( onWindowFocusChanged() со значением фокуса как true) для возобновления игры. Вместо этого используйте другие обработчики событий или обработчики изменения состояния, такие как onConfigurationChanged() или onResume() . Обратите внимание, что вы всегда можете использовать метод isInMultiWindowMode() , чтобы определить, выполняется ли текущее действие в многооконном режиме.

В многооконном режиме в ChromeOS первоначальные размеры окна становятся важным фактором. Игра не обязательно должна быть полноэкранной, и вам нужно указать, каким должен быть размер окна в этом случае. Есть два рекомендуемых способа сделать это.

Первый вариант работает с использованием определенных атрибутов тега <layout> в манифесте Android. Атрибуты defaultHeight и defaultWidth управляют исходными размерами. Также помните об атрибутах minHeight и minWidth , чтобы ваши игроки не могли изменить размер окна игры до размеров, которые вы не поддерживаете. Наконец, есть атрибут 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. Игра в положении «на столе»: основной вид находится в вертикальной части экрана, элементы управления — в горизонтальной части.

Котлин

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

Ява

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