مقالات فنی

بهینه سازی مصرف باتری در بازی های ساخته شده با یونیتی برای موبایل

توسط شهریور ۲۴, ۱۳۹۷ بدون نظر

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

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

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

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

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

اندازه گیری دقیق مصرف باتری

دو روش اصلی برای اندازه گیری دقیق میزان مصرف باتری در اندروید وجود دارد

۱. اندازه گیری دقیق با استفاده از ابزار سخت افزاری

با استفاده از ابزار High Voltage Power Monitor که توسط شرکت Monsoon ارائه شده است، می توان با دقت میزان مصرف باتری را اندازه گیری کرد. توضیحات بیشتر در لینک زیر قابل مطالعه است. اشکال این روش هزینه این ابزار و همچنین مشکل بودن تهیه آن است.

https://msoon.github.io/powermonitor/PowerTool/doc/Power%20Monitor%20Manual.pdf

۲. اندازه گیری با استفاده از realtime profiler روی گوشی

ابزارهای پروفایلر وجود دارند که با دسترسی مستقیم به Power Management IC در اندروید میزان مصرف باتری را اندازه گیری می کنند. Trepn یکی از بهترین ابزارهای پروفایلر است که توسط شرکت Qualcomm ساخته شده است. این ابزار با استفاده از لینک زیر قابل نصب در گوشی است:

https://play.google.com/store/apps/details?id=com.quicinc.trepn&hl=en_US

از جمله مزایای این ابزار عدم نیاز به سخت افزارهای جانبی (حتی کامپیوتر) و نیز عدم هزینه است.

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

https://developer.qualcomm.com/forum/qdn-forums/software/trepn-power-profiler/28349

برای غیر از این موارد این ابزار در حالت Estimation Mode اجرا می شود که با بررسی های انجام شده نتیجه آن قابل اتکا نبوده است.

نکته: در صورتی که نیاز به جمع آوری اطلاعات بر روی کامپیوتر باشد، می توان از Snapdragon Profiler  استفاده کرد. علاوه بر میزان مصرف باتری، اطلاعات مرتبط دیگری نظیر میزان مصرف CPU و GPU و حافظه و همچنین دمای دستگاه را نیز ارائه می کند.

نکته: برای پروفایل کردن GPU نیز می توان از GPU Profiler هایی نظیر Adreno که این نرم افزار نیز محصول شرکت Qualcomm است استفاده کرد.

نکته: برای iOS می توان از Instruments استفاده کرد:

https://gamedev.stackexchange.com/questions/35755/how-to-check-battery-usage-of-an-iphone-android-app

 عوامل احتمالی مصرف بیش از اندازه باتری

در ادامه لیستی از موارد احتمالی که بهینه سازی آنها می تواند در کاهش مصرف باتری موثر باشد لیست شده است.

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

تعداد فریم های پردازش شده در هر ثانیه (targetFrameRate)

هر چه fps بیشتر باشد به معنای استفاده بیشتر از منابع سیستم است. بنابراین باید تا جایی که امکان دارد Application.targetFrameRate را پایین آورد.

  1. بسیاری از بازی ها به خوبی با ۳۰fps روی گوشی اجرا می شوند و نیازی به پردازش ۶۰ فریم در ثانیه نیست.
  2. اگر بازی شما یک بازی اکشن نیست و خیلی از مواقع می توان از تصویر رندر قبلی مجددا استفاده کرد، در شرایط خاص می توان fps را تا ۱۵ یا حتی ۱۰ کاهش داد. مثلا زمانی که UI در حال نمایش است، یا وقتی که بازی برای مدتی بیکار بوده است.
  3. اگر با فعال کردن vSync قصد محدود کردن تعداد فریم های پردازش شده را دارید، مقدار targetFrameRate را تغییر ندهید و فقط با مقداردهی به vSyncCount این کار را انجام دهید. یونیتی فعال بودن هر دوی این موارد را توصیه نمی کند.
  4. در نسخه ۲۰۱۷ یونیتی پردازش Input همزمان با پردازش یک frame انجام می شود و کاهش fps حتی اگر نیازمند رندر تصویر جدید هم نباشد، ممکن است موجب کاهش سرعت واکنش به کاربر شود. زیرا پردازش Input هم در هر frame انجام می شود. یک ویژگی جدید در یونیتی در حال برنامه ریزی است که وابستگی Input به تعداد فریم را از بین می برد و در صورت پیاده سازی می توان fps را در زمان های خاص با شدت بیشتری کاهش داد. مثلا در صفحه های UI که انیمیشن خاصی هم در حال اجرا نیست حتی می توان fps را به ۱ تغییر داد و بعد از دریافت Input کاربر آن را اصلاح کرد. اطلاعات بیشتر در این زمینه: https://forum.unity.com/threads/battery-preserving-low-frame-rate-but-with-immediate-new-frame-upon-input.476263/ فرد خوش ذوقی یک سایت اینترنتی برای بررسی اینکه آیا این ویژگی در یونیتی پیاده سازی شده است یا نه راه اندازی کرده است: http://www.isthenewinputhereyet.com

