Pull to refresh

Comments 13

При разнообразии моделей врагов, пуль и эффектов в полтысячи, при присутствии в области видимости примерно с сотню выгодно держать полтысячи бассейнов?
Я немного не понял ваш вопрос, вы его перефразируете как-нибудь пожалуйста. Если вы про то стоит ли хранить 500 объектов пула при старте, когда на деле активны в зоне видимости бывает максимум только 100, то нет, это не выгодно. Сделайте пул в 110 объектов(на верняк), или сделайте пул динамически расширяемым, если вы хотите чтобы у вас все было всегда четко впритык.
Я представляю ситуацию так:
* тактика с разнообразием моделей юнитов в 500;
* использующих разнообразие моделей оружия тоже примерно 500, половина пулемёты, любой из которых может на уровень положить, скажем, 200-500 пуль.
* тактическая картина может включать единомоментно порядка 50 моделей юнитов и 50 моделей оружия.
* в кругу визуального контакта 10-100 юнитов, часть из которых применяет своё оружие.
Вот такой вопрос: что вы посоветуете рациональным образом «пулить», в каких количествах?
Используем в своём проекте такую же штуковину. Дело в том, что инстанцирование префаба операция раз в 30 медленнее, чем сменить UV координаты и сделать объект видимым. Поэтому я держу несколько пулов, в каждом лежат обезличенные префабы. Когда надо добавить на экран спрайт из этого атласа из пула вынимается объект, включается в дерево отображения и выставляются координатки для тестуры или какое ещё там поведение на инициализации нужно. Получается штук 5-6 разных бассейнов на игру.

На сцене у меня порой возникает по 2-3 сотни объектов почти одновременно и при этом я забыл про тормоза инстанцирования.

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

То есть вы рекомендуете всё разнообразие пуль и снарядов держать в одном бассеине, и при выстреле заполнять пулю своими индивидуальными баллистическими параметрами? Понял. Спасибо!..

Юниты в игре появляются согласно тактике: захотел — появился, захотел — ушёл.

Простой пример — осень 1943. На сцене доступны Focke Wulf 190 A-6/R2, Focke Wulf 190 A-6/R6, Focke Wulf 190 A-5, Junkers 88 A-4, Junkers 188 E-1, Spitfire 9c, Spitfire LF 9c, Spitfire HF 8c, Mosquito B Mk. 4, Mosquito B Mk. 6 и так далее.

А вообще разнообразие включает, соответственно, Spitfire 1..22, Mosquito 2..18 и так далее. Понятно, что осенью 1943 недоступны Spitfire 14, Spitfire 22, Focke Wulf 190 D-9…

Итого примерно 500 моделей. Ну и порядка 500 моделей оружия для них. Некоторые, вроде 190 A-5 и 190 A-6 настолько мало различимы визуально, что могут при жадности представляться одной графмоделью.

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

А дальше получается что-то вроде:
var item = poolController.Get(PrefabName);
item.decorate(imgDescription);

Пришёл к такой схеме потому что оказалось, что переключится с атласа на атлас спрайту почти так же быстро. В первой версии заводил по бассейну под каждый атлас. Думаю с юнитами у вас проканает примерно такой же подход.

А ещё я реализовал полезную штуку — что когда если в кадре к пулингМенеджеру не обращались, он про запас создаёт по одному префаб, пока их сотня в резерве не накопится.
Взял к размышлениям.
Спасибо!
Читал про пулы, код немного не тот который я люблю.
Сделал свой, но использую Queue и операции добавить и изъять. Это избавило меня от индексов и контроля наличия элементов по ним.

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

Очень хорошо про оптимизацию рассказано на курсе 2D и 3D игр на MVA.
Если кто пожелает, переведите для читателей статью:
Unity3D Best Practices

PS меня немного раздражает то что по правилам Unity (из инструкции) нельзя использовать конструкторы классов (те которые наследуются от MonoBehaviour) и студия ругается на методы вроде Update() которые никто не вызывает, переменные которые якобы нигде не инициализируются (это надо делать в методе Start()) и т.д., эти предупреждения в коде от которых хотелось бы избавиться не трогая настройки VS. Плагин для работы с Unity3D почему то этого не делает. Видел ли кто переделанные правила проверки кода от Microsoft переделанные для Unity?
Да вы правы во всем, что написали, спасибо за информацию, я старался предложить наиболее прозрачный для понимания вариант, про второй вопрос не могу ничего ответить, потому что не знаю. Спасибо за ссылки и развернутый комментарий!
При реализации пулов сталкивался с такой проблемой, что при деактивации анимированного объекта, его аниматор (в моей ситуации — анимация смерти, т.е. полного исчезновения объекта) не откатывалась, из-за чего пришлось вводить довольно костыльную штуку, что я сначала отключаю у объекта его рендеринг, откатываю анимацию (что в Юнити тоже не очень просто, ибо для этого нужно запустить анимацию на один кадр и остановить), а затем уже деактивирую сам GameObject. Не находили ли вы решения этой проблемы?

PS: а вообще, пулинг объектов — это крайне полезная вещь. Например, в моём проекте используется сборка уровня из отдельных блоков (похоже на МайнКрафт, только кубики значительно больше), причём беспрерывно: часть уровня за спиной уничтожается, а перед игроком собирается вновь. В итоге, на сцене постоянно присутствует около четырёх—пяти сотен 3D-объектов, задействованных при расчёте физики; благодаря динамическому батчину и пулингу всего, что только можно — игра с включённым попиксельным (forward) рендерингом не лагает на Андроид-устройстве 2012-го года.
Возможно решение с анимацией лежит где-то около параметра «Has exit time» в аниматоре. Или можно сделать запуск анимации смерти по булевому значению, то есть как происходит смерть -> параметр_умер=true -> анимация проигрывается -> деактивация -> при активации параметр_умер=false(стрелочку в аниматоре направить при false на default state анимацию ).Попробуйте так как-нибудь.
missleRed[i].transform.eulerAngles = Caller.transform.eulerAngles;

Не используйте так eulerAngles, юнити все повороты хранит в кватернионах, когда вы вызываете eulerAngles на самом деле происходит следующее:

public Vector3 eulerAngles
{
    get
    {
        return this.rotation.eulerAngles;
    }
    set
    {
        this.rotation = Quaternion.Euler(value);
    }
}

То есть в вашем примере вы сначала конвертируете кватернион в вектор, а потом обратно. На большом количестве объектов у вас будет падение производительности и лишний мусор в памяти — не очень хорошая вещь для пула.

missleRed[i].GetComponent<DisableObject>().StartCoroutine("AblePause");

Запускать корутины по строке — плохая практика, если вы переименуете метод, то у вас где-то в другом месте что-то сломается, и вы об этом не скоро узнаете. И лучше спрятать корутину внутри класса DisableObject, а наружу отдать метод, который её сам запускает, тогда контроль над корутиной останется у класса.

float randomTime = Random.Range(cooldownMin, cooldownMax + 1);

А зачем вы добавляете единицу?
Спасибо за эту ценную информацию, приму к сведению и применю.
Насчет единицы — убрал. У меня это была заглушка своеобразная, на случай если я забуду поставить параметры cooldownMin и cooldownMax, там корутина начинала с ума сходить и запускать снаряды каждый нуль секунд и профукивать весь пул, если так можно выразиться, поэтому это самозащита от своего склероза.
Sign up to leave a comment.

Articles