طراحی برای صفحه‌نمایش‌های بزرگ

در این راهنما، با نحوه سازگار کردن بازی‌تان برای اجرا در ضریب‌های شکل مختلف Android آشنا خواهید شد.

قبل‌از شروع، پشتیبانی از قابلیت تغییر اندازه صفحه‌نمایش بزرگ را بخوانید. بازی‌های مدرن در Android باید با همه اندازه‌های صفحه‌نمایش سازگار شوند بدون اینکه به لایه‌های سازگاری سیستم متکی باشند. به‌این‌ترتیب، همیشه بر نحوه نمایش بازی‌تان کنترل دارید و بازی‌تان تجربه بازیکن ممتازی را ارائه می‌دهد، حتی در ضریب‌های شکل مانند واقعیت گسترده یا دستگاه‌هایی که صفحه‌نمایش آن‌ها نمی‌تواند بچرخد.

برای انجام این کار، تکالیف زیر را تکمیل کنید:

  1. تصویر عریض سیستم را غیرفعال کنید و تصویر عریض درون موتور خودتان را پیاده‌سازی کنید.
  2. ناحیه جعبه‌ای را قابل‌استفاده و ازنظر موضوعی مناسب کنید.
  3. ملاحظات طراحی لازم را برای اینکه بازی‌تان بتواند از ۲۱:۹ تا ۱:۱ و ۹:۲۱ مقیاس‌بندی شود درنظر بگیرید.

فرمان‌های آزمایش

هنگام ساختن و آزمایش کردن بازی، مطمئن شوید که بازی‌تان هرگونه حاشیه سیاهی را خودش رندر می‌کند. همچنین باید بازی‌تان را مجبور کنید که در جهت‌های عمودی و افقی قرار بگیرد، زیرا دستگاه‌هایی مانند تلویزیون‌ها و نمایشگرهای داخل خودرو نمی‌توانند از جهت پیش‌فرض افقی یا عمودی خود بچرخند.

برای بررسی اینکه آیا موتور بازی شما از جعبه‌بندی سیستم استفاده می‌کند یا نه، از فرمان 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 که در آن پنجره‌ها می‌توانند مستقل از جهت‌گیری دستگاه به‌صورت عمودی یا افقی ظاهر شوند چه چیزی می‌بینند.

ابتدا دستگاهتان را در وضعیتی قرار دهید که بتوانید جهت برنامه را لغو کنید:

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

با بازراه‌اندازی یا اجرای فرمان‌های زیر، دستگاهتان را به پیکربندی سازنده اصلی محصول بازنشانی کنید:

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

اکثر موتورهای بازی به شما امکان می‌دهند کنترل کنید که دوربین در کجای صفحه‌نمایش پرداز شود. برای پیاده‌سازی تصویر عریض خودتان، نسبت ابعادی ناحیه پردازش‌شده را اندازه‌گیری کنید و مستطیل برش را برای ناحیه استفاده‌نشده تنظیم کنید، به‌جای اینکه اجازه دهید سیستم بازی شما را به‌صورت تصویر عریض نمایش دهد. نمونه زیر یک دوربین را به رندر کردن در نسبت ابعادی محدودشده محدود می‌کند، درحالی‌که به دوربین‌ها یا گذرهای میانای کاربر اجازه می‌دهد تا به اندازه کامل منطقی صفحه‌نمایش گسترش یابند:

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، به بهینه‌سازی بازی‌های Unity برای صفحه‌نمایش‌های بزرگ و دستگاه‌های تاشو codelab مراجعه کنید.

مدیریت اندازه‌های بزرگ و کوچک صفحه‌نمایش

در صفحه‌نمایش‌های کوچک‌تر، مانند تلفن‌ها و نمایشگرهای بیرونی دستگاه‌های تاشو، بهترین تجربه کاربری ممکن است بازی‌ای باشد که در حالت عمودی یا افقی قفل شده است. با بزرگ‌تر شدن صفحه‌نمایش‌ها (مثل رایانه‌های لوحی، Chromebook، نمایشگرهای داخل خودرو، یا نمایشگرهای داخلی دستگاه‌های تاشو)، چرخاندن دستگاه کمتر مطلوب یا حتی غیرممکن می‌شود، درحالی‌که نمایشگر فیزیکی بزرگ‌تر باعث می‌شود بازی در نسبت‌های ابعادی غیرمحوری قابل‌بازی بماند.