انتخاب معماری صحیح

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

https://x-team.com/blog/unity3d-v4-3-2d-vs-3d-physics/

کیفیت نمایش تصویر (Resolution)

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

  1. در زمان نمایش UI معمولا کیفیت بالایی نیاز نیست. در این صورت ممکن است بتوان رزولوشن را پایین آورد.
  2. ممکن است بتوان به انتخاب کاربر یا در شرایط خاص که میزان انرژی ذخیره شده باتری کاهش پیدا کرده، یا زمانی که دستگاه به برق متصل نیست، از رزولوشن پایین تری استفاده کرد.
  3. با تنظیم Resolution Scaling Mode در Player Settings از یک ضریب بر حسب DPI دستگاه پشتیبانی می کند. استفاده خودکار از این ضریب به جای یک ضریب ثابت باعث می شود رزولوشن در دستگاه های ضعیف تر تغییر نکند و باعث کاهش کیفیت نشود، و برای دستگاه های قوی تر نیز بی دلیل زیاد نباشد.

انیمیشن ها (و spine)

انیمیشن های Spine و دیگر انواع انیمیشن ها بخش عمده ای از مصرف منابع را بر عهده دارند.

  1. انیمیشن اشیائی که خارج از محدوده دید دوربین قرار دارند (انیمیشن های غیر حرکتی) غیر فعال شود. برای این کار میتوان از OnBecameInvisible استفاده کرد.
  2. سعی شود از spine به صورت بهینه استفاده شود تا حداقل مصرف منابع سیستم را داشته باشد.
    1. اگر ازsubmesh استفاده نمی کنید گزینه Use Single Submesh فعال باشد
    2. اگر از attachement استفاده نمی کنید گزینه Immutable Triangles فعال باشد
    3. تا حد امکان از skin های کمتری استفاده کنید و فقط به اندازه مورد نیاز skin ساخته شود.
    4. در صورت امکان می توانید انیمیشن های spine را به صورت baked استفاده کنید.
    5. به جای json از binary استفاده کنید.

ضمنا در زمان ساخت انیمیشن ها می توان به نکاتی توجه داشت و از پیچیده کردن بی دلیل انیمیشن ها خودداری کرد تا پردازش کمتری برای نمایش آنها نیاز باشد. برای مطالعه بیشتر در این زمینه می توانید به این مقاله مراجعه نمایید:

https://www.gamedev.net/articles/programming/graphics/skeletal-animation-optimization-tips-and-tricks-r3988/

Connection Pooling

در صورت امکان به جای باز کردن یک کانکشن و بستن آن هر زمان که نیاز بود، از connection pool استفاده شود. باز و بسته کردن کانکشن و ایجاد کانکشن جدید به جای استفاده از کانکشن های موجود باعث افزایش مصرف باتری خواهد شد.

اطلاعات بیشتر در https://developer.qualcomm.com/download/trepn/trepn-whitepaper-power.pdf

اجرا در پس زمینه

