Thiết kế cho màn hình lớn

Trong hướng dẫn này, bạn sẽ tìm hiểu cách điều chỉnh trò chơi để hoạt động trên nhiều kiểu dáng Android.

Trước khi bắt đầu, hãy đọc bài viết Hỗ trợ khả năng đổi kích thước màn hình lớn. Các trò chơi hiện đại trên Android phải thích ứng với mọi kích thước màn hình mà không cần dựa vào các lớp tương thích của hệ thống. Bằng cách này, bạn luôn có quyền kiểm soát cách hiển thị trò chơi và trò chơi của bạn mang lại trải nghiệm cao cấp cho người chơi, ngay cả trên các kiểu dáng như XR hoặc thiết bị không thể xoay màn hình.

Để làm việc này, hãy hoàn thành các nhiệm vụ sau:

  1. Tắt hiệu ứng hòm thư của hệ thống và triển khai hiệu ứng hòm thư của riêng bạn trong công cụ.
  2. Tạo vùng hòm thư có thể sử dụng và phù hợp với chủ đề.
  3. Giải quyết các yếu tố cần cân nhắc về thiết kế để trò chơi của bạn có thể điều chỉnh tỷ lệ từ 21:9 đến 1:1 và 9:21.

Lệnh để kiểm thử

Khi tạo và thử nghiệm trò chơi, hãy xác minh rằng trò chơi của bạn tự kết xuất mọi hộp thư. Bạn cũng nên buộc trò chơi của mình chuyển sang hướng dọc và ngang, vì các thiết bị như TV và màn hình trên ô tô không thể xoay từ hướng ngang hoặc dọc mặc định.

Để kiểm tra xem công cụ phát triển trò chơi của bạn có đang sử dụng tính năng hòm thư hệ thống hay không, hãy dùng lệnh adb shell cmd window set-letterbox-style. Ví dụ: lệnh sau đây làm cho hòm thư hệ thống có màu xanh lục sáng và thêm bán kính góc vào trò chơi của bạn, giúp bạn dễ dàng nhận biết nếu trò chơi của bạn quay lại chế độ tương thích của hệ điều hành:

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

Để buộc hướng cho hoạt động kiểm thử, hãy sử dụng adb shell cmd window user-rotation lock. Điều này giúp bạn mô phỏng cách trò chơi hoạt động trên một thiết bị không tuân theo chế độ ghi đè ứng dụng cho hướng hoặc hiểu những gì người dùng thấy trên thiết bị XR hoặc thiết bị giống như máy tính, nơi cửa sổ có thể xuất hiện ở chế độ dọc hoặc ngang độc lập với hướng thiết bị.

Trước tiên, hãy đặt thiết bị của bạn ở trạng thái có thể ghi đè hướng ứng dụng:

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

Tiếp theo, hãy thử thay đổi trò chơi sang chế độ ngang:

adb shell cmd window user-rotation lock 1

Sau đó, hãy thử thay đổi trò chơi sang chế độ dọc:

adb shell cmd window user-rotation lock 0

Đặt lại thiết bị về cấu hình OEM bằng cách khởi động lại hoặc chạy các lệnh sau:

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

Tại sao nên tắt tính năng hòm thư hệ thống?

Hệ thống luôn kiểm soát hiệu ứng hòm thư của hệ thống. Bằng cách phát hiện kích thước màn hình và tự quản lý vùng hiển thị, bạn có thể giảm thiểu các vấn đề (chẳng hạn như thao tác nhập bị bỏ qua) xảy ra khi thao tác nhập rời khỏi vùng trò chơi. Bạn cũng có thể mở rộng các thành phần không thuộc lối chơi ra cạnh màn hình, ngay cả khi nội dung trò chơi vẫn cố định ở giữa. Chế độ tương thích hệ thống có thể giúp trò chơi hoạt động, nhưng việc mang đến trải nghiệm tuyệt vời cho người chơi là tuỳ thuộc vào bạn, nhà phát triển trò chơi.

Hình minh hoạ màn hình điện thoại, thiết bị gập, máy tính bảng và máy tính xách tay làm nổi bật các vùng cửa sổ đang hoạt động.
Hình 1. Kiểu dáng điện thoại, thiết bị gập, máy tính bảng và máy tính xách tay.

