Design para telas grandes

Neste guia, você vai aprender a adaptar seu jogo para funcionar em vários formatos do Android.

Antes de começar, leia Oferecer suporte ao redimensionamento de telas grandes. Os jogos modernos no Android precisam se adaptar a todos os tamanhos de tela sem depender de camadas de compatibilidade do sistema. Dessa forma, você sempre tem controle sobre como o jogo é exibido e oferece uma experiência premium ao jogador, mesmo em formatos como XR ou dispositivos em que a tela não pode ser girada.

Para isso, conclua as seguintes tarefas:

  1. Desative o letterboxing do sistema e implemente o seu próprio no mecanismo.
  2. Torne a área de letterbox utilizável e adequada ao tema.
  3. Aborde as considerações de design necessárias para que o jogo seja dimensionado de 21:9 para 1:1 e 9:21.

Comandos para teste

Ao criar e testar o jogo, verifique se ele renderiza as letterboxes. Você também precisa forçar o jogo a usar as orientações retrato e paisagem, porque dispositivos como TVs e telas de carros não podem girar da orientação padrão.

Para verificar se o mecanismo de jogo está usando o letterboxing do sistema, use o comando adb shell cmd window set-letterbox-style. Por exemplo, o comando a seguir torna as letterboxes do sistema verde-claras e adiciona um raio de canto ao jogo, deixando claro se o jogo volta para o modo de compatibilidade do sistema operacional:

adb shell "cmd window set-letterbox-style --backgroundType solid_color --backgroundColor '#00FF00' --cornerRadius 30 --isEducationEnabled false"

Para forçar uma orientação para testes, use adb shell cmd window user-rotation lock. Isso ajuda a simular como o jogo se comporta em um dispositivo que não respeita as substituições de orientação do app ou a entender o que os usuários veem em um dispositivo XR ou semelhante a um PC, em que as janelas podem aparecer em retrato ou paisagem, independente da orientação do dispositivo.

Primeiro, coloque o dispositivo em um estado em que seja possível substituir a orientação do app:

adb shell cmd window set-ignore-orientation-request true
adb shell cmd window fixed-to-user-rotation enabled

Em seguida, teste a mudança do jogo para o modo paisagem:

adb shell cmd window user-rotation lock 1

Em seguida, teste mudar o jogo para o modo retrato:

adb shell cmd window user-rotation lock 0

Redefina o dispositivo para a configuração do OEM reiniciando ou executando os seguintes comandos:

adb shell cmd window reset-letterbox-style
adb shell cmd window fixed-to-user-rotation default
adb shell cmd window user-rotation free
adb shell cmd window set-ignore-orientation-request reset

Por que desativar o letterboxing do sistema?

O sistema sempre controla o letterboxing do sistema. Ao detectar o tamanho da tela e gerenciar a área de exibição por conta própria, é possível reduzir problemas, como entradas perdidas, que ocorrem quando as entradas saem da área do jogo. Também é possível expandir elementos que não são de jogabilidade até a borda da tela, mesmo que o conteúdo do jogo permaneça fixo no meio. Os modos de compatibilidade do sistema podem disponibilizar um jogo, mas cabe a você, como desenvolvedor, torná-lo excelente para os jogadores.

Ilustrações de telas de smartphones, dobráveis, tablets e laptops destacando as áreas de janela ativa.
Figura 1. Formatos de smartphone, dobrável, tablet e laptop.

Exemplo de implementação de letterbox

A maioria dos mecanismos de jogo permite controlar onde uma câmera é renderizada na tela. Para implementar seu próprio letterboxing, meça a proporção da área renderizada e ajuste o retângulo de corte para a área não usada em vez de deixar o sistema aplicar o letterboxing ao jogo. O exemplo a seguir restringe uma câmera à renderização em uma proporção limitada, permitindo que as câmeras ou passagens da interface se expandam para o tamanho lógico total da tela:

Unity

[SerializeField]
private float minAspectRatio = 4f / 3f;

[SerializeField]
private float maxAspectRatio = 21f / 9f;

private Camera _camera;

private void Awake()
{
    _camera = GetComponent<Camera>();
}

