Простейший пул в Unity

в 16:22, , рубрики: C#, unity3d, Программирование, разработка игр, метки: , , ,

Поскольку в Unity операции создания и удаления объектов являются затратными и при их использовании могут появляться микрофризы, по крайней мере, на мобильных устройствах, то желательно создавать объекты заранее и уже потом манипулировать менее дорогостоящими операциями. В данном примере будет описан простейший пул без подгрузки элементов при их нехватке, нехватка компенсируется созданием заранее достаточно большого количества объектов. Таким образом, мы избавляется от микрофризов ценой дольшей загрузки в начале и большего потребления памяти.

Данный пример визуально можно представить так, допустим, что у нас есть стол на котором стоит безразмерная подставка для тарелок, а перед нами кирпичная стена. В начале мы заполняем подставку необходимым количеством тарелок, это будет стек тарелок. Потом мы с определенной периодичностью берем из подставки-стека тарелки по одной с верху и кидаем в стену, при этом разбитые тарелки возвращаются обратно в стек. Пространство между нами и стеной это тоже контейнер. Предположим, что некоторые тарелки мы сбиваем из ружья, следовательно разбиваются и, соответственно, возвращаются они явно не в том порядке, в котором были выпущены. Значит это пространство нельзя реализовать в виде еще одного стека. Здесь нужен контейнер с произвольным доступом, поэтому возьмем List.

Stack<GameObject> plate_stand_pool; //Пул тарелок
List<GameObject> plate_fly_pool; //Пул взятых тарелок

Дальше заполняем пул.

for (int i = 0; i < 100; i++)
{

    plate_stand_pool.Push(Instantiate(plate));
    plate_stand_pool.Peek().SetActive(false); //Можно сразу настроить

}

Там, где нужно берем объект из пула.

plate_fly_pool.Add(plate_stand_pool.Pop());
plate_fly_pool[plate_fly_pool.Count - 1].SetActive(true);

Возвращаем в пул.

for (int i = 0; i < plate_fly_pool.Count; i++)
{

    if (plate_fly_pool[i].transform.position.x > 0.0f)
        {

            plate_stand_pool.Push(plate_fly_pool[i]);
            plate_stand_pool.Peek().SetActive(false);
            plate_fly_pool.RemoveAt(i);

        }

}

Также, если требуется, можно сразу переместить все объекты обратно в стек и очистить лист, вместо удаления элементов листа из цикла.

for (int i = 0; i < plate_fly_pool.Count; i++)
{

    if (plate_fly_pool[i].transform.position.x > 0.0f)
        {

            plate_stand_pool.Push(plate_fly_pool[i]);
            plate_stand_pool.Peek().SetActive(false);

        }

}

plate_fly_pool.Clear();

В данном примере был показан пул без подгрузки элементов при их нехватке. Предполагаю, что ее можно реализовать так: указать минимально необходимый размер при создании стека или вообще его не заполнять, а перед перемещением объекта в лист добавлять один или несколько элементов в стек. Так стек будет постепенно расширяться при необходимости. Также можно сужать размер стека, сравнивая его размер через определенные промежутки времени и удаляя лишние элементы.

Автор: мистер Олимпия

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js