Когда в игре постоянно создаются и удаляются объекты, производительность начинает падать. Особенно это заметно в проектах с большим количеством пуль, врагов, эффектов и других временных объектов.
Для решения этой проблемы используется Object Pooling — один из самых важных паттернов оптимизации в Unity.
В этой статье разберём, как работает Object Pooling, зачем он нужен и как реализовать собственный пул объектов.
Что такое Object Pooling
Обычно объекты создаются через:
Instantiate(prefab);
А удаляются через:
Destroy(gameObject);
Для небольшого количества объектов это нормально.
Но если игра каждую секунду создаёт десятки или сотни объектов, начинают появляться проблемы:
- лишние выделения памяти
- работа сборщика мусора (GC)
- просадки FPS
- микрофризы
Object Pooling решает эту проблему за счёт повторного использования объектов.
Как работает Object Pool
Вместо создания нового объекта:
- Объект создаётся заранее.
- Отключается.
- Когда нужен — активируется.
- После использования снова отключается.
Получается своеобразный склад готовых объектов.
Пример без пула
Представим систему стрельбы:
Instantiate(bulletPrefab, spawnPoint.position, spawnPoint.rotation);
После попадания:
Destroy(gameObject);
Если игрок выпускает 500–1000 пуль в минуту, производительность начнёт ухудшаться.
Создаём простой пул объектов
Создадим класс пула:
using System.Collections.Generic;
using UnityEngine;
public class ObjectPool : MonoBehaviour
{
public GameObject prefab;
public int poolSize = 20;
private Queue<GameObject> pool = new();
private void Awake()
{
for (int i = 0; i < poolSize; i++)
{
GameObject obj = Instantiate(prefab);
obj.SetActive(false);
pool.Enqueue(obj);
}
}
}
Теперь у нас есть набор заранее созданных объектов.
Получение объекта из пула
Добавим метод:
public GameObject Get()
{
GameObject obj = pool.Dequeue();
obj.SetActive(true);
return obj;
}
Теперь вместо Instantiate():
GameObject bullet = pool.Get();
Возврат объекта в пул
Добавим метод:
public void Return(GameObject obj)
{
obj.SetActive(false);
pool.Enqueue(obj);
}
После использования объект возвращается обратно.
Где применяется Object Pooling
Пул объектов особенно полезен для:
- пуль
- врагов
- частиц
- всплывающего урона
- эффектов взрывов
- временных UI-элементов
Практически любой объект, который часто создаётся и уничтожается, является кандидатом для пула.
Unity ObjectPool
Начиная с новых версий Unity появилась встроенная система пулов.
Пример:
using UnityEngine.Pool;
Создание пула:
private ObjectPool<Bullet> bulletPool;
Инициализация:
bulletPool = new ObjectPool<Bullet>(
CreateBullet,
OnGetBullet,
OnReleaseBullet
);
Для большинства проектов встроенного решения достаточно.
Частые ошибки новичков
Пулить вообще всё
Не каждый объект нуждается в пуле.
Если объект создаётся один раз за игру — пул не нужен.
Забывать сбрасывать состояние
Перед возвратом объекта важно очищать данные:
health = maxHealth;
velocity = Vector3.zero;
Иначе появляются трудноуловимые баги.
Слишком маленький пул
Если объектов не хватает, система может начать создавать новые экземпляры во время игры.
Это сводит пользу пула к минимуму.
Когда использовать Object Pooling
Используйте пулы, если:
- объект создаётся десятки раз в секунду
- игра работает на мобильных устройствах
- появляются GC Alloc и лаги
Практический вывод
Object Pooling — одна из первых оптимизаций, которую стоит освоить каждому Unity-разработчику.
Он позволяет:
- уменьшить количество аллокаций
- сократить работу сборщика мусора
- повысить стабильность FPS
- сделать игру более отзывчивой
Поэтому почти во всех коммерческих проектах используются различные виды пулов объектов.
Заключение
Object Pooling — простой, но крайне эффективный инструмент оптимизации.
Даже небольшая система пулов способна заметно улучшить производительность проекта, особенно на мобильных устройствах и в играх с большим количеством объектов.
Это одна из тех технологий Unity, которую стоит изучить каждому разработчику.