برای ارائه بهترین تجربه به بازیکنان، اندازه صفحه‌نمایش را در زمان اجرا شناسایی کنید و درصورت لزوم چرخش را محدود کنید، و درعین‌حال با افزایش اندازه صفحه‌نمایش، انعطاف‌پذیری بیشتری به بازیکنان بدهید. Android حد آستانه ایده‌آل را sw600dp، یعنی کمترین عرض ۶۰۰ پیکسل مستقل از تراکم (600dp) درنظر می‌گیرد. این با WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND مرتبط است. از computeMaximumWindowMetrics برای اعتبارسنجی اندازه صفحه‌نمایش دردسترس در پیکربندی‌های چندنمایشگری استفاده کنید.

برای پشتیبانی از این ویژگی در بازی‌تان، از همه جهت‌ها در مانیفست خود پشتیبانی کنید و سپس در هر دو onCreate() و onConfigurationChanged()، کوچک‌ترین عرض را ارزیابی کنید و قفل جهت را به‌طور مناسب تنظیم کنید:

  1. قفل‌های جهت ثابت را در مانیفست خود بردارید و مدیریت تغییر پیکربندی را اعلام کنید:

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

طراحی براساس مشکلات رایج

پشتیبانی از طیفی از نسبت‌های ابعادی و جهت‌ها بهترین تجربه کاربری ممکن را به بازیکنان شما ارائه می‌دهد. برخلاف تلفن‌ها، نمایشگرهای بزرگ‌تر اغلب در جهت افقی یا عمودی ثابت هستند و در برخی موارد صفحه‌نمایش تقریباً مربع است. در این دستگاه‌های بزرگ‌تر، بازیکنان اغلب هنگام بازی کردن بازی شما چندوظیفگی انجام می‌دهند. با به‌حداکثر رساندن استفاده از فضای صفحه‌نمایش، می‌توانید بازیکنان بیشتری را بیشتر اوقات و برای جلسه‌های بازی طولانی‌تر جذب کنید.

بخش‌های زیر راه‌حل‌هایی ارائه می‌دهند که باعث می‌شود بازی شما در انواع ضریب‌های شکل، به‌جای یک بازی تلفن جاسازی‌شده در صفحه‌نمایش غیرتلفن، مانند یک تجربه ممتاز احساس شود.

دوربین‌های آگاه از نسبت ابعاد

در بازی‌های سه‌بعدی، اگر صفحه‌نمایش خیلی بلند باشد، بازیکنان ممکن است احساس کنند که بازی را ازطریق یک شکاف باریک مشاهده می‌کنند، و اگر خیلی عریض باشد، ممکن است تعاملات طراحی‌شده را ازدست بدهند. همانند بازی‌های دوبعدی، می‌توانید «منطقه امنی» را همیشه قابل‌مشاهده نگه دارید. کد زیر دوربین را بین میدان دید افقی و میدان دید عمودی براساس نحوه مقایسه نسبت ابعادی فعال با نسبت ابعادی مرجع ۱۹۲۰×۱۰۸۰ جابه‌جا می‌کند. به‌این‌ترتیب، طراح می‌تواند بازی را برای نمایشگر 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;
}

جعبه‌های نامه کاملاً تعاملی

برخی‌از بازی‌ها به‌طور پیش‌فرض دارای منطقه بازی ثابت هستند که اغلب با ملاحظات طراحی مبتنی بر ژانر مطابقت دارد، مانند میدان ثابت یک بازی تیراندازی عمودی یا پیمایش صفحه برگردان که برای زیبایی‌شناسی قدیمی استفاده می‌شود.