Triển khai mẫu hộp thư

Hầu hết các công cụ phát triển trò chơi đều cho phép bạn kiểm soát vị trí máy ảnh kết xuất trên màn hình. Để triển khai hiệu ứng hòm thư của riêng bạn, hãy đo lường tỷ lệ khung hình của vùng hiển thị và điều chỉnh hình chữ nhật cắt cho vùng không sử dụng thay vì để hệ thống tạo hiệu ứng hòm thư cho trò chơi của bạn. Mẫu sau đây giới hạn một camera chỉ hiển thị theo tỷ lệ khung hình giới hạn, đồng thời cho phép camera hoặc lượt truyền giao diện người dùng mở rộng ra toàn bộ kích thước màn hình logic:

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);
}

Để xem hướng dẫn từng bước trong Unity, hãy xem lớp học lập trình Tối ưu hoá trò chơi Unity cho màn hình lớn và thiết bị gập.

Xử lý kích thước màn hình lớn và nhỏ

Trên màn hình nhỏ hơn, chẳng hạn như điện thoại và màn hình ngoài của thiết bị có thể gập lại, trải nghiệm người dùng tốt nhất có thể là trò chơi bị khoá theo hướng dọc hoặc ngang. Khi màn hình trở nên lớn hơn (chẳng hạn như máy tính bảng, Chromebook, màn hình trên ô tô hoặc màn hình bên trong của thiết bị có thể gập lại), việc xoay thiết bị sẽ trở nên không mong muốn hoặc thậm chí là không thể, trong khi màn hình vật lý lớn hơn giúp trò chơi có thể chơi được ở tỷ lệ khung hình ngoài trục.

Để mang đến cho người chơi trải nghiệm tốt nhất, hãy phát hiện kích thước màn hình trong thời gian chạy và hạn chế xoay khi cần, đồng thời mang đến cho người chơi sự linh hoạt hơn khi kích thước màn hình tăng lên. Android coi điểm cắt lý tưởng là sw600dp, chiều rộng nhỏ nhất là 600 pixel không phụ thuộc vào mật độ (600dp). Điều này tương quan với WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND. Sử dụng computeMaximumWindowMetrics để xác thực kích thước màn hình có sẵn trong cấu hình nhiều màn hình.

Để hỗ trợ tính năng này trong trò chơi, hãy hỗ trợ tất cả các hướng trong tệp kê khai, sau đó trong cả onCreate() và onConfigurationChanged(), hãy đánh giá chiều rộng nhỏ nhất và đặt khoá hướng cho phù hợp:

  1. Xoá các khoá hướng tĩnh trong tệp kê khai và khai báo cách xử lý thay đổi cấu hình:

    <activity
        android:name=".MainActivity"
        android:resizeableActivity="true"
        android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|density|keyboard|keyboardHidden" />
    
  2. Thêm các lệnh nhập bắt buộc:

    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. Xử lý cả onCreate và onConfigurationChanged:

    override fun onCreate(savedInstanceState: Bundle?) {
        enableEdgeToEdge()
        super.onCreate(savedInstanceState)
        applyAdaptiveOrientationPolicy()
        // ...
    }
    
    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        applyAdaptiveOrientationPolicy()
        // ...
    }
    
  4. Cập nhật hướng được yêu cầu dựa trên chiều rộng màn hình nhỏ nhất, khoá màn hình nhỏ theo hướng thiết kế ưu tiên của trò chơi:

    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
        }
    }
    

Thiết kế để tránh các vấn đề thường gặp

Việc hỗ trợ nhiều tỷ lệ khung hình và hướng giúp người chơi có được trải nghiệm người dùng tốt nhất có thể. Không giống như điện thoại, màn hình lớn thường được cố định theo hướng ngang hoặc dọc và trong một số trường hợp, màn hình gần như là hình vuông. Trên các thiết bị lớn hơn này, người chơi thường làm nhiều việc cùng lúc khi chơi trò chơi của bạn. Bằng cách tối đa hoá việc sử dụng không gian màn hình, bạn có thể thu hút nhiều người chơi hơn, thường xuyên hơn và trong các phiên chơi dài hơn.

Các phần sau đây cung cấp giải pháp giúp trò chơi của bạn mang lại trải nghiệm cao cấp trên nhiều kiểu dáng, thay vì chỉ là một trò chơi trên điện thoại được nhúng vào màn hình không phải điện thoại.

Máy ảnh nhận biết tỷ lệ khung hình

Trong trò chơi 3D, nếu màn hình quá cao, người chơi có thể cảm thấy như đang xem trò chơi qua một khe hẹp và nếu màn hình quá rộng, người chơi có thể bỏ lỡ các hoạt động tương tác được thiết kế. Giống như trong trò chơi 2D, bạn có thể giữ cho "vùng an toàn" luôn hiển thị. Mã sau đây chuyển đổi máy ảnh giữa trường nhìn ngang và trường nhìn dọc dựa trên cách so sánh tỷ lệ khung hình đang hoạt động với tỷ lệ khung hình tham chiếu là 1920x1080. Bằng cách này, nhà thiết kế có thể xây dựng trò chơi cho màn hình 1080p và biết rằng mọi thứ được thiết kế trong khung tham chiếu đó vẫn hiển thị:

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;
}

Hộp thư tương tác đầy đủ

Một số trò chơi có khu vực chơi cố định theo thiết kế, thường phù hợp với các yếu tố thiết kế dựa trên thể loại, chẳng hạn như trường cố định của trò chơi bắn súng dọc hoặc thao tác cuộn màn hình lật được dùng cho phong cách cổ điển.

Đối với những trò chơi này, hãy điều chỉnh tỷ lệ khu vực chơi sao cho phù hợp để một trục của trò chơi luôn được tối đa hoá nhằm lấp đầy khu vực chơi. Trục được tối đa hoá có thể thay đổi dựa trên tỷ lệ khung hình tương đối của trò chơi và ranh giới hiển thị.

Cố định HUD và các phần tử trên giao diện người dùng vào cạnh an toàn của màn hình: tránh vết cắt, nhưng nếu không, hãy đặt các thành phần tương tác như nút điều khiển ảo, thanh máu và bản đồ nhỏ càng xa khu vực lối chơi càng tốt. Bằng cách này, phần tương tác của trò chơi sẽ sử dụng toàn bộ màn hình và người chơi trên các kiểu dáng như máy tính bảng và thiết bị gập có thể thoải mái chơi trò chơi của bạn mà không cần phải duỗi ngón tay quá mức.

Cuối cùng, hãy tạo vùng hòm thư có chủ đề hoặc nội dung phù hợp. Hãy cân nhắc đường viền phù hợp với bảng màu hoặc bộ ô trên màn hình, bảng hoặc màn hình ảo cho trò chơi cờ bàn hoặc trò chơi cổ điển, hoặc bản đồ nhỏ mở rộng và hình ảnh trang trí.

Trong ví dụ sau, trò chơi hiển thị kích thước đầy đủ cho hầu hết các tỷ lệ khung hình. Khi tỷ lệ khung hình hẹp hơn 4:3, tỷ lệ này sẽ hiển thị một hộp bầu trời có màu theo chủ đề, đồng thời tiếp tục đặt các phần tử trên giao diện người dùng như các nút điều khiển ở cạnh màn hình:

Trò chơi cuộn cảnh màn hình ngang trong rừng, hiển thị tràn viền trong cửa sổ ngang rộng với các nút điều khiển cảm ứng ở các góc.
Hình 2. Trò chơi hiển thị toàn kích thước ở tỷ lệ khung hình rộng tiêu chuẩn.
Trò chơi cuộn cảnh màn hình ngang trong rừng trong một cửa sổ hẹp hơn tỷ lệ 4:3, hiển thị các thanh hòm thư có tán lá màu vàng theo chủ đề với các nút điều khiển cảm ứng được neo vào các cạnh màn hình bên ngoài.
Hình 3. Trò chơi có tỷ lệ khung hình hẹp hơn 4:3, kết xuất một skybox theo chủ đề với các thành phần điều khiển trên giao diện người dùng được neo vào các cạnh màn hình.

Sương mù chiến tranh

