Object Pooling для мобільної гри: реалізація та оптимізація

Просадки на піках бою та підвисання при масових ефектах б'ють по утриманню гравців. Ми впроваджуємо пул об'єктів у Unity під ключ: знаходимо джерела навантаження, налаштовуємо перевикористання об'єктів і закріплюємо результат вимірами. Ваша гра тримає рівний темп на слабких пристроях.

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Object Pooling для мобільної гри: реалізація та оптимізація
Середній
від 1 дня до 3 днів
Часті запитання

Чому пул об'єктів в Unity вирішує проблему просідань

Постійні Instantiate та Destroy в ігровому циклі — одна з найдорожчих звичок у проєкті. Кожен виклик створює новий керований об'єкт у купі, а знищення залишає по собі сміття, яке збирач рано чи пізно має прибрати.

Поки об'єктів десятки, це непомітно; на кулях, частинках, ворогах і спливаючих підказках рахунок іде на сотні за секунду.

Проблема проявляється не в середній продуктивності, а в піках часу кадру. Збирання сміття запускається не тоді, коли зручно, а коли купа заповнилася, — і зупиняє потік на час, який залежить від обсягу живих об'єктів.

Гравець бачить це як ривок: керування «залипає», анімація смикається, влучання не зараховується. На слабких пристроях, де пам'яті мало, збирач викликається частіше, і просідання fps стають регулярними.

Пул об'єктів перевертає логіку: об'єкти створюються один раз на старті сцени і далі не знищуються, а перевикористовуються. Коли куля влучає в ціль, вона не видаляється, а повертається в пул і скидає стан — позицію, швидкість, таймери, посилання на ефекти.

При наступному пострілі береться вже готовий екземпляр, і в купі не з'являється жодного нового об'єкта.

Практичний ефект — рівний кадр замість пилкоподібного графіка. Збирач перестає запускатися в розпал бою, бо сміття не виробляється; час кадру тримається в передбачуваному коридорі, а не підскакує на піках.

Пул об'єктів в Unity особливо важливий для сцен з щільним потоком короткоживучих сутностей: кулі, гільзи, іскри, спливаючі числа шкоди, вороги з хвиль.

Є й друга вигода — керована пам'ять. Розмір пулу задається заздалегідь і зростає за зрозумілим правилом, а не хаотично під навантаженням. Це дозволяє тримати стабільний бюджет пам'яті на пристрої і не впиратися в ліміт у найневдаліший момент. Розбираємо, як такий пул спроєктувати, щоб він не перетворився на джерело нових проблем.

Що дає оптимізація пулу об'єктів у мобільній грі

Пулінг прибирає головне джерело нестабільності кадру — постійні виділення та звільнення об'єктів у рантаймі.

Коли снаряди, вороги та ефекти перевикористовуються із заздалегідь створеного набору, процесор перестає витрачати час на резервування пам'яті в розпал бою, і час кадру тримається рівним замість пилкоподібного графіка.

Саме на слабких пристроях, де запас за навантаженням на процесор мінімальний, ця різниця видна найсильніше: гра не «клює» на масових сценах.

Другий ефект — передбачуване споживання пам'яті. Пул фіксує верхню межу живих об'єктів, тому збирач сміття не отримує сплесків і не запускається в найневдаліший момент.

Довгі паузи, через які кадр провалюється і керування «залипає», відходять у минуле — залишаються короткі фонові проходи, непомітні гравцеві.

Окрема вигода — керований клас відмов. Коли ліміт пулу вичерпано, поведінка задається явно: об'єкт перевикористовується за пріоритетом, ставиться в чергу або вимикається.

Це краще, ніж неконтрольоване зростання пам'яті та падіння через нестачу ресурсів, яке неможливо ні передбачити, ні відтворити на стенді.

Нарешті, скорочується час відновлення після збою. Пул можна скинути в початковий стан однією операцією, повернувши всі об'єкти в набір, — сцена приходить у робочий стан без повного перезавантаження рівня.

Для команд це ще й стабільний fps на всьому парку пристроїв, а не лише на топових моделях, де проблеми маскуються запасом потужності.

Підходи до організації пулу: порівняння варіантів

Вибір між ручним пулом, вбудованими засобами рушія та сторонніми бібліотеками — це вибір між контролем, швидкістю впровадження та обсягом підтримки. Нижче — порівняння за придатністю та обмеженнями, а не «що краще взагалі».