public void MaintainAspectRatio()
{
    int viewWidth = Screen.width;
    int viewHeight = Screen.height;

    // 1. Calculate screen aspect ratio
    float scaleScreen = viewWidth / (float)viewHeight;
    Rect rect = _camera.pixelRect;

    // 2. Scale to the fullest of the lower between width or height
    if (scaleScreen > maxAspectRatio)
    {
        // use height, lock width to max at aspect scale
        rect.width = viewHeight * maxAspectRatio;
        rect.height = viewHeight;
    }
    else if (scaleScreen < minAspectRatio)
    {
        // use width, lock height to min at aspect scale
        rect.width = viewWidth;
        rect.height = viewWidth / minAspectRatio;
    }
    else
    {
        // within allowed aspect ratio range, use full screen
        rect.width = viewWidth;
        rect.height = viewHeight;
    }

    rect.x = Mathf.Floor((viewWidth - rect.width) * 0.5f);
    rect.y = Mathf.Floor((viewHeight - rect.height) * 0.5f);

    Debug.Log("camera view width = " + rect.width +
        " height = " + rect.height +
        " x = " + rect.x +
        " y = " + rect.y);

    // 3. Commit the new size to the camera so that it takes effect
    _camera.pixelRect = rect;
}

C++ (Vulkan)

/**
 * @brief Calculates a bounded-aspect-ratio gameplay viewport and scissor
 * rectangle and records them directly into a Vulkan command buffer.
 *
 * @note Requires `VK_DYNAMIC_STATE_VIEWPORT` and `VK_DYNAMIC_STATE_SCISSOR` to
 * be enabled on the bound graphics `VkPipeline`.
 *
 * @param command_buffer   Active `VkCommandBuffer` in the recording state.
 * @param window_width     Full physical window or swapchain width in pixels.
 * @param window_height    Full physical window or swapchain height in pixels.
 * @param min_aspect_ratio Minimum allowed aspect ratio (`width / height`).
 * @param max_aspect_ratio Maximum allowed aspect ratio (`width / height`).
 */
void MaintainAspectRatio(VkCommandBuffer command_buffer, uint32_t window_width,
                         uint32_t window_height, float min_aspect_ratio,
                         float max_aspect_ratio) {
  if (command_buffer == VK_NULL_HANDLE || window_width == 0 ||
      window_height == 0 || min_aspect_ratio <= 0.0f ||
      max_aspect_ratio < min_aspect_ratio) {
    return;
  }

  // 1. Calculate screen aspect ratio.
  const float view_width = static_cast<float>(window_width);
  const float view_height = static_cast<float>(window_height);
  const float scale_screen = view_width / view_height;

  // 2. Scale to the fullest of the lower between width or height.
  float rect_width = view_width;
  float rect_height = view_height;
  if (scale_screen > max_aspect_ratio) {
    // Use height, lock width to max at aspect scale (pillarbox).
    rect_width = std::floor(view_height * max_aspect_ratio);
    rect_height = view_height;
  } else if (scale_screen < min_aspect_ratio) {
    // Use width, lock height to min at aspect scale (letterbox).
    rect_width = view_width;
    rect_height = std::floor(view_width / min_aspect_ratio);
  } else {
    // Within allowed aspect ratio range, use full screen.
    rect_width = view_width;
    rect_height = view_height;
  }

  const float rect_x = std::floor((view_width - rect_width) * 0.5f);
  const float rect_y = std::floor((view_height - rect_height) * 0.5f);

  // 3. Commit the new viewport and scissor to the command buffer so that
  // subsequent gameplay draw calls are transformed and clipped to this region.
  const VkViewport viewport = {
      .x = rect_x,
      .y = rect_y,
      .width = rect_width,
      .height = rect_height,
      .minDepth = 0.0f,
      .maxDepth = 1.0f,
  };
  const VkRect2D scissor = {
      .offset =
          {
              .x = static_cast<int32_t>(rect_x),
              .y = static_cast<int32_t>(rect_y),
          },
      .extent =
          {
              .width = static_cast<uint32_t>(rect_width),
              .height = static_cast<uint32_t>(rect_height),
          },
  };

  vkCmdSetViewport(command_buffer, 0, 1, &viewport);
  vkCmdSetScissor(command_buffer, 0, 1, &scissor);
}

Para ver um tutorial detalhado no Unity, consulte o codelab Como otimizar jogos do Unity para telas grandes e dobráveis.