Nhiều nhà phát triển trò chơi lo ngại rằng người chơi có thể đạt được lợi thế không công bằng từ tỷ lệ khung hình dọc hoặc ngang cực lớn. Ví dụ: người chơi trong một trò chơi mang tính cạnh tranh như đấu trường trực tuyến nhiều người chơi (MOBA) có thể sử dụng màn hình rất dọc để nhìn sâu vào làn đường của đối thủ.

Đối với trò chơi mô phỏng và chiến lược từ trên xuống, hãy cân nhắc việc kết xuất sương mù chiến tranh:

  • Không kết xuất hình học cho đến khi người chơi có thể xem được.
  • Kết xuất hình học mà nhân vật của người chơi không thể chủ động nhìn thấy dưới dạng mờ, không có bất kỳ phần tử động nào.
  • Chỉ kết xuất đối thủ, vật phẩm thu thập được và các đối tượng động khác mà nhân vật của người chơi có thể chủ động nhìn thấy trong thế giới trò chơi.

Nếu kết hợp kỹ thuật này với hộp thư tương tác đầy đủ và kết xuất giao diện người dùng của bạn ra cạnh màn hình, thì người chơi sẽ có được trải nghiệm vừa mượt mà vừa có chủ đích mà không cần bạn phải thiết kế lại cấu trúc cấp độ hoặc cân bằng đội ngũ.

Việc mở rộng trò chơi này để lấp đầy màn hình lớn hơn mà không có sương mù chiến tranh sẽ làm lộ những phần bản đồ mà người chơi không nên nhìn thấy:

Trò chơi nhập vai góc nhìn từ trên xuống trên màn hình nhỏ, cho thấy Sir Bugdroid đang cầm khiên và đèn lồng gần một thanh kiếm phát sáng trên bệ, một cây cầu bắc qua sông và đường ray xe goòng.
Hình 4. Chế độ xem camera ban đầu trên màn hình nhỏ hơn.
Chế độ xem mở rộng của cùng một bản đồ RPG từ trên xuống trên màn hình lớn, cho thấy một golem và rương kho báu bên trong phòng ngục tối và yêu tinh bên kia sông.
Hình 5. Chế độ xem mở rộng cho thấy những phần của bản đồ mà người chơi không nên nhìn thấy.

Bằng cách kết xuất sương mù chiến tranh và ẩn các thành phần động như kẻ thù và vật phẩm, bạn sẽ duy trì được sự công bằng trong trò chơi trong khi vẫn sử dụng toàn bộ khung hình có sẵn cho trò chơi:

Trò chơi nhập vai từ trên xuống trên màn hình nhỏ cho thấy khu vực hoạt động xung quanh người chơi.
Hình 6. Khu vực hiển thị đang hoạt động xung quanh nhân vật của người chơi.
Chế độ xem mở rộng của bản đồ RPG từ trên xuống, trong đó địa hình ở xa bị làm mờ, còn kẻ thù và vật phẩm nằm ngoài tầm nhìn của người chơi thì bị ẩn.
Hình 7. Chế độ xem mở rộng với sương mù chiến tranh làm mờ địa hình ở xa và ẩn các yếu tố động.

Làm mờ dần hình học

Nhiều trò chơi, đặc biệt là trong không gian chiến lược theo lượt, sử dụng kỹ thuật tương tự như sương mù chiến tranh được mô tả trong phần trước và không kết xuất hình học mà người chơi chưa khám phá hoặc người chơi không thể tương tác trong một bối cảnh nhất định.

Nếu trường nhìn mở rộng làm lộ ra những phần trong bối cảnh hoặc cảnh quay mà người chơi không nên nhìn thấy, thì việc che một số phần của cảnh theo cách thiết kế gọn gàng sẽ đạt được hiệu quả thực tế tương tự như hiệu ứng dải đen ngang mà không tạo cảm giác có đường viền tĩnh cố định.

Trong ví dụ sau, việc mở rộng trò chơi sang tỷ lệ khung hình lớn hơn sẽ cho thấy một bầy thây ma bên ngoài tường thành:

Góc nhìn đẳng cự trong trò chơi nhập vai chiến thuật về Bugdroid và Mecha Hamster bên trong tường thành.
Hình 8. Khu vực chơi bên trong tường thành có tỷ lệ khung hình hẹp hơn.
Góc nhìn chiến thuật đẳng cự mở rộng trong game nhập vai, cho thấy một bầy kẻ thù đang chờ đợi bên ngoài cổng dưới của lâu đài.
Hình 9. Tỷ lệ khung hình lớn hơn cho thấy một bầy thây ma bên ngoài tường thành.

