Разрабатывайте игры для всех экранов

При разработке игры для Android важно предвидеть разнообразие возможных вариантов взаимодействия игрока с системой и адаптироваться к потребностям игрока в реальном времени. Поддержка различных вариантов взаимодействия повышает гибкость игрового процесса, что помогает расширить охват вашей игры.

К конкретным различиям в игровом опыте относятся следующие:

  • Форм-факторы устройств: Хотя телефоны обеспечивают традиционный опыт использования устройств Android, взаимодействовать с играми можно и на других форм-факторах. Устройства ChromeOS могут запускать контейнер Android, отображающий вашу игру. Планшеты, работающие под управлением Android, поддерживают несколько различных уровней детализации. Устройства Android TV обеспечивают более детализированный и захватывающий игровой процесс. Игроки могут имитировать многооконную среду, используя инструмент расширения дисплея. А при использовании складных устройств игроки могут изменять размер экрана во время игровой сессии.
  • Способы взаимодействия: Игроки могут вводить данные, касаясь экрана устройства, но также могут использовать мышь, тачпад, клавиатуру или контроллер. Кроме того, наличие инструментов расширения экрана и складных устройств позволяет игрокам наслаждаться игрой на большом экране, что делает более длительные игровые сессии и более сложные интерфейсы более осуществимыми.
  • Поддержка оборудования: Некоторые устройства на базе Android не имеют аппаратного обеспечения, более типичного для портативных устройств, такого как задняя камера, GPS и сетевое подключение. Ваша игра должна адаптироваться к доступному оборудованию и корректно обрабатывать ситуации, когда определенные функции недоступны.

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

лучшие практики игрового дизайна

При планировании дизайна и архитектуры вашей игры следуйте рекомендациям, описанным в следующих разделах.

Реагируйте на изменения конфигурации вручную.

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

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

Чтобы узнать, как добавить эту логику изменения конфигурации в вашу игру, см. раздел о создании пользовательских обработчиков изменения конфигурации .

Создайте гибкую архитектуру.

Чтобы обеспечить поддержку вашей игры на как можно большем количестве устройств, следуйте этим рекомендациям:

  • Вместо отдельных APK-файлов используйте пакеты приложений Android. Пакеты приложений Android позволяют объединять артефакты разного разрешения и архитектуры, например, x86, ARM, в один артефакт. Более того, пакеты приложений Android поддерживают более высокие ограничения по размеру для вашей игры; каждый базовый APK-файл может достигать 150 МБ, а сам пакет может занимать несколько гигабайт.
  • Добавьте поддержку архитектур x86. Этот шаг улучшит производительность вашей игры на устройствах, не поддерживающих ARM, поскольку теперь эти устройства могут выполнять инструкции без предварительной трансляции.

Добавить поддержку Vulkan

Поддержка Vulkan позволит вашей игре добиться более высокой графической производительности. Большинство устройств поддерживают этот графический API.

Создайте пользовательские обработчики изменений конфигурации.

Чтобы указать типы изменений конфигурации, которые ваша игра обрабатывает самостоятельно, добавьте атрибут android:configChanges к каждому элементу <activity> в вашем манифесте, который представляет собой экран или сложный интерфейс.

Следующий фрагмент кода демонстрирует, как объявить, что ваша игра сама обрабатывает изменения размера экрана, ориентации экрана и метода ввода:

<activity ...
    android:configChanges="screenSize|orientation|keyboard|keyboardHidden">
</activity>

При изменении объявленной конфигурации система теперь вызывает другой метод — onConfigurationChanged() . В этом методе добавьте логику для обновления пользовательского интерфейса вашей игры:

Обработка изменений конфигурации экрана

В игре изменения размера и ориентации экрана обрабатываются вручную, если вы указываете значения screenSize и orientation соответственно в атрибуте android:configChanges . Вы можете использовать эти новые значения для обновления содержимого сцены и областей ввода игрока. Рекомендации по проектированию макета игры для упрощения обновления см. в руководстве по поддержке различных размеров экрана .

В реализации метода onConfigurationChanged() в вашей игре используйте переданный объект Configuration и объект Display оконного менеджера для определения обновленных значений размера экрана и ориентации экрана соответственно.

Следующий фрагмент кода показывает, как получить обновленный размер и ориентацию экрана вашей игры:

Котлин

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 , чтобы предотвратить изменение конфигурации в зависимости от размера. Однако, если ваша игра не всегда работает в полноэкранном режиме, добавлять этот атрибут следует только в качестве временного решения для целей тестирования.

Ориентация экрана

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

<activity ...
    android:screenOrientation="landscape">
</activity>

Характеристики экрана, специфичные для конкретного устройства

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

Соотношение сторон