Processar tamanhos de tela grandes e pequenos

Em telas menores, como smartphones e telas externas de dobráveis, a melhor experiência do usuário pode ser um jogo bloqueado no modo retrato ou paisagem. À medida que as telas ficam maiores, como em tablets, Chromebooks, telas de carros ou telas internas de dobráveis, fica menos desejável ou até mesmo impossível girar o dispositivo, enquanto a tela física maior mantém o jogo jogável em proporções fora do eixo.

Para oferecer a melhor experiência aos jogadores, detecte o tamanho da tela no momento da execução e restrinja a rotação quando necessário, oferecendo mais flexibilidade aos jogadores à medida que o tamanho da tela aumenta. O Android considera o limite ideal como sw600dp, uma largura mínima de 600 pixels independente de densidade (600 dp). Isso se correlaciona com WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND. Use computeMaximumWindowMetrics para validar o tamanho de tela disponível em configurações de várias telas.

Para oferecer suporte a isso no seu jogo, aceite todas as orientações no manifesto e, em onCreate() e onConfigurationChanged(), avalie a menor largura e defina o bloqueio de orientação adequadamente:

  1. Remova os bloqueios de orientação estática no manifesto e declare o processamento de mudanças de configuração:

    <activity
        android:name=".MainActivity"
        android:resizeableActivity="true"
        android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|density|keyboard|keyboardHidden" />
    
  2. Adicione as importações necessárias:

    import android.content.pm.ActivityInfo
    import android.content.res.Configuration
    import android.os.Bundle
    import androidx.activity.enableEdgeToEdge
    import androidx.window.core.layout.WindowSizeClass
    import androidx.window.layout.WindowMetricsCalculator
    import kotlin.math.min
    
  3. Processar onCreate e onConfigurationChanged:

    override fun onCreate(savedInstanceState: Bundle?) {
        enableEdgeToEdge()
        super.onCreate(savedInstanceState)
        applyAdaptiveOrientationPolicy()
        // ...
    }
    
    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        applyAdaptiveOrientationPolicy()
        // ...
    }
    
  4. Atualize a orientação solicitada com base na menor largura de tela, bloqueando as telas compactas na orientação de design preferida do jogo:

    private fun applyAdaptiveOrientationPolicy() {
        // compute the smallest screen bound in dp
        val maxMetrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this)
        val minDimensionPx = min(maxMetrics.bounds.width(), maxMetrics.bounds.height())
        val displaySmallestWidthDp = minDimensionPx / maxMetrics.density
    
        val targetOrientation = if (displaySmallestWidthDp >= WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND) {
            // Large display (>= 600dp): allow free rotation in any orientation
            ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
        } else {
            // Compact display (< 600dp): lock to your game's preferred orientation
            // (use SCREEN_ORIENTATION_SENSOR_LANDSCAPE for landscape-first games)
            ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
        }
    
        // Guard against redundant setter calls to avoid configuration change loops
        if (requestedOrientation != targetOrientation) {
            requestedOrientation = targetOrientation
        }
    }
    

Projetar considerando problemas comuns

Oferecer suporte a uma variedade de proporções e orientações proporciona aos jogadores a melhor experiência do usuário possível. Ao contrário dos smartphones, as telas maiores geralmente são fixas na orientação paisagem ou retrato e, em alguns casos, são quase quadradas. Nesses dispositivos maiores, os jogadores costumam realizar várias tarefas ao mesmo tempo enquanto jogam. Ao maximizar o uso do espaço da tela, você pode atrair mais jogadores com mais frequência e por sessões de jogo mais longas.

As seções a seguir oferecem soluções para que seu jogo pareça uma experiência premium em todos os formatos, em vez de um jogo para smartphone incorporado em uma tela que não é de smartphone.

Câmeras com reconhecimento de proporção

Em jogos 3D, se uma tela for muito alta, os jogadores podem sentir que estão vendo o jogo por uma fresta estreita. Se for muito larga, eles podem perder interações projetadas. Assim como nos jogos 2D, é possível manter uma "área segura" sempre visível. O código a seguir alterna uma câmera entre um campo de visão horizontal e um vertical com base na comparação entre a proporção ativa e uma proporção de referência de 1920 x 1080. Dessa forma, um designer pode criar um jogo para uma tela de 1080p e saber que tudo o que foi projetado dentro desse frame de referência permanece visível:

