ออกแบบสำหรับหน้าจอขนาดใหญ่

ในคู่มือนี้ คุณจะได้เรียนรู้วิธีปรับเกมให้ทำงานในอุปกรณ์ Android รูปแบบต่างๆ

ก่อนเริ่มต้น โปรดอ่านรองรับความสามารถในการปรับขนาดหน้าจอขนาดใหญ่ เกมสมัยใหม่บน Android ควรปรับให้เข้ากับหน้าจอทุกขนาดโดยไม่ต้องอาศัยเลเยอร์ความเข้ากันได้ของระบบ วิธีนี้ช่วยให้คุณควบคุมวิธีแสดงเกมได้เสมอ และเกมจะมอบประสบการณ์การเล่นระดับพรีเมียม แม้ในรูปแบบอุปกรณ์อย่าง XR หรืออุปกรณ์ที่หมุนหน้าจอไม่ได้

โดยทำตามขั้นตอนต่อไปนี้

  1. ปิดใช้การทำ Letterbox ของระบบและใช้การทำ Letterbox ในเครื่องมือของคุณเอง
  2. ทำให้พื้นที่ Letterbox ใช้งานได้และมีธีมที่เหมาะสม
  3. พิจารณาการออกแบบที่จำเป็นเพื่อให้เกมปรับขนาดได้ตั้งแต่ 21:9 ไปจนถึง 1:1 และ 9:21

คำสั่งสำหรับการทดสอบ

เมื่อสร้างและทดสอบเกม ให้ตรวจสอบว่าเกมแสดงผลแถบสีดำเอง นอกจากนี้ คุณควรบังคับให้เกมแสดงผลทั้งในแนวตั้งและแนวนอน เนื่องจากอุปกรณ์อย่างทีวีและจอแสดงผลในรถยนต์ไม่สามารถหมุนจากแนวตั้งหรือแนวนอนเริ่มต้นได้

หากต้องการตรวจสอบว่าเกมเอนจินใช้การแสดงผลแบบ Letterbox ของระบบหรือไม่ ให้ใช้คำสั่ง adb shell cmd window set-letterbox-style ตัวอย่างเช่น คำสั่งต่อไปนี้จะทำให้แถบสีดำของระบบเป็นสีเขียวสว่างและเพิ่มรัศมีมุมให้กับเกม ทำให้เห็นได้ชัดเจนหากเกมกลับไปใช้โหมดความเข้ากันได้ของระบบปฏิบัติการ

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

หากต้องการบังคับการวางแนวเพื่อทดสอบ ให้ใช้ adb shell cmd window user-rotation lock ซึ่งจะช่วยให้คุณจำลองลักษณะการทำงานของเกมในอุปกรณ์ที่ไม่รองรับการลบล้างแอปสำหรับการวางแนว หรือทำความเข้าใจสิ่งที่ผู้ใช้เห็นในอุปกรณ์ XR หรืออุปกรณ์ที่คล้ายกับ PC ซึ่งหน้าต่างสามารถปรากฏในแนวตั้งหรือแนวนอนโดยไม่ขึ้นอยู่กับการวางแนวของอุปกรณ์

ก่อนอื่น ให้อุปกรณ์อยู่ในสถานะที่คุณลบล้างการวางแนวของแอปได้ โดยทำดังนี้

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

ถัดไป ให้ทดสอบการเปลี่ยนเกมเป็นแนวนอนโดยทำดังนี้

adb shell cmd window user-rotation lock 1

จากนั้นทดสอบการเปลี่ยนเกมเป็นแนวตั้งโดยทำดังนี้

adb shell cmd window user-rotation lock 0

รีเซ็ตอุปกรณ์เป็นการกำหนดค่า OEM โดยการรีบูตหรือเรียกใช้คำสั่งต่อไปนี้

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

เหตุใดจึงควรปิดใช้การแสดงผลแบบ Letterbox ของระบบ

ระบบจะควบคุมการทำ Letterbox ของระบบเสมอ การตรวจหาขนาดหน้าจอและจัดการพื้นที่แสดงผลด้วยตนเองจะช่วยลดปัญหาต่างๆ เช่น การป้อนข้อมูลที่หายไป ซึ่งเกิดขึ้นเมื่อการป้อนข้อมูลอยู่นอกพื้นที่เกม นอกจากนี้ คุณยังขยายองค์ประกอบที่ไม่ใช่เกมเพลย์ไปยังขอบหน้าจอได้ แม้ว่าเนื้อหาเกมจะยังคงอยู่ตรงกลางก็ตาม โหมดความเข้ากันได้ของระบบช่วยให้เกมพร้อมใช้งานได้ แต่ก็ขึ้นอยู่กับคุณในฐานะนักพัฒนาเกมที่จะทำให้เกมยอดเยี่ยมสำหรับผู้เล่น

