بهینه‌سازی بازی

بهینه‌سازی (optimization) بازی به مجموعه اصلاحاتی در پروژه گفته می‌شود که در نهایت منجر به کاهش مصرف منابعی از قبیل حافظه، پردازش، رم، گرافیک و… توسط بازی در هنگام اجرا می‌شود؛ علاوه بر این موضوع بهینه‌سازی باعث کاهش قابل توجه حجم فایل(های) بازی می‌گردد. حجم یکی از فاکتورهای مهم تصمیم‌گیری کاربران برای دریافت بازی از مارکت‌ها می‌باشد. بدیهی است که کاربران یک مارکت در مواجهه با یک بازی پرحجم به سادگی از نصب آن صرفنظر می‌کنند. این موضوع تاحدی اهمیت دارد که بازی‌های پرحجم اندرویدی assetهای مورداستفاده‌ی خود را از فایل اصلی بازی جدا کرده و بازی پس از نصب اقدام به دانلود دیتا می‌کند.

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

هنر یک بهینه‌سازی مناسب در مدیریت حداکثری مصرف منابع توسط اجزای بازی بدون آسیب رساندن به هویت و کیفیت بازی است

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

ابزارهای مشاهده‌ی میزان مصرف منابع

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

پنجره‌ی Profiler

image

پنجره‌ی Profiler میزان مصرفی منابع در حین اجرای بازی را در قالب داده‌های آماری و نمودار در دسته‌بندی‌های تفکیک شده نمایش می‌دهد. برای باز کردن این پنجره از منوی Window گزینه‌ی Analysis و سپس Profiler را انتخاب می‌کنیم. سپس بازی را اجرا کرده تا عملیات گزارش‌گیری آغاز شود. دقت کنید که برای این کار کلید Record نوار کنترل این پنجره باید فعال باشد.

نکته

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

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

این داده‌ها مربوط به دسته‌ی انتخاب شده می‌باشند (به عنوان مثال در تصویر بالا دسته‌ی انتخاب شده CPU Usage است)؛ این دسته با رنگ آبی از سایر دسته‌ها متمایز می‌شود. با کلیک بر روی هر دسته می‌توان آن را به حالت انتخاب درآورد.

یکی از مهم‌ترین داده‌های پنجره‌ی Profiler، داده‌ی Draw Calls می‌باشد که در هنگام فعال بودن قسمت Rendering نمایش داده می‌شود. Draw Call به عملیات پردازش تصویری گفته می‌شود که منجر به رندر شدن texture در صفحه نمایش پلیر می‌شود. داده‌ی Draw Calls تعداد دفعات رندر شدن texture در آن فریم را نشان می‌دهد. این عدد با پرفورمنس بازی رابطه‌ی عکس دارد و تا حد امکان بایستی پایین نگه داشته شود.

پنجره‌ی Rendering Statistics

image

این پنجره که با کلیک بر روی دکمه‌ی Stats واقع در نوار کنترل پنجره‌ی Games نمایان می‌شود نیز حاوی اطلاعاتی است که در حالت اجرای بازی در هر فریم بروز شده و می‌توانند مفید واقع شوند.

روش‌های بهینه‌سازی

استفاده از assetهای مناسب

بدیهی است که حجم تمام assetهای مورد استفاده در بازی باید تا حدی که به کیفیت آسیب نرسد کاهش داده شوند. برای مثال می‌توان به استفاده از فرمت‌های فشرده برای فایل‌های صوتی و استفاده از الگوریتم‌های فشرده‌سازی lossless (بدون آسیب) هنگام خروجی گرفتن تکسچرها از نرم‌افزارهای گرافیکی (مثل فتوشاپ) اشاره کرد. همچنین ابعاد تکسچرها نباید بیش از اندازه بزرگ باشد؛ بزرگی ابعاد یک تکسچر تا حدی که در بزرگ‌ترین رزولوشن مرسوم با افت کیفیت مواجه نشود کفایت می‌کند.

یکی دیگر از مواردی که بهتر است در خصوص ابعاد یک تکسچر به آن توجه شود «توانی از 2 بودن» طول و عرض تکسچرها است. به این معنی که استفاده از تکسچرهایی با ابعاد «2 به توان n ضربدر 2 به توان m» پیکسل (که m و n عدد طبیعی هستند) باعث صرفه‌جویی در پردازش گرافیکی می‌شود. علت این امر به معماری کارت‌های گرافیک باز می‌گردد. به تکسچرهایی که ابعاد آن‌ها توانی از 2 است POT (مخفف Power Of Two) و به سایر تکسچرها NPOT (مخفف Non-Power Of Two) گفته می‌شود.

تنظیمات صحیح assetها

علاوه بر assetهای مناسب، تنظیمات صحیح یک asset (در Inspector) نیز در بهینه‌سازی یک بازی تاثیر دارد. بهتر است تنظیماتی که در inspector این assetها platform-specific است به ازای هر پلتفرم override شود.

image

برای مثال در صورتی که پراپرتی Max Size موجود در تنظیمات تکسچرها (که گزینه‌های آن توان‌های 2 هستند) با ضلع بزرگ‌تر تکسچر متناسب باشد (یعنی کوچکترین گزینه‌ای که مساوی یا بزرگ‌تر از اندازه‌ی ضلع است) خروجی بهینه‌تری خواهیم داشت.

استفاده از texture atlas

در حالت عادی به ازای هر اسپرایت موجود در صحنه یک Draw Call انجام خواهد شد. این امر به هیچ وجه مطلوب نیست و بر پرفورمنس بازی تاثیر زیادی می‌گذارد. برای حل این مشکل باید اسپرایت‌هایی که در یک صحنه استفاده می‌شوند در یک texture atlas قرار داشته باشند. چرا که تمام اسپرایت‌های یک texture atlas تنها با یک بار Draw Call رندر می‌شوند.

در مواقعی که اسپرایت‌ها از همدیگر جدا هستند با استفاده از ابزار Sprite Packer می‌توان نسبت به ایجاد یک texture atlas جدید توسط ادیتور یونیتی اقدام نمود.

نکته

برای مشاهده‌ی دقیق ترتیب رندر شدن تکسچرها (Draw Calls) از پنجره‌ی Frame Debug (از مسیر Window>Analysis>Frame Debugger) استفاده می‌شود.

مدیریت گیم‌آبجکت‌های بدون استفاده

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

یکی از روش‌های مرسوم برای مدیریت گیم‌آبجکت‌ها استفاده از مفهومی به نام استخر اشیا (Object Pool) است. از آن‌جا که ساختن و نابود کردن گیم‌آبجکت‌ها امری هزینه‌بر است در این الگوریتم‌ها هیچ گیم‌آبجکتی از بین نمی‌رود؛ بلکه پس از پایان وظیفه‌ی خود غیرفعال شده و در مخزنی به نام استخر (pool) قرار می‌گیرد. سپس در صورت نیاز مجدد فعال شده و دوباره مورد استفاده قرار می‌گیرد.

image

عکس از raywenderlich.com

استفاده از اسکریپت‌های استاندارد

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