برای این بازی‌ها، مقیاس ناحیه بازی را طوری تنظیم کنید که یک محور بازی همیشه بیشترین اندازه را داشته باشد تا ناحیه بازی را پر کند. محوری که بیشینه می‌شود می‌تواند براساس نسبت‌های ابعادی نسبی بازی شما و مرزهای نمایش تغییر کند.

عناصر HUD و میانای کاربر را تا لبه امن صفحه‌نمایش لنگر کنید: از برش‌ها اجتناب کنید، اما درغیراین‌صورت عناصر تعاملی مانند کنترل‌های مجازی، نوارهای سلامتی، و نقشه‌های کوچک را تا حد امکان خارج از منطقه بازی قرار دهید. به‌این‌ترتیب، بخش تعاملی بازی از کل صفحه‌نمایش استفاده می‌کند و بازیکنان در دستگاه‌هایی با ضریب‌های شکل مختلف مانند رایانه‌های لوحی و دستگاه‌های تاشو می‌توانند به‌راحتی و بدون کشش بیش‌ازحد انگشتان خود بازی کنند.

درنهایت، ناحیه حاشیه سیاه را به‌طور مناسبی زمینه‌دار یا روایی کنید. حاشیه‌هایی را درنظر بگیرید که با پالت روی صفحه یا مجموعه کاشی‌ها، میز یا صفحه مجازی برای بازی‌های تخته‌ای یا قدیمی، یا نقشه‌های کوچک گسترده و جلوه‌های بصری تزئینی مطابقت داشته باشند.

در مثال زیر، بازی برای اکثر نسبت‌های ابعادی به‌صورت اندازه کامل ارائه می‌شود. وقتی نسبت ابعادی باریک‌تر از ۴:۳ باشد، یک جعبه آسمان با رنگ موضوعی ارائه می‌دهد و درعین‌حال عناصر میانای کاربر مانند کنترل‌ها را در لبه صفحه‌نمایش قرار می‌دهد:

بازی جنگلی پیمایش افقی که به‌صورت تمام‌صفحه در پنجره افقی عریض با کنترل‌های لمسی در گوشه‌ها پرداز زده شده است.
شکل ۲. بازی با اندازه کامل در نسبت ابعادی عریض استاندارد پرداز زده می‌شود.
بازی پیمایش افقی جنگل در پنجره‌ای باریک‌تر از ۴:۳، که ستون‌های تصویر عریض با طرح برگ‌های زرد و کنترل‌های لمسی متصل به لبه‌های بیرونی صفحه‌نمایش را نشان می‌دهد.
شکل ۳. بازی با نسبت ابعادی باریک‌تر از ۴:۳ که یک اسکای‌باکس با موضوع خاص را با کنترل‌های میانای کاربر متصل به لبه‌های صفحه‌نمایش ارائه می‌دهد.

مه جنگ

بسیاری از توسعه‌دهندگان بازی نگران هستند که بازیکنان بتوانند از نسبت‌های ابعادی عمودی یا افقی شدید، مزیت ناعادلانه‌ای کسب کنند. برای مثال، بازیکنی در یک بازی رقابتی مانند میدان نبرد آنلاین چندنفره (MOBA) ممکن است از یک صفحه‌نمایش بسیار عمودی استفاده کند تا دید عمیقی به مسیر حریف داشته باشد.

برای بازی‌های شبیه‌سازی و استراتژی بالا به پایین، مه جنگ را رندر کنید:

  • تا زمانی که بازیکن نتواند هندسه را ببیند، آن را رندر نکنید.
  • هندسه را به‌گونه‌ای رندر کنید که شخصیت بازیکن نتواند به‌طور فعال آن را به‌صورت کم‌نور ببیند، بدون هیچ عنصر پویایی.
  • فقط حریفان، موارد قابل‌جمع‌آوری، و دیگر اشیای پویایی را که شخصیت بازیکن می‌تواند به‌طور فعال در دنیای بازی ببیند رندر کنید.