Варіант Коли підходить Обмеження
Ручний пул Неоднорідні об'єкти, складна логіка повторного використання, вимоги до детермінованої поведінки Потрібно самим закрити повернення об'єктів, скидання стану та захист від подвійного повернення
Вбудований пул Однотипні часто створювані об'єкти: снаряди, ефекти, спливаючі підказки Обмежена гнучкість політик; частина сценаріїв все одно потребує обв'язки
Сторонні бібліотеки Швидкий старт, типові сценарії, готові політики розширення Залежність від зовнішнього коду, власний життєвий цикл, ризик конфлікту з оновленнями рушія

Управління життєвим циклом

Ключова відмінність — хто відповідає за повернення об'єкта в пул. У ручному варіанті це робить викликаючий код, і тут з'являються типові дефекти: об'єкт повернули двічі, повернули чужому власнику або не повернули взагалі після винятку.

Вбудовані та бібліотечні рішення знімають частину цього навантаження, але вимагають явного скидання стану при видачі — інакше об'єкт приходить із залишками попереднього використання.

Обмеження на масштабі

Ручний пул передбачуваний, але дорожчий у підтримці при зростанні числа типів об'єктів. Вбудований — швидкий, поки сценарій однотипний. Сторонній — зручний на старті, але додає зовнішню залежність у життєвий цикл проєкту.

На практиці часто комбінують: вбудований пул для масових однотипних об'єктів, ручний — там, де потрібна своя політика скидання та обліку.

Опишіть, які об'єкти плодяться у вашій грі та як часто, — повернемося з оцінкою та планом по кожному варіанту.

Як ми впроваджуємо пул об'єктів: етапи роботи

Робота починається не з коду, а з вимірювання: поки немає цифр щодо алокацій, будь-яка оптимізація — це вгадування.

Ми знімаємо профіль на реальних сценаріях гри — бій, перехід між рівнями, масовий спавн противників — і знаходимо джерела сміття, яке тригерить збирання і просаджує кадри.

  1. Аудит алокацій. Проганяємо профілювальник пам'яті на цільових пристроях, фіксуємо частоту збирань сміття, піки споживання та кадри, де просадка помітна гравцю. На виході — список об'єктів-кандидатів: кулі, вороги, ефекти частинок, спливаючі підказки, звукові джерела.

  2. Проєктування схеми пулу. Визначаємо, що перевикористовуємо, а що дешевше створювати заново. Задаємо стартовий розмір пулу, межу зростання та поведінку при вичерпанні: розширюватися, чекати на звільнення або відкидати запит. Тут же вирішуємо, як об'єкт повертається в пул — вручну або автоматично за подією.

  3. Реалізація та інтеграція. Пишемо пул під архітектуру проєкту, а не поверх неї: фабрика створення, скидання стану об'єкта перед видачею, єдина точка повернення. Прибираємо прямі виклики створення та видалення по коду, щоб об'єкти не «тікали» повз пул.

  4. Налаштування під сценарії. Підбираємо розміри пулів окремо для кожного типу об'єктів і рівня навантаження, налаштовуємо прогрів на етапі завантаження, щоб перший сплеск активності не викликав лавину створення об'єктів.

  5. Перевірка результату. Повторюємо вимірювання на тих самих сценаріях і пристроях: порівнюємо частоту збирань сміття, стабільність кадрів і споживання пам'яті до і після. Окремо перевіряємо граничні випадки — переповнення пулу, одночасне повернення об'єктів, перезапуск рівня.

  6. Передача та документація. Віддаємо налаштовану систему, схему пулів з параметрами, інструкцію щодо додавання нових типів об'єктів і чек-ліст перевірки при змінах у грі.

Процес ітеративний: якщо після впровадження профіль показує нове джерело алокацій, повертаємося на крок аудиту. Опишіть вашу гру та поточні просадки — повернемося з оцінкою та планом робіт.

Що отримує замовник після оптимізації пулу об'єктів

Пулінг об'єктів — це не одноразова правка в коді, а частина архітектури рантайму, яку далі супроводжує команда. Тому після оптимізації замовник отримує не «стало швидше», а набір артефактів, за якими систему можна розвивати й передавати без втрати контексту.

  • Конфігурації пулу — винесені з коду параметри: стартовий і максимальний розмір, крок зростання, політика передзаповнення на старті сцени, прив'язка до типів об'єктів. Значення змінюються без перезбирання, під різні сцени та режими навантаження.
  • Схеми життєвого циклу — діаграми станів об'єкта: створення, видача з пулу, використання, повернення, скидання стану, знищення при переповненні. Видно, де об'єкт може «втекти» й не повернутися.
  • Політики доступу — правила, хто і коли бере об'єкт з пулу, що відбувається при вичерпанні вільних, як обробляється повторне повернення та звернення до вже звільненого об'єкта.
  • Регламенти скидання стану — що саме обнуляється при поверненні: трансформи, матеріали, підписки на події, таймери, посилання на інші об'єкти. Без цього пул віддає «брудні» екземпляри.
  • Інструменти діагностики — лічильники активних і вільних об'єктів, пікові значення, лог промахів пулу, коли запит іде на створення нового екземпляра замість перевикористання.
  • Документація — опис архітектури пулу, точок розширення під нові типи об'єктів, відомих обмежень і порядку додавання сутностей у систему.
  • Регламенти супроводу — як змінювати розміри пулу при зростанні навантаження, як перевіряти відсутність утечок перед релізом, які метрики дивитися в першу чергу.