ภาพหน้าจอโทรศัพท์ อุปกรณ์แบบพับได้ แท็บเล็ต และแล็ปท็อปที่ไฮไลต์พื้นที่หน้าต่างที่ใช้งานอยู่
รูปที่ 1 รูปแบบของอุปกรณ์โทรศัพท์ อุปกรณ์แบบพับได้ แท็บเล็ต และแล็ปท็อป

ตัวอย่างการใช้งาน Letterbox

เกมเอนจินส่วนใหญ่ช่วยให้คุณควบคุมตำแหน่งที่กล้องแสดงผลบนหน้าจอได้ หากต้องการใช้ Letterbox ของคุณเอง ให้วัดสัดส่วนภาพของพื้นที่ที่แสดงผลและปรับสี่เหลี่ยมผืนผ้าที่ตัดสำหรับพื้นที่ที่ไม่ได้ใช้ แทนที่จะปล่อยให้ระบบแสดงเกมแบบ Letterbox ตัวอย่างต่อไปนี้จำกัดกล้อง 1 ตัวให้แสดงผลในสัดส่วนภาพที่จำกัด ขณะที่อนุญาตให้กล้อง UI หรือการส่งผ่านขยายเป็นขนาดหน้าจอเชิงตรรกะแบบเต็ม

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

ดูคำแนะนำทีละขั้นตอนใน Unity ได้ที่ Codelab การเพิ่มประสิทธิภาพเกม Unity สำหรับหน้าจอขนาดใหญ่และอุปกรณ์แบบพับได้

จัดการหน้าจอขนาดใหญ่และขนาดเล็ก

ในหน้าจอขนาดเล็ก เช่น โทรศัพท์และจอแสดงผลด้านนอกของอุปกรณ์แบบพับได้ ประสบการณ์ของผู้ใช้ที่ดีที่สุดอาจเป็นเกมที่ล็อกแนวตั้งหรือแนวนอน เมื่อหน้าจอมีขนาดใหญ่ขึ้น เช่น แท็บเล็ต, Chromebook, จอแสดงผลในรถยนต์ หรือจอแสดงผลด้านในของอุปกรณ์แบบพับได้ การหมุนอุปกรณ์จึงไม่เป็นที่ต้องการหรือเป็นไปไม่ได้เลย ในขณะที่จอแสดงผลขนาดใหญ่ขึ้นช่วยให้เล่นเกมในสัดส่วนภาพที่ไม่ได้อยู่ในแนวแกนได้

เพื่อให้ผู้เล่นได้รับประสบการณ์ที่ดีที่สุด ให้ตรวจหาขนาดหน้าจอขณะรันไทม์และจำกัดการหมุนเมื่อจำเป็น พร้อมทั้งให้ผู้เล่นมีความยืดหยุ่นมากขึ้นเมื่อขนาดหน้าจอเพิ่มขึ้น Android ถือว่าจุดตัดที่เหมาะสมคือ sw600dp ซึ่งมีความกว้างที่เล็กที่สุดเท่ากับ 600 ความหนาแน่นของพิกเซลอิสระ (600dp) ซึ่งสอดคล้องกับ WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND ใช้ computeMaximumWindowMetrics เพื่อตรวจสอบขนาดหน้าจอที่ใช้ได้ในการกำหนดค่าแบบหลายจอแสดงผล

หากต้องการรองรับฟีเจอร์นี้ในเกม ให้รองรับการวางแนวทั้งหมดในไฟล์ Manifest จากนั้นประเมินความกว้างที่เล็กที่สุดทั้งใน onCreate() และ onConfigurationChanged() แล้วตั้งค่าการล็อกการวางแนวอย่างเหมาะสม ดังนี้

  1. นำการล็อกการวางแนวแบบคงที่ในไฟล์ Manifest ออกและประกาศการจัดการการเปลี่ยนแปลงการกำหนดค่า ดังนี้

    <activity
        android:name=".MainActivity"
        android:resizeableActivity="true"
        android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|density|keyboard|keyboardHidden" />
    
  2. เพิ่มการนําเข้าที่จําเป็น ดังนี้

    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. จัดการทั้ง onCreate และ onConfigurationChanged:

    override fun onCreate(savedInstanceState: Bundle?) {
        enableEdgeToEdge()
        super.onCreate(savedInstanceState)
        applyAdaptiveOrientationPolicy()
        // ...
    }
    
    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        applyAdaptiveOrientationPolicy()
        // ...
    }
    
  4. อัปเดตการวางแนวที่ขอตามความกว้างของหน้าจอที่เล็กที่สุด โดยล็อกหน้าจอขนาดกะทัดรัดให้เป็นแนวการออกแบบที่ต้องการของเกม ดังนี้

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

ออกแบบโดยคำนึงถึงปัญหาที่พบได้ทั่วไป

การรองรับสัดส่วนภาพและการวางแนวที่หลากหลายจะช่วยให้ผู้เล่นได้รับประสบการณ์การใช้งานที่ดีที่สุด จอแสดงผลขนาดใหญ่มักจะได้รับการแก้ไขในแนวนอนหรือแนวตั้ง ซึ่งต่างจากโทรศัพท์ และในบางกรณีหน้าจอเกือบจะเป็นสี่เหลี่ยมจัตุรัส ในอุปกรณ์ขนาดใหญ่เหล่านี้ ผู้เล่นมักจะทำงานหลายอย่างพร้อมกันเมื่อเล่นเกมของคุณ การใช้พื้นที่หน้าจอให้เกิดประโยชน์สูงสุดจะช่วยให้คุณดึงดูดผู้เล่นได้มากขึ้น บ่อยขึ้น และเล่นเกมได้นานขึ้น

ส่วนต่อไปนี้จะแสดงโซลูชันที่ทำให้เกมของคุณให้ความรู้สึกเหมือนเป็นประสบการณ์ระดับพรีเมียมในรูปแบบของอุปกรณ์ต่างๆ แทนที่จะเป็นเกมโทรศัพท์ที่ฝังอยู่ในหน้าจอที่ไม่ใช่โทรศัพท์

กล้องที่รองรับสัดส่วนภาพ

ในเกม 3 มิติ หากหน้าจอสูงเกินไป ผู้เล่นอาจรู้สึกเหมือนกำลังดูเกมผ่านช่องแคบๆ และหากหน้าจอกว้างเกินไป ผู้เล่นอาจพลาดการโต้ตอบที่ออกแบบไว้ คุณสามารถทำให้ "พื้นที่ปลอดภัย" ปรากฏอยู่เสมอได้เช่นเดียวกับในเกม 2 มิติ โค้ดต่อไปนี้จะสลับกล้องระหว่างขอบเขตการมองเห็นแนวนอนกับขอบเขตการมองเห็นแนวตั้ง โดยอิงตามการเปรียบเทียบสัดส่วนภาพที่ใช้งานอยู่กับสัดส่วนภาพอ้างอิงที่ 1920x1080 วิธีนี้ช่วยให้นักออกแบบสามารถสร้างเกมสำหรับจอแสดงผล 1080p และทราบว่าทุกอย่างที่ออกแบบภายในเฟรมอ้างอิงนั้นจะยังคงมองเห็นได้ ดังนี้

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

Letterbox แบบอินเทอร์แอกทีฟเต็มรูปแบบ

เกมบางเกมมีพื้นที่การเล่นที่คงที่ตามการออกแบบ ซึ่งมักจะตรงกับการพิจารณาการออกแบบตามประเภท เช่น สนามคงที่ของเกมยิงแนวตั้งหรือการเลื่อนหน้าจอแบบพลิกที่ใช้เพื่อความสวยงามแบบย้อนยุค

สำหรับเกมเหล่านี้ ให้ปรับขนาดพื้นที่เกมเพลย์ให้พอดีเพื่อให้แกนหนึ่งของเกมขยายใหญ่สุดเพื่อเติมเต็มพื้นที่เกมเพลย์เสมอ แกนที่ขยายใหญ่สุดอาจเปลี่ยนแปลงได้ตามสัดส่วนภาพสัมพัทธ์ของเกมและขอบเขตการแสดงผล

ยึด HUD และองค์ประกอบ UI ทั้งหมดไว้ที่ขอบที่ปลอดภัยของหน้าจอ โดยหลีกเลี่ยงส่วนที่ถูกตัดออก แต่ให้วางองค์ประกอบแบบอินเทอร์แอกทีฟ เช่น ตัวควบคุมเสมือน แถบพลังชีวิต และแผนที่ย่อ ให้อยู่นอกพื้นที่เกมเพลย์ให้มากที่สุด วิธีนี้จะทำให้ส่วนอินเทอร์แอกทีฟของเกมใช้ทั้งหน้าจอ และผู้เล่นในอุปกรณ์รูปแบบต่างๆ เช่น แท็บเล็ตและอุปกรณ์แบบพับได้ จะเล่นเกมของคุณได้อย่างสะดวกสบายโดยไม่ต้องยืดนิ้วมากเกินไป

สุดท้าย ให้สร้างพื้นที่ Letterbox ที่มีธีมหรือเรื่องราวที่เหมาะสม ลองใช้ขอบที่เข้ากับจานสีหรือชุดไทล์บนหน้าจอ โต๊ะหรือหน้าจอเสมือนจริงสำหรับเกมกระดานหรือเกมย้อนยุค หรือแผนที่ย่อแบบขยายและภาพตกแต่ง

ในตัวอย่างต่อไปนี้ เกมจะแสดงผลแบบเต็มขนาดสำหรับสัดส่วนภาพส่วนใหญ่ เมื่อสัดส่วนภาพแคบกว่า 4:3 ระบบจะแสดงผลสกายบ็อกซ์ที่มีสีตามธีมในขณะที่ยังคงวางองค์ประกอบ UI เช่น ตัวควบคุม ไว้ที่ขอบหน้าจอ

เกมป่าแบบ Side-scrolling ที่แสดงผลแบบเต็มหน้าจอในหน้าต่างแนวนอนกว้างพร้อมการควบคุมด้วยการสัมผัสที่มุม
รูปที่ 2 เกมแสดงผลแบบเต็มขนาดในสัดส่วนภาพแบบกว้างมาตรฐาน
เกมป่าไม้แบบ Side-scrolling ในหน้าต่างที่แคบกว่า 4:3 แสดงแถบ Letterbox สีเหลืองตามธีมใบไม้พร้อมการควบคุมด้วยการสัมผัสที่ยึดกับขอบหน้าจอด้านนอก
รูปที่ 3 เกมที่มีสัดส่วนภาพแคบกว่า 4:3 แสดงผลสกายบ็อกซ์ตามธีมพร้อมตัวควบคุม UI ที่ยึดกับขอบหน้าจอ

หมอกแห่งสงคราม

นักพัฒนาเกมหลายรายกังวลว่าผู้เล่นอาจได้รับข้อได้เปรียบที่ไม่เป็นธรรมจากสัดส่วนภาพแนวตั้งหรือแนวนอนที่มากเกินไป ตัวอย่างเช่น ผู้เล่นในเกมที่มีการแข่งขันสูงอย่างสนามประลองออนไลน์ที่มีผู้เล่นหลายคน (MOBA) อาจใช้หน้าจอแนวตั้งมากๆ เพื่อให้มองเห็นเลนของคู่ต่อสู้ได้ลึกขึ้น

สำหรับเกมกลยุทธ์และเกมจำลองสถานการณ์แบบมุมมองจากบนลงล่าง ให้พิจารณาแสดงผลหมอกแห่งสงคราม ดังนี้

  • อย่าแสดงผลเรขาคณิตเลยจนกว่าผู้เล่นจะดูได้
  • แสดงผลเรขาคณิตที่ตัวละครของผู้เล่นมองไม่เห็นอย่างชัดเจนเป็นสีหม่น โดยไม่มีองค์ประกอบแบบไดนามิก
  • แสดงผลเฉพาะคู่ต่อสู้ ของสะสม และวัตถุแบบไดนามิกอื่นๆ ที่ตัวละครของผู้เล่นสามารถมองเห็นได้อย่างชัดเจนในโลกของเกม

หากคุณใช้เทคนิคนี้ร่วมกับแถบสีดำแบบอินเทอร์แอกทีฟเต็มรูปแบบและแสดงผล UI ที่ขอบหน้าจอ ผู้เล่นจะได้รับประสบการณ์ที่ทั้งดูดีและตั้งใจโดยที่คุณไม่ต้องออกแบบโครงสร้างระดับหรือความสมดุลของทีมใหม่

การขยายเกมนี้ให้เต็มหน้าจอขนาดใหญ่ขึ้นโดยไม่มีหมอกแห่งสงครามจะเผยให้เห็นส่วนต่างๆ ของแผนที่ที่ผู้เล่นไม่ควรเห็น ดังนี้

เกม RPG แบบมุมมองจากบนลงล่างบนหน้าจอขนาดเล็กที่แสดงภาพ Sir Bugdroid ถือโล่และโคมไฟอยู่ใกล้กับดาบเรืองแสงบนแท่น สะพานข้ามแม่น้ำ และรางรถเข็นในเหมือง
รูปที่ 4 มุมมองกล้องดั้งเดิมบนหน้าจอขนาดเล็ก
มุมมองแบบขยายของแผนที่ RPG แบบมองจากบนลงล่างเดียวกันบนหน้าจอขนาดใหญ่ที่แสดงโกเลมและหีบสมบัติภายในห้องดันเจี้ยนและก็อบลินที่อยู่อีกฝั่งของแม่น้ำ
รูปที่ 5 มุมมองแบบขยายที่แสดงส่วนต่างๆ ของแผนที่ซึ่งผู้เล่นไม่ควรเห็น

การแสดงผลหมอกแห่งสงครามและซ่อนองค์ประกอบแบบไดนามิก เช่น ศัตรูและไอเทม จะช่วยรักษาความยุติธรรมในเกมขณะใช้เฟรมเต็มรูปแบบที่เกมมีให้ ดังนี้

เกม RPG แบบมุมมองจากด้านบนบนหน้าจอขนาดเล็กที่แสดงพื้นที่ที่ใช้งานอยู่รอบๆ ผู้เล่น
รูปที่ 6 พื้นที่ที่มองเห็นได้รอบตัวละครของผู้เล่น
มุมมองแบบขยายของแผนที่ RPG แบบบนลงล่างซึ่งภูมิประเทศที่อยู่ห่างไกลจะมืดลง และศัตรูและไอเทมที่อยู่นอกแนวสายตาของผู้เล่นจะถูกซ่อนไว้
รูปที่ 7 มุมมองแบบขยายที่มีหมอกแห่งสงครามบดบังภูมิประเทศที่อยู่ห่างไกลและซ่อนองค์ประกอบแบบไดนามิก

เรขาคณิตค่อยๆ จางหายไป

เกมจำนวนมาก โดยเฉพาะในพื้นที่กลยุทธ์แบบผลัดกันเล่น ใช้เทคนิคที่คล้ายกับหมอกแห่งสงครามที่อธิบายไว้ในส่วนก่อนหน้า และไม่แสดงผลเรขาคณิตที่ผู้เล่นยังไม่ได้ค้นพบหรือที่ผู้เล่นไม่สามารถโต้ตอบด้วยได้ในระหว่างฉากหนึ่งๆ

หากขอบเขตการมองเห็นที่ขยายออกจะเผยให้เห็นส่วนต่างๆ ของฉากหรือภาพยนตร์ที่ผู้เล่นไม่ควรเห็น การมาสก์บางส่วนของฉากด้วยวิธีที่ออกแบบมาอย่างเรียบร้อยจะให้ผลลัพธ์ที่เหมือนกับการใช้แถบดำโดยไม่มีการรับรู้ถึงขอบเขตที่คงที่

ในตัวอย่างต่อไปนี้ การขยายเกมให้มีสัดส่วนภาพที่ใหญ่ขึ้นจะเผยให้เห็นฝูงซอมบี้นอกกำแพงปราสาท

มุมมอง RPG เชิงกลยุทธ์แบบไอโซเมตริกของ Bugdroid และ Mecha Hamster ภายในกำแพงปราสาท
รูปที่ 8 พื้นที่เล่นภายในกำแพงปราสาทในสัดส่วนภาพที่แคบลง
มุมมองเกม RPG แนวกลยุทธ์แบบไอโซเมตริกที่ขยายออก เผยให้เห็นฝูงศัตรูที่รออยู่นอกประตูปราสาทด้านล่าง
รูปที่ 9 สัดส่วนภาพที่ใหญ่ขึ้นเผยให้เห็นฝูงซอมบี้นอกกำแพงปราสาท

แต่คุณสามารถละเว้นการแสดงผลเรขาคณิตของระดับที่อยู่นอกขอบเขตของพื้นที่เล่นปัจจุบันได้ ดังนี้

มุมมองเกม RPG เชิงกลยุทธ์แบบไอโซเมตริกของ Bugdroid และ Mecha Hamster ภายในกำแพงปราสาท
รูปที่ 10 พื้นที่เล่นภายในกำแพงปราสาท
มุมมอง RPG เชิงกลยุทธ์แบบไอโซเมตริกที่ขยายออก โดยละเว้นเรขาคณิตของเลเวลและศัตรูนอกกำแพงปราสาท
รูปที่ 11 สัดส่วนภาพที่ใหญ่ขึ้นซึ่งไม่มีการแสดงผลเรขาคณิตของเลเวลนอกพื้นที่เล่นปัจจุบัน

ขอบเขตที่สอดคล้องกับเนื้อเรื่อง

ในเกม 3 มิติที่สมจริงซึ่งขอบเขตการมองเห็นที่กว้างขึ้นอาจทำให้ได้เปรียบในการแข่งขันในเกมแบบผู้เล่นหลายคนในมุมมองบุคคลที่หนึ่งหรือบุคคลที่สาม หรือเปิดเผยพื้นที่ที่ไม่ได้สร้างขึ้นในเกมแบบฉากคงที่ ให้พิจารณาสร้างองค์ประกอบที่สมจริงในเกมเพื่อจำกัดขอบเขตการมองเห็นแทนที่จะใช้แถบสีดำสี่เหลี่ยมผืนผ้า ตัวอย่างเช่น

  • ห้องคนขับภายในยานพาหนะ เช่น รถยนต์หรือเครื่องบิน
  • ด้านในของหมวกกันน็อก
  • ขอบภาพมืดที่แสดงขอบเขตการมองเห็นของผู้เล่น

องค์ประกอบ UI และ HUD ควรขยายไปจนถึงขอบหน้าจอหรือรวมไว้ในขอบเขตของเรื่องราว และควรทำให้เป็นแบบไดนามิก องค์ประกอบในเรื่องเหล่านี้ยังช่วยผู้เล่นที่รู้สึกเวียนศีรษะได้ด้วย โดยเฉพาะในรูปแบบของอุปกรณ์ XR ซึ่งจะช่วยเพิ่มการช่วยเหลือพิเศษนอกเหนือจากการช่วยลดความซับซ้อนของสัดส่วนภาพใหม่ๆ

หลีกเลี่ยงการแสดงผลเกมบนพื้นผิวภายในฉากนิ่งที่ไม่ใช่แบบอินเทอร์แอกทีฟ แม้ว่าแนวทางดังกล่าวจะดีกว่าการแสดงผลแถบสีดำสำหรับ Letterbox และ Pillarbox แต่ผู้เล่นจะสังเกตเห็นขอบที่คงที่ได้อย่างรวดเร็ว และอาจรู้สึกหงุดหงิดหากเกมโปรดแสดงผลเป็นแพตช์หน้าจอขนาดโทรศัพท์ในรูปแบบที่ไม่ใช่โทรศัพท์

ในตัวอย่างนี้ เกมที่ออกแบบมาสำหรับหน้าจอโทรศัพท์มาตรฐานจะแสดงผลภายในโทรศัพท์จำลองที่มีเกมแพดแบบเสมือนจริงเพื่อรองรับสัดส่วนภาพสี่เหลี่ยมจัตุรัสที่พบได้ทั่วไปในจอแสดงผลด้านในของอุปกรณ์แบบพับได้

เกมเขาวงกต 3 มิติที่แสดงผลภายในกรอบโทรทัศน์ CRT จำลองที่มีเกมแพดแบบ Skeuomorphic อยู่เบื้องหน้า
รูปที่ 12 เกมที่แสดงผลภายในเฟรมโทรทัศน์จำลองแบบคงที่พร้อมเกมแพดแบบเสมือนจริง

เกม 3 มิติบางเกมอาจต้องจำกัดขอบเขตการมองเห็นเพื่อความยุติธรรมในการแข่งขันหรือเพื่อพิจารณาการออกแบบ การใช้ห้องนักบิน หมวกนิรภัย หรืออุปมาอุปไมยอื่นๆ ที่เป็นส่วนหนึ่งของเรื่องราวเพื่อจำกัดขอบเขตการมองเห็นนั้นดีกว่าการใช้แถบสีดำ

มุมมองเขาวงกต 3 มิติแบบบุคคลที่หนึ่งจากภายในห้องนักบินทรงกลมแบบลูกบอลแฮมสเตอร์ พร้อมแผนที่ย่อเหนือศีรษะและการควบคุมด้วยการสัมผัสด้านล่าง
รูปที่ 13 กรอบห้องนักบินทรงกลมแบบไดเจติกที่จำกัดขอบเขตการมองเห็นขณะยึด HUD และตัวควบคุมไว้ที่ขอบหน้าจอ

แหล่งข้อมูลเพิ่มเติม