اگر این تکنیک را با حالت سینمایی کاملاً تعاملی ترکیب کنید و میانای کاربر را تا لبه صفحه‌نمایش رندر کنید، بازیکن تجربه‌ای را دریافت می‌کند که هم صیقل‌خورده و هم هدفمند به‌نظر می‌رسد، بدون اینکه نیاز باشد ساختار سطح یا توازن تیم را دوباره طراحی کنید.

گسترش دادن این بازی برای پر کردن صفحه‌نمایش بزرگ‌تر بدون مه جنگ، بخش‌هایی از نقشه را که بازیکن نباید ببیند آشکار می‌کند:

بازی نقش‌آفرینی از بالا به پایین در صفحه‌نمایش کوچکی که Sir Bugdroid را نشان می‌دهد که سپر و فانوسی را در نزدیکی شمشیر درخشانی روی پایه، پل رودخانه، و ریل واگن معدن نگه داشته است.
شکل ۴. نمای دوربین اصلی در صفحه‌نمایش کوچک‌تر.
نمای گسترده از همان نقشه بازی نقش‌آفرینی از بالا به پایین در صفحه‌نمایش بزرگ که یک گالم و صندوق گنج را در اتاق سیاه‌چال و گابلین‌ها را در آن‌سوی رودخانه نشان می‌دهد.
شکل ۵. نمای ازهم بازشده که بخش‌هایی از نقشه را که بازیکن نباید ببیند آشکار می‌کند.

با رندر کردن مه جنگ و پنهان کردن عناصر پویا مانند دشمنان و آیتم‌ها، عدالت را در بازی حفظ می‌کنید و درعین‌حال از کل قاب موجود برای بازی استفاده می‌کنید:

بازی نقش‌آفرینی از بالا به پایین در صفحه‌نمایش کوچکی که منطقه فعال اطراف بازیکن را نشان می‌دهد.
شکل ۶. ناحیه رؤیت‌پذیر فعال در اطراف شخصیت بازیکن.
نمای گسترده از نقشه بازی نقش‌آفرینی بالا به پایین که در آن زمین‌های دوردست کم‌نور شده‌اند و دشمنان و آیتم‌های خارج از خط دید بازیکن پنهان هستند.
شکل ۷. نمای گسترده با مه جنگی که زمین‌های دور را تیره می‌کند و عناصر پویا را پنهان می‌کند.

محو شدن هندسه

بسیاری از بازی‌ها، به‌ویژه در فضای استراتژی نوبتی، از تکنیکی مشابه مه جنگ که در بخش قبلی توضیح داده شد استفاده می‌کنند و هندسه‌ای را که بازیکن هنوز کشف نکرده است یا بازیکن نمی‌تواند درطول یک صحنه خاص با آن تعامل داشته باشد ارائه نمی‌کنند.

اگر میدان دید گسترده‌شده بخش‌هایی از مجموعه یا سینمایی شما را آشکار کند که بازیکن نباید ببیند، پوشاندن بخش‌های خاصی از صحنه به‌صورت تمیز و طراحی‌شده همان تأثیر عملی را مانند جعبه نامه بدون درک مرز ثابت ایستا به‌دست می‌آورد.

در مثال زیر، گسترش بازی به نسبت ابعادی بزرگ‌تر، انبوهی از زامبی‌ها را در خارج از دیوارهای قلعه نشان می‌دهد:

نمای بازی نقش‌آفرینی تاکتیکی ایزومتریک از باگ‌دروید و همستر مکانیکی درون دیوارهای قلعه.
شکل ۸. محوطه بازی داخل دیوارهای قلعه با نسبت ابعادی باریک‌تر.
نمای گسترده ایزومتریک تاکتیکی بازی نقش‌آفرینی که انبوهی از دشمنان را نشان می‌دهد که بیرون دروازه پایینی قلعه منتظرند.
شکل ۹. نسبت ابعادی بزرگ‌تر که انبوهی از زامبی‌ها را در بیرون دیوارهای قلعه نشان می‌دهد.

درعوض، می‌توانید از رندر کردن هندسه سطح فراتر از مرزهای منطقه بازی فعلی صرف‌نظر کنید:

نمای بازی نقش‌آفرینی تاکتیکی ایزومتریک از Bugdroid و Mecha Hamster در داخل دیوارهای قلعه.
شکل ۱۰. محوطه بازی داخل دیوارهای قلعه.
نمای گسترده ایزومتریک تاکتیکی بازی نقش‌آفرینی که در آن هندسه سطح و دشمنان خارج از دیوارهای قلعه حذف شده‌اند.
شکل ۱۱. نسبت ابعادی بزرگ‌تر که در آن هندسه سطح فراتر از منطقه بازی فعلی ارائه نمی‌شود.

مرزهای داستانی

در بازی‌های سه‌بعدی همه‌جانبه که در آن‌ها میدان دید گسترده می‌تواند به مزیت رقابتی در بازی‌های چندنفره اول شخص یا سوم شخص منجر شود یا مناطق غیرمجاز بازی‌های مبتنی بر مجموعه ثابت را آشکار کند، به‌جای تکیه بر جعبه نامه مستطیلی، عناصر داستانی را در بازی بسازید تا میدان دید را محدود کنید. نمونه‌ها عبارت‌اند از:

  • اتاق فرمان داخلی وسیله نقلیه‌ای مثل خودرو یا هواپیما
  • داخل کلاه ایمنی
  • تصویر حاشیه‌دار که لبه دید بازیکن را نشان می‌دهد

عناصر میانای کاربر و نمایشگر هاد (HUD) باید همچنان تا لبه صفحه‌نمایش گسترش یابند یا در مرزهای داستانی ادغام شوند، و ایده‌آل این است که پویا باشند. این عناصر داستانی همچنین می‌توانند به بازیکنانی که دچار بیماری حرکت می‌شوند کمک کنند (به‌ویژه در ضریب‌های شکل واقعیت گسترده) و علاوه‌بر کمک به کاهش پیچیدگی نسبت‌های ابعادی جدید، یک کمک دسترسی‌پذیری ارائه دهند.

از رندر کردن بازی روی سطحی در داخل صحنه ثابت غیرتعاملی اجتناب کنید. اگرچه این رویکرد بهتر از رندر کردن نوارهای سیاه برای جعبه‌های نامه و تصویر باریک است، بازیکنان به‌سرعت متوجه حاشیه‌های ثابت می‌شوند و اگر بازی‌های موردعلاقه‌شان در ابعاد غیرتلفن به اندازه یک وصله صفحه‌نمایش تلفن رندر شود، ممکن است ناامید شوند.

در این مثال، بازی‌ای که برای صفحه‌نمایش تلفن استاندارد طراحی شده است درون یک تلویزیون شبیه‌سازی‌شده با دسته بازی واقع‌گرایانه ارائه می‌شود تا با نسبت ابعادی مربعی‌تر که در نمایشگرهای داخلی دستگاه‌های تاشو رایج است سازگار شود:

بازی هزارتوی سه‌بعدی که در داخل قاب شبیه‌سازی‌شده تلویزیون CRT با دسته بازی واقع‌گرایانه در پیش‌زمینه رندر شده است.
شکل ۱۲. بازی در یک قاب تلویزیون شبیه‌سازی‌شده ثابت با یک دسته بازی واقع‌گرایانه نمایش داده می‌شود.

برخی‌از بازی‌های سه‌بعدی ممکن است لازم باشد میدان دید را به‌دلیل رعایت انصاف در رقابت یا ملاحظات طراحی محدود کنند. استفاده از کابین خلبان، کلاه ایمنی، یا استعاره‌های داستانی دیگر برای محدود کردن میدان دید بهتر از نوارهای سیاه است:

نمای سه‌بعدی اول شخص از هزارتو از داخل کابین خلبان کروی شکل همستر با نقشه کوچک در بالا و کنترل‌های لمسی در پایین.
شکل ۱۳. قاب کروی دیژتیک کابین خلبان که میدان دید را محدود می‌کند و درعین‌حال نمایشگر هاد (HUD) و کنترل‌ها را به لبه‌های صفحه‌نمایش متصل می‌کند.

منابع بیشتر