Thay vào đó, bạn có thể bỏ qua việc kết xuất hình học cấp độ vượt quá giới hạn của khu vực chơi hiện tại:

Góc nhìn RPG chiến thuật đẳng cự của Bugdroid và Mecha Hamster bên trong tường thành.
Hình 10. Khu vui chơi bên trong tường thành.
Góc nhìn mở rộng của trò chơi nhập vai chiến thuật đẳng cự, trong đó hình học cấp độ và kẻ thù bên ngoài tường thành bị bỏ qua.
Hình 11. Tỷ lệ khung hình lớn hơn, trong đó hình học cấp độ không được kết xuất ngoài khu vực chơi hiện tại.

Ranh giới trong thế giới trò chơi

Trong các trò chơi 3D sống động, nơi trường nhìn mở rộng có thể mang lại lợi thế cạnh tranh trong các trò chơi nhiều người chơi ở góc nhìn thứ nhất hoặc thứ ba, hoặc cho thấy các khu vực không được tạo trong các trò chơi dựa trên bối cảnh cố định, hãy cân nhắc việc xây dựng các yếu tố diegetic vào trò chơi để giới hạn trường nhìn thay vì dựa vào hộp thư hình chữ nhật. Ví dụ:

  • Bên trong buồng lái của một phương tiện như ô tô hoặc máy bay
  • Bên trong mũ bảo hiểm
  • Hiệu ứng mờ viền cho biết ranh giới tầm nhìn của người chơi

Các thành phần giao diện người dùng và HUD vẫn phải mở rộng đến cạnh màn hình hoặc được kết hợp vào ranh giới diegetic, và việc làm cho các thành phần này trở nên linh động là điều lý tưởng. Những yếu tố diegetic này cũng có thể giúp ích cho những người chơi bị say tàu xe (đặc biệt là trên hệ số hình dạng XR), hỗ trợ tiếp cận và giúp giảm bớt sự phức tạp của tỷ lệ khung hình mới.

Tránh kết xuất trò chơi trên một nền tảng bên trong cảnh tĩnh không tương tác. Mặc dù phương pháp đó tốt hơn việc kết xuất các thanh màu đen cho hòm thư và hộp thư, nhưng người chơi sẽ nhanh chóng nhận thấy các đường viền tĩnh và có thể cảm thấy thất vọng nếu trò chơi yêu thích của họ kết xuất thành một mảng màn hình có kích thước bằng điện thoại trên các kiểu dáng không phải điện thoại.

Trong ví dụ này, một trò chơi được thiết kế cho màn hình điện thoại tiêu chuẩn sẽ được kết xuất bên trong một chiếc tivi mô phỏng có tay điều khiển trò chơi theo phong cách mô phỏng để phù hợp với tỷ lệ khung hình vuông hơn thường thấy trên màn hình bên trong của thiết bị có thể gập lại:

Trò chơi mê cung 3D được hiển thị bên trong khung hình mô phỏng TV CRT, có tay điều khiển trò chơi theo phong cách mô phỏng ở nền trước.
Hình 12. Trò chơi được kết xuất bên trong một khung hình TV mô phỏng tĩnh có tay điều khiển trò chơi theo phong cách mô phỏng.

Một số trò chơi 3D có thể cần hạn chế trường nhìn để đảm bảo tính công bằng trong thi đấu hoặc vì lý do thiết kế. Bạn nên sử dụng buồng lái, mũ bảo hiểm hoặc phép ẩn dụ khác để hạn chế trường nhìn thay vì dùng các thanh màu đen:

Góc nhìn thứ nhất trong mê cung 3D từ bên trong buồng lái hình cầu của chuột hamster, có bản đồ nhỏ ở trên và các nút điều khiển cảm ứng ở dưới.
Hình 13. Khung buồng lái hình cầu diegetic hạn chế trường nhìn trong khi cố định HUD và các nút điều khiển vào các cạnh màn hình.

Tài nguyên khác