Scalerهای سفارشی (Custom Scalers)
شما میتوانید با ایجاد Scalerهای سفارشی، سیستم Web Adaptive Performance را بهراحتی گسترش دهید. این کار در صورتی مفید است که بخواهید مکانیکهای خاصی از بازی را بهطور پویا بهینهسازی کنید: مثلاً کاهش تراکم جمعیت، غیرفعال کردن شیدرهای سنگین، یا ساده کردن هوش مصنوعی دشمنان هنگام افت FPS.
معماری WebAP در برابر Unity AP
در پکیج رسمی Unity، ایجاد Scalerهای سفارشی نیازمند تنظیمات پیچیدهای است: ساخت یک ScriptableObject، پیوند دادن پیکربندیها از طریق اینترفیسها (Interfaces) و انتخاب بین یکی از دو گردش کارِ (Workflow) ناسازگار با یکدیگر.
در WebAP، همهچیز بهصورت Plug-and-Play کار میکند.
کافیست یک اسکریپت C# ساده بنویسید که از WebScalerBase ارثبری کند. هسته افزونه بهطور خودکار کلاس شما را پیدا کرده و به لیست سراسری Scalerها در پنجره Project Settings اضافه میکند، جایی که میتوانید آن را فعال کرده و پارامترهایش را بهصورت بصری تنظیم کنید.
یادگیری با مثال
بهترین راه برای درک نحوه نوشتن Scalerهای سفارشی، بررسی نمونههای داخلی (Built-in) است. سورسکد تمامی Scalerهای پایه (Resolution, Shadows, LOD و غیره) در مسیر زیر در پروژه شما قرار دارد:WebAdaptivePerformance/Runtime/Scalers/.
قالب Scaler سفارشی
برای ایجاد Scaler خود، ۳ مرحله ساده را دنبال کنید:
۱. کلاسی بسازید که از WebScalerBase ارثبری کند.
۲. در Constructor پارامترهای پیشفرض (Target، Visual Impact، Max Level) را مقداردهی کنید.
۳. متدهای چرخه حیات (Lifecycle) را بازنویسی (Override) کنید: OnEnabled()، OnDisabled()، و OnLevel().
حذف کد توسط IL2CPP (حیاتی برای WebGL)
هنگام بیلد گرفتن برای WebGL، کامپایلر IL2CPP کدهایی را که استفاده نمیشوند ("Dead Code") بهطور تهاجمی حذف (Strip) میکند. از آنجایی که افزونه Scalerهای سفارشی شما را بهصورت پویا از طریق Reflection ایجاد (Instantiate) میکند، کامپایلر آنها را بدون استفاده در نظر گرفته و از بیلد نهایی پاک میکند.
همیشه ویژگی [UnityEngine.Scripting.Preserve] را به کلاسهای سفارشی خود اضافه کنید. این کار تضمین میکند که Scaler شما در بیلد نهایی (Release Build) بهدرستی کار خواهد کرد.
مثال: Scaler کیفیت بافت (Texture Quality Scaler)
در زیر یک مثال جامع از ایجاد Scaler برای کاهش وضوح بافتها (Mipmap Limit) آورده شده است.
using System;
using UnityEngine;
using GrindsetStudios.WebAdaptivePerformance.Scalers;
// افزودن این Attributes برای نمایش UI (در Project Settings) و جلوگیری از حذف کد (توسط IL2CPP) الزامی است
[Serializable]
[UnityEngine.Scripting.Preserve]
public sealed class WebTextureQualityScaler : WebScalerBase
{
// متغیری انحصاری برای ذخیره تنظیمات اولیه کاربر
private int _defaultTextureLimit;
public WebTextureQualityScaler()
{
// تعیین میکند که این Scaler بار روی کارت گرافیک را کاهش میدهد
_target = ScalerTarget.GPU;
// کاهش وضوح بافتها بسیار به چشم میآید، بنابراین تأثیر بصری را High قرار میدهیم
_visualImpact = ScalerVisualImpact.High;
// تنظیم ۳ مرحله کاهش کیفیت برای بافت: نصف (۱)، یکچهارم (۲)، یکهشتم (۳)
_maxLevel = 3;
}
// در شروع بازی یا فعال شدن افزونه فراخوانی میشود
protected override void OnEnabled()
{
// مقدار اصلی را ذخیره میکند تا هنگام غیرفعال شدن Scaler بتواند آن را بازیابی کند
_defaultTextureLimit = QualitySettings.globalTextureMipmapLimit;
ApplyScale();
}
// هنگام غیرفعال شدن افزونه یا حذف دستی Scaler فراخوانی میشود
protected override void OnDisabled()
{
// بازی را بهطور ایمن به حالت اولیه بازمیگرداند
QualitySettings.globalTextureMipmapLimit = _defaultTextureLimit;
}
// هر بار که Indexer تصمیم به تغییر سطح کیفیت میگیرد، فراخوانی میشود
protected override void OnLevel()
{
ApplyScale();
}
private void ApplyScale()
{
// متد ScaleChanged() وضعیت مقیاس را دوباره محاسبه کرده و در صورت تغییر true برمیگرداند
if (ScaleChanged())
{
// ما عمداً از مقدار پیشفرض برای محاسبات استفاده نمیکنیم
// تا در صورتی که گرافیک از ابتدا در حداقل مقدار خود بوده، از تداخل (Conflicts) جلوگیری کنیم.
//
// پارامتر globalTextureMipmapLimit مقادیر صحیح را میپذیرد:
// 0 (کامل)، 1 (نصف)، 2 (یکچهارم)، 3 (یکهشتم).
// متغیر CurrentLevel ما (از 0 تا 3) دقیقاً با این منطق هماهنگ است.
QualitySettings.globalTextureMipmapLimit = CurrentLevel;
}
}
}هنگامی که این اسکریپت را ذخیره کردید، به مسیر Edit -> Project Settings -> Adaptive Performance (Web) بروید. تب Scalers را باز کنید، خواهید دید که Texture Quality به لیست ماژولهای موجود اضافه شده است.
بهینهسازی جستجوی اشیاء
متد OnLevel() ممکن است بهدفعات فراخوانی شود (در طول زمانهای Cooldown). هرگز از متدهای سنگین مانند GameObject.Find() یا GetComponent() در داخل آن استفاده نکنید. همیشه کامپوننتهای مورد نیاز را در متد OnEnabled() پیدا کرده و در حافظه پنهان (Cache) ذخیره کنید.