Unity

[SerializeField]
private Camera _camera;

[SerializeField]
private float _referenceWidth = 1920f;

[SerializeField]
private float _referenceHeight = 1080f;

[SerializeField]
private float _referenceVerticalFov = 60f;

public float ReferenceAspectRatio => _referenceWidth / Mathf.Max(0.0001f, _referenceHeight);

private void Awake()
{
    if (_camera == null)
    {
        _camera = GetComponent<Camera>();
    }
}

// Built-in Render Pipeline callback. In URP, subscribe to
// RenderPipelineManager.beginCameraRendering or call UpdateFov() on resize.
private void OnPreCull()
{
    UpdateFov();
}

public void UpdateFov()
{
    if (_camera == null || _camera.orthographic)
    {
        return;
    }

    float referenceAspect = ReferenceAspectRatio;
    float currentAspect = _camera.aspect;
    if (currentAspect <= 0.0001f)
    {
        return;
    }

    float targetVerticalFov;

    if (currentAspect >= referenceAspect)
    {
        // Viewport is wider than (or equal to) the reference safe area
        targetVerticalFov = _referenceVerticalFov;
    }
    else
    {
        // Viewport is skinnier than the reference safe area
        float referenceHorizontalFov = Camera.VerticalToHorizontalFieldOfView(_referenceVerticalFov, referenceAspect);
        targetVerticalFov = Camera.HorizontalToVerticalFieldOfView(referenceHorizontalFov, currentAspect);
        targetVerticalFov = Mathf.Clamp(targetVerticalFov, 1f, 179f);
    }

    if (!Mathf.Approximately(_camera.fieldOfView, targetVerticalFov))
    {
        _camera.fieldOfView = targetVerticalFov;
    }
}

C++ (Vulkan)

/**
 * @brief Calculates an aspect-aware Vulkan perspective projection matrix using
 * GLM that keeps a reference safe area (e.g., 1920x1080) visible across
 * aspect ratios.
 *
 * @note Uses `glm::perspectiveZO` for Vulkan's `[0, 1]` depth range and
 * inverts `projection[1][1]` for Vulkan's top-left (`+Y` down) clip space.
 *
 * @param viewport_width         Active gameplay viewport width in pixels.
 * @param viewport_height        Active gameplay viewport height in pixels.
 * @param reference_width        Authored safe-area reference width in pixels.
 * @param reference_height       Authored safe-area reference height in pixels.
 * @param reference_vertical_fov Authored vertical FOV in degrees (e.g., 60.0f).
 * @param near_plane             Near clipping plane distance (`zNear > 0.0f`).
 * @param far_plane              Far clipping plane distance (`zFar > zNear`).
 * @return Aspect-aware `glm::mat4` perspective projection matrix for Vulkan.
 */
glm::mat4 CalculateAspectAwareProjectionMatrix(
    float viewport_width, float viewport_height, float reference_width = 1920.0f,
    float reference_height = 1080.0f, float reference_vertical_fov = 60.0f,
    float near_plane = 0.1f, float far_plane = 100.0f) {
  if (viewport_width <= 0.0001f || viewport_height <= 0.0001f) {
    return glm::mat4(1.0f);
  }

  // 1. Compare the active viewport aspect ratio against the reference safe
  // area.
  const float reference_aspect =
      reference_width / std::max(0.0001f, reference_height);
  const float current_aspect = viewport_width / viewport_height;

  float target_vertical_fov_rad = glm::radians(reference_vertical_fov);

  if (current_aspect >= reference_aspect) {
    // Viewport is wider than (or equal to) the reference safe area (Hor+).
    target_vertical_fov_rad = glm::radians(reference_vertical_fov);
  } else {
    // Viewport is skinnier than the reference safe area (Vert+):
    // Convert reference vertical FOV -> reference horizontal FOV -> new
    // vertical FOV at current_aspect so the safe area is never cropped.
    const float tan_half_horiz =
        std::tan(target_vertical_fov_rad * 0.5f) * reference_aspect;
    target_vertical_fov_rad = 2.0f * std::atan(tan_half_horiz / current_aspect);
    target_vertical_fov_rad = std::clamp(
        target_vertical_fov_rad, glm::radians(1.0f), glm::radians(179.0f));
  }

  // 2. Build the Vulkan [0, 1] depth perspective matrix and flip +Y clip space.
  glm::mat4 projection = glm::perspectiveZO(
      target_vertical_fov_rad, current_aspect, near_plane, far_plane);
  projection[1][1] *= -1.0f;
  return projection;
}