Такий комплект знімає залежність від конкретного розробника: пул залишається керованим, а не «магією», яку бояться чіпати. Опишіть вашу задачу — повернемося з оцінкою та планом робіт.

Кейс: як пул об'єктів прибрав просідання в мобільній грі

Проєкт — казуальна аркада з хвилями ворогів і снарядами, які створювалися й знищувалися десятками за секунду.

На середніх пристроях це давало регулярні провали часу кадру: збирач сміття запускався по кілька разів за бій і «з'їдав» кадри пачками, а на слабких моделях гра помітно смикалася саме в найдинамічніші моменти.

Що змінили

Перевели снаряди, ворогів, ефекти влучання та спливаючі числа шкоди на пул об'єктів. Екземпляри створюються один раз під час завантаження рівня, далі лише беруться з пулу й повертаються назад із повним скиданням стану — позиція, швидкість, таймери, посилання на компоненти.

Окремо закрили витік: об'єкт, повернутий у пул, знімає підписки на події та перестає тікати в оновленні кадру.

Метрики до і після

Показник До пулу Після пулу
Піки збирача сміття за бій 8–12 1–2
Просідання часу кадру регулярні, до 3× від норми поодинокі, у межах норми
Частка кадрів нижче цільового порогу помітна близька до нуля
Стабільність на слабких пристроях смикання в бою рівний хід

Ключовий ефект — не середній кадр, а саме хвіст розподілу: зникли рідкісні, але дуже довгі кадри, які гравець відчуває як «залипання». Їх прибрав не сам пул, а те, що він зняв навантаження з Unity щодо управління пам'яттю в гарячому циклі.

Окремо перевірили, що пул не росте нескінченно: задали верхню межу на кожен тип і політику розширення при вичерпанні. Якщо об'єкт повернувся в пул із незакритим станом — це ловиться в тестовому прогоні, а не в релізі.

Такий підхід ми застосовуємо і в інших проєктах: спочатку профілюємо реальний бій, потім оптимізуємо те, що справді гріє кадр.

Чим пул об'єктів відрізняється від звичайного створення екземплярів?

Створення екземпляра — це не одна операція, а ланцюжок: виділення блоку в керованій купі, ініціалізація полів, реєстрація в структурах движка.

Коли таке відбувається десятки разів за секунду — на постріли, частинки, спливаючі числа шкоди — купа фрагментується, а збирач сміття виходить на сцену в найневдаліший момент. Пул перевертає логіку: об'єкти створюються один раз на старті рівня і далі лише перемикають стан.

Різниця проявляється в характері навантаження. При звичайному створенні алокація пам'яті зростає разом із темпом гри: чим інтенсивніший бій, тим частіше збирач зупиняє кадр, і піки просідань припадають рівно на найдинамічніші моменти.

Пул розриває цей зв'язок — пам'ять виділяється заздалегідь і фіксованим обсягом, а в рантаймі об'єкт лише отримує прапорець «активний» і початкові параметри. Купа перестає зростати, збирач не отримує приводу для позапланового проходу.

Повторне використання вимагає дисципліни, якої немає при звичайному створенні. Об'єкт повертається в пул не «як є», а приведеним до початкового стану: скинуті таймери, обнулені посилання на зовнішні дані, зупинені анімації та корутини.

Якщо цього не зробити, наступний «постріл» успадкує чужий стан — звідси класичні баги із застряглими ефектами та об'єктами, які не зникають. Тому повернення в пул — така сама явна операція, як і вилучення, а не побічний ефект видалення.

За продуктивністю порівняння не на користь постійного створення навіть на слабких пристроях. Пул прибирає не лише алокацію, а й супутню роботу: пошук вільного місця в купі, оновлення посилань, подальше прибирання.

Час кадру стає передбачуваним — замість рідкісних, але глибоких просідань отримуємо рівний графік. Для гравця це різниця між «іноді смикається» та «йде гладко на всьому протязі рівня».

Є й ціна: пул тримає пам'ять зайнятою постійно, навіть коли об'єкти не потрібні. Тому розмір підбирають за піковим навантаженням сцени, а не «із запасом на всякий випадок» — інакше виграш у продуктивності обмінюється на зайву витрату. Грамотна реалізація — це баланс між зарезервованим обсягом і реальним піком активності.

Часті технічні сумніви щодо пулу об'єктів

Пулінг вбудовується в уже працюючий проєкт без переписування ігрової логіки: змінюється не поведінка об'єктів, а спосіб їх отримання та повернення.

Якщо гра вже зібрана й випущена, починаємо з одного класу — снарядів, ворогів або частинок, — де найчастіше просідає частота кадрів, і лише після заміру переносимо решту.

Сумісність із поточною архітектурою перевіряємо на цій самій ділянці: пул не конфліктує з наявними системами сцени, а за потреби обгортає їх.

Складність впровадження залежить від того, наскільки розкидане створення об'єктів по коду. Коли Instantiate викликається в десятках місць, спочатку зводимо їх до єдиної точки через фабрику — це і є основна робота, а сам пул додається поверх.

Ризик на цьому етапі один: забути повернути об'єкт у пул, через що він «залипає» активним. Закриваємо це скиданням стану при видачі та перевіркою в тестах, а не надією на дисципліну розробника.

Чи можна впровадити пул, якщо проєкт уже розгорнуто і в релізі?

Так, і це типовий сценарій. Пулінг не потребує зупинки розробки або перезбирання архітектури — ділянка переводиться на пул інкрементально, по одному типу об'єктів, з перевіркою на кожному кроці.

Якщо щось іде не так, відкат локальний: повертаємо попередній виклик створення для конкретного класу, решта гри не зачіпається.

Чи не зламає пул наявну логіку об'єктів?

Пул змінює лише момент створення та повторного використання, але не поведінку. Кожен об'єкт при видачі отримує скинутий стан — позицію, швидкість, таймери, посилання, — тому логіка бачить його як новий.

Ризик виникає, якщо об'єкт зберігає дані між життями; такі поля виносимо в явне скидання і покриваємо перевіркою.

Наскільки це складно, якщо створення об'єктів розкидане по коду?

Це найтрудомісткіша частина, і її варто робити поступово. Спочатку знаходимо всі точки створення потрібного типу, зводимо їх до одного інтерфейсу отримання, і лише потім підключаємо пул.

Так інтеграція не перетворюється на великий переписувальний коміт, а йде ділянками з зрозумілим результатом на кожній.

Обговоримо ваше завдання з оптимізації пулу об'єктів

Розкажіть, що вже є: рушій і версія, жанр, на якій стадії проєкт — прототип, бета чи реліз з оновленнями. Якщо пул уже реалізовано, але він поводиться нестабільно, корисно знати, як він влаштований зараз: де створюються об'єкти, хто повертає їх у пул, чи є розподіл за типами. Цього достатньо, щоб зрозуміти клас задачі та запропонувати рішення з оптимізації.

Object pooling в Unity майже завжди впирається не в сам пул, а в те, як об'єкти з нього виходять і повертаються. Ми дивимося на життєвий цикл об'єктів, на моменти пікових навантажень і на те, що відбувається під час перезавантаження сцени. Далі — оцінка та план: які зміни дадуть ефект одразу, а які потребують переробки архітектури.

  • Розбір поточної реалізації пулу та точок зростання навантаження
  • Оцінка обсягу робіт і ризиків за кожним сценарієм
  • План поетапної оптимізації без зупинки розробки
  • Рекомендації щодо структури пулу під ваш жанр і профіль гри
  • Варіанти інтеграції з наявним кодом і системами сцени
  • Критерії, за якими будемо вимірювати результат після впровадження

Опишіть задачу у вільній формі — що турбує, які метрики просідають, що вже пробували. Повернемося з оцінкою та планом, де буде видно, які кроки дають який ефект і в якому порядку їх має сенс робити.

Наші компетенції:

Останні роботи

  • Розробка мобільного додатка для компанії FEEDME
    Розробка мобільного додатка для компанії FEEDME
    1009
  • Розробка мобільного додатку для компанії XOOMER
    Розробка мобільного додатку для компанії XOOMER
    902
  • Розробка мобільного додатку для компанії RHL
    Розробка мобільного додатку для компанії RHL
    1331
  • Розробка мобільного додатку для компанії ZIPPY
    Розробка мобільного додатку для компанії ZIPPY
    1179
  • Розробка мобільного додатку для компанії Affhome
    Розробка мобільного додатку для компанії Affhome
    1106
  • Розробка мобільного додатку для компанії FLAVORS
    Розробка мобільного додатку для компанії FLAVORS
    713