در صورتی که با فرستادن بازی به پس زمینه، همچنان بازی مقدار قابل توجهی باتری مصرف می کند Application Pause و Resume مدیریت شود و در حالتی که بازی در پس زمینه است پردازش قابل توجهی انجام نشود. مثلا timeScale برابر کمترین عدد ممکن قرار داده شود و همینطور targetFrameRate نیز مثلا به عدد ۱ تغییر کند.

کاهش Overdraw

کاهش Overdraw (توجه: میزان overdraw در زمان design در Unity قابل مشاهده است)

  1. حتما میزان overdraw را بررسی کنید و هر جا overdraw وجود داشت برای کاهش آن تلاش کنید
  2. بهینه سازی برای کاهش حجم فایل و تعداد اطلس گاها با بهینه سازی برای مصرف باتری تداخل دارد. در اینصورت بر حسب اینکه مصرف باتری اولویت دارد یا حجم فایل و تعداد اطلس، می توان پیاده سازی را تغییر داد. مثلا اگر در یک بازی دو بعدی برای نمایش جنگل به جای یک تصویر جنگل، از چندین تصویر درخت استفاده می شود که در runtime چیده می شوند، می تواند هم حجم پردازش و هم Overdraw را افزایش دهد.
  3. در صورتی که مناطقی که در بازی تغییر می کنند کل تصویر نمایش داده شده توسط دوربین نیست، می توان از تکنیک Depth Buffer استفاده کرد تا در حالتی که نیازی نیست، کل تصویر مجددا render نشود و فقط بخش هایی که تغییر می کنند در هر فریم رندر شوند. (مثلا UI در حال نمایش است، یا بخش های مشخصی از تصویر تغییر نمی کنند. مثلا در بازی Candy Crash حاشیه تصویر ثابت است و تغییری نمی کند.

بهینه سازی script ها

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

  1. با پروفایلر گلوگاه ها را تشخیص داده و برای بهینه کردن آنها اقدام کنید.
  2. کد را بررسی کنید و مستندی از کل کارهای CPU-bound که در هر فریم انجام می شود تهیه شود و برای بهینه سازی آنها اقدام نمایید.
  3. وقتی شیءای از دید دوربین خارج شد، بخش هایی از کد که ضرورتی ندارند اجرا نشود.
  4. کد بررسی شود و هر جا چیزی محاسبه و پردازش می شود که می توان آن را cache کرد، از محاسبه مجدد آن در هر فریم جلوگیری شود.
  5. در صورتی که Busy Waiting دارید، حذف شوند و از Coroutine با حداکثر فاصله wait ممکن استفاده شود تا پردازنده بیهوده مشغول نباشد.
  6. گاهی اوقات در هر فریم وقوع یک اتفاق بررسی می شود. اگر احتمال رخداد پشت سر هم این اتفاق کم است می توان تعداد این بررسی را کاهش داد و مثلا به ازای هر ۶۰ فریم یک بار این بررسی را انجام داد. مثلا کد را در یک عبارت if با این شرط قرار داد: Time.frameCount % 60 == 0
  7. استفاده از raycast برای تشخیص تاچ بر روی یک Gameobject پر هزینه است. در صورت امکان می توانید از ویژگی جدیدی که یونیتی در نسخه های جدیدتر از آن بهره مند است استفاده کنید.
    1. نحوه پیاده سازی این ویژگی در این لینک قابل مشاهده است: https://stackoverflow.com/questions/41391708/how-to-detect-click-touch-events-on-ui-and-gameobjects
    2. در صورتی که امکان تغییر این روش را ندارید، می توانید استفاده از raycasting را بهینه کنید. به عنوان مثلا طول ray همیشه به اندازه حداکثر میزان مورد نیاز باشد.

بهینه سازی استفاده از سیستم فیزیک در یونیتی

  1. همه ی بازی ها از فیزیک استفاده نمی کنند. در صورتی که از فیزیک استفاده نمی شود، کلا دو سیستم فیزیک یونیتی غیر فعال شوند. یعنی مقادیر برای این دو به false تغییر کند: Physics.autoSimulation, Physics2D.autoSimulation
  2. در صورتی که بازی از فیزیک استفاده می کند این نکته را در نظر داشته باشید. شیئی که collider داشته باشد و ridigbody نداشته باشد، از نوع static در نظر گرفته می شود. یعنی این اشیاء مناسب حرکت دادن و تغییر شکل دادن نیستند و سیستم فیزیک یونیتی طوری بهینه سازی شده است که انتظار حرکت و تغییر از اشیاء استاتیک را ندارد. اگر اشیاء شما به collider نیاز دارند اما نباید تحت تاثیر عوامل فیزیکی قرار بگیرند، یک rigidbody از نوع kinematic نیز به این اشیاء اضافه شود. در غیر اینصورت colliderها را حذف کنید. عدم رعایت این نکته بار پردازشی زیادی روی سیستم فیزیک خواهد داشت.
  3. بسته به نوع بازی، ممکن است بتواند مقدار بهینه تری برای Fixed Timestep انتخاب کرد. هر چه این مقدار بیشتر باشد سیستم فیزیک بار پردازشی کمتری خواهد داشت.

استفاده از SpriteAtlas

SpriteAtlas نوع جدیدی از asset است که با استفاده از آن می توان spriteها را به راحتی در یک atlas مدیریت کرد و از POT بودن texture نهایی نیز مطمئن شد.
اطلاعات بیشتر: https://docs.unity3d.com/Manual/class-SpriteAtlas.html

موارد دیگر

  • Built-in Quality Settings در Unity بهینه سازی شود، و در صورت امکان برای هر دیوایس بر حسب شرایط آن از تنظیمات کیفیت متفاوتی استفاده شود.
  • تیک Use 32-bit Display Buffer برداشته شود (در صورتی که بر کیفیت نمایش رنگ های بازی تاثیر منفی ندارد).
  • همواره از object pool ها استفاده شود و سعی کنید تا حد امکان از instantiate و Destroy کردن اشیاء خودداری کنید و از اشیاء موجود مجدد استفاده کنید.
  • در صورتی که ممکن باشد، موسیقی همواره در حال پخش نباشد و در شرایط خاص آن را متوقف کرد یا صدای آن را کم کرد (مثلا بعد از مدت کوتاهی از عدم ارتباط بازیکن با بازی)
  • از قسمت Player Settings > Resolution and Presentation تیک Disable Depth and Stencil برداشته شود.
  • از anisotropic filtering استفاده نشود.
  • Antialiasing غیرفعال شود.
  • از Simple Filtering استفاده شود.
  • تا حد ممکن از particle ها استفاده نشود. زیرا از تعداد زیادی Draw Call استفاده می کنند و به طور کلی بهینه شده نیستند. در صورت امکان از روش جایگزین دیگری استفاده شود.
  • در صورتی که از Shader استفاده میکنید حتما از Shader های موبایل استفاده شده باشد و از ساده ترین Shader مورد قبول استفاده شود.
  • در صورتی که از lightning و shadow استفاده می کنید، از کمترین کیفیت قابل قبول استفاده شود
  •  تنظمیات Texture Import Settings بهینه شود. (مثلا همیشه از Compression مناسب استفاده شود)

نتیجه گیری

با توجه به محدودیت مصرف انرژی که در دستگاه های موبایل با آن مواجه هستیم برای کاهش مصرف باتری به طور کلی باید دو عامل را مد نظر داشت.

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

به طور خلاصه هر چه از منابع سیستم کمتر و بهینه تر استفاده کنیم، مصرف باتری بهینه تری نیز خواهیم داشت.

در انتها از شما دعوت می‌کنیم تا تجریبات خودتان را با ما در میان بگذارید و اگر فکر می کنید مواردی بیان نشده است حتما در کامنت ها آنها را با ما به اشتراک بگذارید.

مطالعه بیشتر:

https://www.youtube.com/watch?v=KK2hWczq8ZY&feature=youtu.be

https://www.youtube.com/watch?v=6Ra3ouahAzM

https://unity3d.com/learn/tutorials/topics/performance-optimization/optimizing-scripts-unity-games

https://docs.unity3d.com/Manual/MobileOptimisation.html

https://software.intel.com/en-us/articles/unity-software-performance-optimizations-for-games-best-practices

https://divillysausages.com/2016/01/21/performance-tips-for-unity-2d-mobile/