Letterboxes totalmente interativos

Alguns jogos têm uma área de jogo fixa por design, geralmente de acordo com considerações de design baseadas em gênero, como o campo fixo de um jogo de tiro vertical ou a rolagem de tela invertida usada para uma estética retrô.

Para esses jogos, dimensione a área de jogabilidade para que um eixo do jogo seja sempre maximizado para preencher a área de jogabilidade. O eixo maximizado pode mudar com base nas proporções relativas do jogo e nos limites da tela.

Ancore os elementos de HUD e interface até a borda segura da tela: evite recortes, mas coloque elementos interativos, como controles virtuais, barras de vida e minimapas, o mais longe possível da área de jogo. Dessa forma, a parte interativa do jogo usa a tela inteira, e os jogadores em formatos como tablets e dobráveis podem jogar confortavelmente sem precisar esticar demais os dedos.

Por fim, use um tema adequado ou diegético na área de letterbox. Considere bordas que combinem com a paleta ou o conjunto de blocos na tela, uma mesa ou tela virtual para jogos de tabuleiro ou retrô, ou minimapas estendidos e recursos visuais decorativos.

No exemplo a seguir, o jogo é renderizado em tamanho normal para a maioria das proporções. Quando a proporção é menor que 4:3, ele renderiza um skybox com cores temáticas, mas continua posicionando os elementos da interface, como controles, na borda da tela:

Jogo de floresta com rolagem lateral renderizado em sangria total em uma janela de paisagem ampla com controles por toque nos cantos.
Figura 2. Jogo renderizado em tamanho normal em uma proporção ampla padrão.
Jogo de floresta com rolagem lateral em uma janela mais estreita que 4:3, mostrando barras de letterbox com folhagem amarela temática e controles por toque fixados nas bordas externas da tela.
Figura 3. Jogo com uma proporção menor que 4:3 renderizando um skybox temático com controles de interface fixados nas bordas da tela.

Cinza Fog

Muitos desenvolvedores de jogos se preocupam com a possibilidade de os jogadores terem uma vantagem injusta com proporções extremas verticais ou horizontais. Por exemplo, um jogador em um jogo competitivo, como uma arena de batalha multiplayer on-line (MOBA, na sigla em inglês), pode usar uma tela muito vertical para ter uma visão profunda da rota de um oponente.

Para jogos de estratégia e simulação de cima para baixo, considere renderizar uma névoa de guerra:

  • Não renderize a geometria até que o jogador possa vê-la.
  • Renderize a geometria que o personagem do jogador não consegue ver ativamente como esmaecida, sem elementos dinâmicos.
  • Renderize apenas oponentes, itens colecionáveis e outros objetos dinâmicos que o personagem do jogador pode ver de forma diegética.

Se você combinar essa técnica com letterboxes totalmente interativas e renderizar sua interface até a borda da tela, o jogador terá uma experiência refinada e intencional, sem que você precise reformular a estrutura de níveis ou o equilíbrio da equipe.

Expandir esse jogo para preencher uma tela maior sem uma névoa de guerra revela partes do mapa que o jogador não deveria ver:

RPG de cima para baixo em uma tela pequena mostrando o Sir Bugdroid segurando um escudo e uma lanterna perto de uma espada brilhante em um pedestal, uma ponte sobre um rio e trilhos de carrinho de mina.
Figura 4. Visualização original da câmera em uma tela menor.
Visualização expandida do mesmo mapa de RPG de cima para baixo em uma tela grande, revelando um golem e um baú de tesouro dentro de uma masmorra e goblins do outro lado do rio.
Figura 5. Visualização expandida que revela partes do mapa que o jogador não deveria ver.

Ao renderizar uma névoa de guerra e ocultar elementos dinâmicos, como inimigos e itens, você mantém a imparcialidade no jogo enquanto usa todo o frame disponível para o jogo:

RPG de cima para baixo em uma tela pequena mostrando a área ativa ao redor do jogador.
Figura 6. Área visível ativa ao redor do personagem do jogador.
Visualização expandida do mapa de RPG de cima para baixo, em que o terreno distante é escurecido e os inimigos e itens fora da linha de visão do jogador ficam ocultos.
Figura 7. Visualização expandida com uma névoa de guerra que escurece o terreno distante e oculta elementos dinâmicos.

Esmaecer geometria

Muitos jogos, especialmente no espaço de estratégia baseado em turnos, usam uma técnica semelhante à névoa de guerra descrita na seção anterior e não renderizam a geometria que o jogador não descobriu ou com que não pode interagir durante um determinado cenário.

Se um campo de visão expandido revelar partes do cenário ou da cena que o jogador não deveria ver, mascarar certas partes da cena de maneira limpa alcança o mesmo efeito prático de um letterbox sem a percepção de uma borda estática fixa.

No exemplo a seguir, expandir o jogo para uma proporção maior revela uma horda de zumbis fora das paredes do castelo:

Visão isométrica de RPG tático do Bugdroid e do Mecha Hamster dentro das muralhas de um castelo.
Figura 8. Área de jogo dentro das paredes do castelo em uma proporção mais estreita.
Visualização isométrica expandida de RPG tático revelando uma horda de inimigos esperando do lado de fora do portão inferior do castelo.
Figura 9. Proporção maior que revela uma horda de zumbis do lado de fora das muralhas do castelo.

Em vez disso, você pode omitir a geometria do nível de renderização além dos limites da área de jogo atual:

Visão isométrica de RPG tático do Bugdroid e do Mecha Hamster dentro das muralhas do castelo.
Figura 10. Área de recreação dentro das muralhas do castelo.
Visualização isométrica expandida de RPG tático em que a geometria do nível e os inimigos fora das paredes do castelo são omitidos.
Figura 11. Proporção maior em que a geometria do nível não é renderizada além da área de jogo atual.

Limites diegéticos

Em jogos 3D imersivos, em que um campo de visão ampliado pode levar a uma vantagem competitiva em jogos multiplayer em primeira ou terceira pessoa ou revelar áreas não autorizadas de jogos baseados em conjuntos fixos, considere criar elementos diegéticos no jogo para limitar o campo de visão em vez de usar um letterbox retangular. Por exemplo:

  • O interior de um veículo, como um carro ou avião
  • O interior de um capacete
  • Uma vinheta que indica o limite da visão de um jogador

Os elementos da interface e do HUD ainda precisam se estender até a borda da tela ou ser incorporados aos limites diegéticos, e o ideal é que sejam dinâmicos. Esses elementos diegéticos também podem ajudar os jogadores que têm enjoo de movimento, especialmente em formatos XR, oferecendo um recurso de acessibilidade, além de ajudar a reduzir a complexidade das novas proporções.

Evite renderizar o jogo em uma superfície dentro de uma cena estática não interativa. Embora essa abordagem seja melhor do que renderizar barras pretas para letterboxes e pillarboxes, os jogadores percebem rapidamente as bordas estáticas e podem ficar frustrados se os jogos favoritos forem renderizados em uma parte da tela do tamanho de um smartphone em formatos que não são de smartphone.

Neste exemplo, um jogo projetado para uma tela de smartphone padrão é renderizado em uma televisão simulada com um gamepad esqueumórfico para acomodar a proporção mais quadrada comum nas telas internas de dobráveis:

Jogo de labirinto 3D renderizado dentro de um quadro de TV CRT simulado com um gamepad esqueumórfico em primeiro plano.
Figura 12. Jogo renderizado dentro de um frame de televisão simulado estático com um gamepad esqueumórfico.

Alguns jogos em 3D podem precisar restringir o campo de visão para garantir a competitividade ou por considerações de design. Usar uma cabine, um capacete ou outra metáfora diegética para restringir o campo de visão é preferível a barras pretas:

Visão em primeira pessoa de um labirinto 3D de dentro de uma cabine esférica de hamster, com um minimapa na parte de cima e controles por toque na parte de baixo.
Figura 13. O cockpit esférico diegético restringe o campo de visão enquanto fixa o HUD e os controles nas bordas da tela.

Outros recursos