Некоторые устройства поддерживают разные соотношения сторон. Например, складные устройства разработаны для поддержки соотношения сторон 21:9 в сложенном состоянии. Чтобы справиться с таким потенциальным разнообразием соотношений сторон, выполните хотя бы одно из следующих действий:

  • Целевая платформа: Android 8.0 (уровень API 26) или выше.
  • Сделайте сцену и интерфейс вашей игры изменяемыми по размеру. Установите параметр android:resizeableActivity в true на устройствах под управлением Android 7.0 (уровень API 24) и выше.
  • Укажите максимальное поддерживаемое соотношение сторон. В атрибуте <meta-data> , связанном с вашей игрой, установите android.max_aspect равным 2.4 , как показано в следующем фрагменте кода. Однако имейте в виду, что соотношения сторон, превышающие указанное вами значение, приведут к тому, что игра будет отображаться с черными полосами по бокам экрана.

    <application>
    <meta-data android:name="android.max_aspect"
               android:value="2.4" />
    </application>

Одновременно отображается несколько действий

Многие современные устройства поддерживают различные варианты расположения элементов на экране, включая разделенный экран, «картинка в картинке» и большие области отображения. При использовании одного из этих режимов система может отображать несколько действий одновременно.

На устройствах под управлением Android 9 (уровень API 28) и выше возможно одновременное возобновление всех видимых сверху действий. Однако для корректной работы этой функции необходимо, чтобы и ваша игра, и производитель устройства её поддерживали. Добавить поддержку в игру можно, установив параметр android.allow_multiple_resumed_activities в true в манифесте игры, как показано в следующем фрагменте кода:

<application>
    <meta-data android:name="android.allow_multiple_resumed_activities"
               android:value="true" />
</application>

Затем вы можете протестировать свою игру на разных устройствах, чтобы определить, какие из них обеспечивают необходимую поддержку производителя для корректной работы многократного возобновления игры.

Для получения дополнительной информации о настройке игры для отображения в многооконном режиме см. руководство по добавлению поддержки многооконного режима .

Обработка различных типов моделей взаимодействия

В игре отображение наличия и доступности клавиатуры обрабатывается вручную, если вы указываете значения keyboard и keyboardHidden соответственно в атрибуте android:configChanges . Вы можете использовать эти новые значения для обновления основного метода ввода в игре.

При настройке игры для поддержки различных типов пользовательского ввода учитывайте следующее:

  • Определяйте методы ввода, а не отдельные устройства. Такой подход упрощает улучшение пользовательского опыта без чрезмерного сосредоточения на конкретном устройстве, которое может использовать игрок.
  • Включите атрибут keyboardHidden в список изменений конфигурации, выполняемых вручную. Таким образом, ваша игра сможет отслеживать, когда клавиатура физически подключена к устройству, но недоступна для использования.
  • Определите доступные в данный момент методы ввода. Для этого вызывайте метод getInputDeviceIds() при запуске игры и после каждого изменения конфигурации.

    Зачастую можно определить, как игрок планирует взаимодействовать с вашей игрой, исходя из предпочитаемого им устройства ввода:

    • Игроки обычно используют клавиатуру или игровой контроллер для выполнения быстрых последовательностей нажатий кнопок.
    • Игроки обычно используют сенсорный экран или тачпад для выполнения более сложных жестов.
    • Игроки обычно используют мышь для выполнения более точных действий.

В следующих разделах представлены рекомендации по использованию конкретных типов устройств ввода.

Клавиатура

При создании раскладки клавиатуры для вашей игры учитывайте, как игрок перемещается по той или иной сцене, а также как он взаимодействует с настройками игры.

Для управления движением персонажа обычно лучше всего подходят клавиши WASD или стрелки. Также рекомендуется назначить отдельную клавишу для каждого важного действия или навыка, который может выполнять управляемый персонаж в вашей игре. Для максимального удобства игрока рассмотрите возможность добавления поддержки пользовательских назначений клавиш в вашу игру.

Игроки также должны иметь возможность открывать меню вашей игры и перемещаться по ним с помощью клавиатуры. Клавиша Esc — это распространенная комбинация клавиш для приостановки сцены и отображения меню игры.

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

Игровой контроллер

Для получения дополнительной информации об обработке ввода с контроллера в вашей игре см. руководство по поддержке игровых контроллеров .

Мышь или сенсорная панель

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

На устройствах под управлением Android 8.0 (уровень API 26) и выше можно использовать API захвата мыши для помощи в процессе захвата указателя. В играх, реагирующих на высокоточный ввод, можно получить текущие координаты указателя, вызвав методы getX() и getY() .

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

Протестируйте свою игру

Перед запуском игры проверьте, как она реагирует на изменения конфигурации, выполнив действия, описанные в следующих разделах.

Обновите свой план тестирования.

При проверке функциональности вашей игры включите следующие тестовые примеры:

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

Также стоит подумать об обновлении системы контроля качества вашей игры, чтобы оптимизировать её для более широкого круга игроков.

Рекомендации по тестированию игры см. в руководстве «Основы тестирования» .

Используйте инструменты тестирования и отладки.

Вы можете проводить тестирование, используя различные инструменты, поддерживаемые платформой: