12 + 1 نکته بهینه سازی بازی های موبایل در یونیتی

آیفون، آیپد و گجت‌ های اندرویدی به نسبت کنسول و کامپیوتر های شخصی، سخت افزار ضعیف تری دارند، در نتیجه برای ساخت بازی برای آنها باید برنامه نویس قوی تری شوید. هرچند که بهینه سازی نباید در ابتدای توسعه انجام شود، اما در این مقاله شما با رویه هایی آشنا خواهید شد که با پیروی از آنها از تکرارِ مداوم یک اشتباه، جلوگیری خواهید کرد.بهینه سازی بازی نیمی تجربه و نیمی هنر است. شما باید میانبر ها، روش های متفاوت ایمپورت کردن، رفتار موتور یونیتی و خط های کد تان را بشناسید. مطمئنا هنگامی که بازی تان بر روی آیفون قدیمی یا گوشی اندرویدی تان خیلی آهسته اجرا شد، ایده ها و نکته های این مقاله را بیش از پیش کاربردی و با ارزش خواهید یافت.نکته شماره 0: موبایلِ تستِ بازی تان را هوشمندانه انتخاب کنیدهرچه دستگاه کند تر باشد، بهتر است. البته در این کار افراط نکنید زیرا یک گوشی بسیار کند، سرعت شما را خیلی کم خواهد کرد و باعث می شود از ابتدای کار شروع به بهینه سازی کنید، که کاری اضافی و غیر ضروری خواهد بود. به نظر من گوشی های میان رده گزینه ی مناسبی خواهند بود.تا به حال هیچ وقت اینقدر دستگاه های جور وا جور در دنیا وجود نداشته !بهینه سازی در حجم بازیگاهی اوقات بازی شما بدون هیچ دلیلی فضای بسیار زیادی را اشغال می کند .حجم بازی تان از اهمیت بسیار بالایی برخوردار است و باید همواره مراقب آن باشید، زیرا این موضوع روی تعداد افرادی که بازی تان را دانلود میکنند تاثیر مستقیم دارد. علاوه بر این به خاطر داشته باشید که وقتی کاربری نیاز دارد نرم افزاری را حذف کند تا فضای بیشتری برای گوشی خود خالی کند، ابتدا نرم افزار های با حجم بالا هستند که قربانی می شوند!نکته شماره 1: تکسچر ها و فایل های صوتی را فشرده کنیداز بازی تان خروجی بگیرید و سپس درون Editor.log به دنبال فایل هایی بگردید که بیشترین فضا را در بازی تان اشغال کرده است، که اکثر اوقات تکسچرها و فایل های صوتی می باشند. برای اینکه تکسچرها بصورت فشرده و کم حجم در بازی مورد استفاده قرار گیرند باید رزولوشن آنها توان دو باشد، مثلا 1024X2014 گزینه ی مناسبی است. و ترجیحا این ابعاد را بیشتر از 2048 در نظر نگیرید. همچنین فایل های صوتی نیز باید همواره حالت فشرده سازی شان (Compression) فعال باشد مگر اینکه فایل صوتی خیلی خیلی کوتاه باشد و فشرده سازی کیفیتش را مختل کند. (که خیلی بعید است)نکته شماره 2: اسپرایت ها را بسته بندی کنید (Pack)همواره باید اسپرایت های UI و بازی را بسته بندی کنید. از ورژن یونیتی 5 به بعد کاربران امکان استفاده رایگان از Sprite Packerدرون موتور یونیتی را دارند. علاوه بر این ابزار های دیگری مانند NGUI نیز در این زمینه بسیار کارآمد و محبوب هستند. به کمک ابزار sprite packer می توانید به راحتی محدودیتِ اسپرایت ها با رزولوشنِ توان دو و ساخت atlas که گاها از سمت آرتیست ایجاد میشود را از بین ببرید. تنها کافیست که تگِ بسته بندی (packing tag) را مشخص کنید تا یونیتی همه مشکلات را حل کند و به راحتی حجم بازی تان به شکل قابل توجهی کاهش پیدا کند.نکته شماره 3: کتابخانه و dll های بدون استفاده را حذف کنیدشما باید امکان حذفِ (stripping) کتابخانه ها و dll هایِ بدونِ استفاده را فعال کنید، البته به شرط اینکه مشکلی برای پروژه تان و پلاگین های مورد استفاده از آن پیش نیاید. بازی دو بعدی شما احتمالا از بسیاری از امکانات یونیتی از جمله فیزیک استفاده نمی کند که فضای زیادی از بازی تان را اشغال کرده و میتوانید با این تکنیک از شر این فضای اضافی خلاص شوید.نکته شماره 4: مطمئن شوید که asset های غیرضروری را در پروژه اضافه نکرده ایداگر یک گیم آبجکت غیرفعال در بازی دارید، یونیتی در هنگام خروجی گرفتن از بازی تمام رفرنس هایی که آن گیم آبجکت مورد استفاده قرار داده را درون فایل خروجی قرار می دهد، حتی اگر این گیم آبجکت هیچگاه درون بازی فعال نشود و مورد استفاده قرار نگیرد. پنجره hierarchy را از گیم آبجکت های غیر ضروری و رفرنس های آن به assetهایِ بدون کاربرد پاکسازی کنید. همچنین هر فایلی که درون پوشه Resources باشد نیز در خروجی بازی تان اضافه می شود، پس مراقب این موضوع باشید !به خاطر داشته باشید که بهینه سازی مانند هدیه ای است که شما به پلیرهای محبوبتان می دهید.بهینه سازی در استفاده از حافظهسیستم عامل گوشی های هوشمند با آپگرید شدن، نیازمند RAM بیشتری شده اند که در نتیجه این امر، فضایِ حافظهِ کمی برای بازی شما خالی خواهد ماند (بله iOS روی صحبتم با تو هست! ...). با این شرایط بسیار منطقی است که تا حد ممکن تعداد asset های بازی تان که در حافظه لود می شود را کاهش دهید اولین دلیلی که باعث می شود اپلیکیشنی توسط سیستم عامل بسته شود، فشار حافظه (Memory Pressure) است. درست متوجه شدید، کِرَش های رندم بازی تان، اکثرا کِرَش هایی به دلیل مشکلات حافظه هستند.نکته شماره 5: اسپرایت ها را ...هوشمندانه....بسته بندی کنید (Pack)وقتی بازی را اجرا میکنید، فایل ها از حالت فشرده خارج می شوند و دوباره فضای زیادی را اشغال خواهند کرد. اما اگر کارتان را درست انجام داده باشید و اسپرایت ها را به شکل مناسب بسته بندی کرده باشید، فضای زیادی از RAM را حفظ خواهید کرد. قاعده کلی این است که باید تصاویری که قرار است باهم نشان داده شوند را با هم بسته بندی کنید و سعی کنید و سع کنید فضای خالی زیادی در atlasنداشته باشید. برای مثال باید تصاویر مرتبط با رابط کاربری بازی تان را درون یک atlas مجزا قرار دهید. اما در صورتی که بخش بزرگی از آیتم های رابط کاربری تان خیلی مورد استفاده قرار نمیگیرد، باید اسپرایت های آن را درون یک atlasدیگر ذخیره کنید. نکته ی مهم دیگر این که از اسپرایت های 9 قسمتی در رابط کاربری استفاده کنید و به هیچ وجه از تصاویر بکگراند خیلی بزرگ استفاده نکنید، به هیچ وجه.(در عوض سعی کنید تصویر بکگراند را از تایل ها یا اسپرایت های ساده تر بسازید). و نکته ی پایانی اینکه Mipmaps را غیر فعال کنید.نکته شماره 6: کیفیت تصاویر و فایل های صوتی را کم کنیدآیا مطمئنید که در بازی تان به کاراکتری با طول یا عرض 1024 پیکسل نیاز دارید؟به نظرم نیازی به این کیفیت نداشته باشید چون رزولوشن رایج در بین گوشی ها 1024x768 است. (مگر اینکه می خواهید کاراکتر تان، هم اندازه نمایشگر گوشی باشد). آیا موزیک بازی تان یک لوپ 3 دقیقه ای است؟ شاید بتوانید آن را به 30 ثانیه کاهش دهید.این موضوع خیلی رایج است که بازی ساخته شده از حداکثر کیفیت گوشی ها بیشتر باشد. اگر کیفیت تصاویر و فایل های صوتی را کاهش دهید اکثر افراد متوجه این تفاوت در گوشی هایشان نخواهند شد.نکته شماره 7: مراقب رفرنس ها در صحنه بازی (scene) باشیدبگذارید اتفاقی که برای خودم رخ داد را برایتان تعریف کنم. در گذشته در حال توسعه و ساخت یک بازی بودم که در آن تصاویر زیادی وجود داشت. بر اساس انتخاب پلیر ، پریفبی از لیست انتخاب و instantiateمیشد و تصویری ظاهر میشد. این لیست بسیار طولانی بود. در کمال تعجبم این لیستِ رفرنس باعث این میشد تا تمام پریفب ها و تصاویر، درون حافظه RAM لود شوند که اصلا خوب نبود. نکته ی اخلاقی این داستان؟ پروفایلر هیچگاه به شما دروغ نمی گوید، پس همیشه از آن استفاده کنید.نکته شماره 8: اگر نیاز شد از پوشه منابع (Resource Folder) استفاده کنیدراهکار برای مشکل قبلی این است که تمام پریفب ها و asset ها را درون پوشه resourceببرید و هر زمان که نیاز داشتید، همان آیتم را به شکل پویا و داینامیک لود کنید. این روش مثل استفاده از رفرنس خیلی راحت و بی دردسر نیست زیرا شما باید همواره آدرس asset ها را معین کنید و اگر ناخواسته فایلی را به آدرس دیگر منتقل کردید، با خطا روبرو خواهید شد. اما میتوانید به کمک اسکریپت نویسی، ادیتوری برای این منظور بسازید تا این مشکل را برطرف کند.وقتی بازی تان از حجم زیادی از RAM استفاده می کند سیستم عامل با عصبانیت بازی را می بندد :)بهینه سازی در استفاده از CPUیک بازی کند، یک بازی مرده به حساب می آید. پلیر ها در خیلی از موارد با شما کنار می آیند و سطح معمولی بازی تان را نادیده می گیرند. اگر بازی تان رابط کاربری بد، داستان معمولی، گرافیک ضعیف و … داشته باشد احتمالا پلیرها شما را خواهند بخشید، اما در مورد پرفورمنس ضعیف، جای هیچ گونه بخششی نخواهد بود. باید محدودیت هایتان را بشناسید و در مواقعی که مجبور هستید خیلی از چیزها را به بهای فریم ریت قابل قبول قربانی کنید. بله، این یک واقعیت تلخ است!نکته شماره 9: مراقب ساختار های آبنباتی (candy syntax ) باشید، مانند حلقه foreachاین نکته یکی از تکراری ترین راهکارها برای بهینه سازی CPU در یونیتی است. زیرا یونیتی از ورژن های قدیمی دات نت فریمورک استفاده میکند که به اندازه کافی بهینه نیستند. پس بهتر است به جای foreach از حلقه ی for استفاده کنید و به جای لیست از آرایه استفاده کنید.(البته این موضوع مربوط به ورژن های قدیمی یونیتی است که در زمان نوشتن مقاله مورد استفاده قرار میگرفته و در نسخه های جدید یونیتی این مشکل برطرف شده. اکنون یونیتی از NET 4.x. پشتیبانی می شود )نکته شماره 10: لاگ های کنسول را حذف کنیددر یونیتی متغیرهایی از نوع رشته (strings) باعث کند شدن بازی تان می شوند و تا می توانید از تغییر دادن رشته ها بپرهیزید. به همین دلیل حتما در انتهای توسعه بازی، تمامی Debug.Logهایی که برای لاگ گرفتن و دیباگ کردن بازی نوشته اید را حذف کنید، مخصوصا آنهایی که در update یا حلقه ها هستند. از اینکه تغییری به این کوچکی چقدر میتواند روی کارایی بازی تاثیر بگذارد شگفت زده خواهید شد.نکته شماره 11: بهینه سازی را از پایین به بالا شروع کنیدوقتی در حال بهینه سازی بازی تان هستید و پروفایلر را چک میکنید، کلاس هایی که باعث کند شدن بازی شده اند را شناسایی کنید و سپس شروع به بهینه سازی کلاسی کنید که در انتهای و پایین ترین نقطه قرار دارد. اینها کلاس هایی هستند که کلاس های دیگر هم از آنها استفاده میکنند، برای مثال کلاس های هوش مصنوعی (AI) یا مسیریابی (Pathfinding). اگر شانس بیاورید احتمالا با بهینه سازی کلاس های پایین، نیازی به تغییر در کلاس های بالا نداشته باشید.نکته شماره 12: ابتدا به دنبال گلوگاه های (bottlenecks) کلاسیک بگردید، مثل حلقه های تو در تو یا اسکریپت هایی که آیتم های زیادی تولید (instantiate) میکنندتصور کنید که اسکریپتی به اسم PlayerController و اسکریپت دیگری به نام EnemyControllerدارید. اگر قرار است در بازی تان 100 دشمن به صورت همزمان وجود داشته باشند و کنترل شوند، پس این احتمال وجود دارد که اسکریپت EnemyController صد مرتبه بیشتر باعث کند شدن بازی تان شود. درنتیجه شروع به بهینه سازی این اسکریپت کنید و ابتدا سراغ راهکارهای کلاسیکی مانند این موارد بروید: فراخوانی های کندی مانند تابع FindObjectOfType را حذف کنید، استفاده از این توابع در Updateممنوع است. از کَش کردن به کمک متغیر ها استفاده کنید. همچنین کلاس های Singleton نیز می تواند در زمینه بهینه سازی به شما کمک کند.پروفایل عمیق (deep profile) به شما اجازه می دهد تا توابع کند را پیدا کنید. هر چند خود این نوع پروفایل کردن، پرفورمنس را کاهش میدهد.بهینه سازی خوبی را برایتان آرزومندم ! و به خاطر داشته باشید که بازی ای بسازید که پلیرهای تان مستحق آن باشند، پس بازیِ عالی بسازید.منبع: unitydojoترجمه شده در شماره 29 بازینامه