Оптимизация. Пул объектов (Objects Pool). Рассказываю на примерах в Unity3d
Вставка
- Опубліковано 28 лют 2021
- Поддержи канал, бро!
paypal.me/gamedevlavka - мир
boosty.to/gamedevlavka - рф
И даже криптой (пока только Ethereum):
0x7a53325D1C36Eea7BbE8C6a8D00f2a0efd580e77
Урок по Unity, в котором я рассказываю про один из приемов оптимизации - пул объектов (Objects Pool). Прием, который позволяет сократить количество Instantiate для объектов с короткой продолжительностью "жизни". Что в последствии благоприятно влияет на производительность.
Плюс, этот урок является отличным примером к предыдущему уроку о Generic классах в C#:
• Generic классы в C#. Р...
Подписуйся на канал в телеге, или на твиттер, там я публикую коротенькие типсы и практики, которые помогут писать код лучше, понятнее и эффективнее:
Telegram: t.me/gamedevlavka
Twitter: / gamedevlavka
Спасибо! Очень хороший и понятный пример пула объектов!
Супер! Спасибо за труд!
Спасибо тебе и твоему ObjectPool. Вы мне очень помогли
Делай дальше. Ролики отличные. Вечером попробую
Хорошо показан пример. Отличный ролик.
Спасибо! Очень понятно
Привет!
Комментарий поддержки)
Очень интересные видео)
Не останавливайся)
Привет! Спасибо за поддержку)
Спасибо за видео!
Отлично, 😉 спасибо 👍
То что нужно, спасибо
Начала писать свой пул с этого видео, потом пошла на другие, и в итоге все равно вернулась сюда, потому что здесь все намного понятнее. И есть хорошая возможность перестроить под себя то, что нужно, без излишних напряжений извилин)
Спасибо большое! Это видео сильно упростило мне жизнь)
Спасибо, наверное лучший Pool который я видел на UA-cam, и на Unity Learn.
Сейчас по рандому смотрю твои видосики, хоч сказать что мне старые больше нравиться...
В новых видосиков ты столько создаешь интерфейсов :c
Шо просто путаешься, а здесь 1 скрипт и Pool готов!
пасиб большое
Спасибо!
Отличный вариант, чтобы делать снаряды выстрелов и другие эффекты
По сути, просто на сцене заранее есть объекты, либо создаются 1 раз при старте, и потом включаются или выключаются имитируя создание и разрушение, глобально это не увеличивает производительность но избавляет от ненужных фризов на любой платформе , кроме того пул можно расширить разными объектами, и вообще какой-то иерархией с типами
Видео классное. Одно замечание важное для следующих видео: null - это не ноль;
очень полезные видео у тебя и понятно объясняешь, спасибо большое! подписка и лайк однозначно!
было бы здорово, если бы ты снял видео о паттерне фабрика)
Да, надо заняться и этой темой)
@@gamedevlavka спасибо 🤗
Это просто великолепно!
Почему здесь так мало подписчиков?
Потому что канал еще молодой. Но ты можешь помочь ему, поделившись роликом в соц. сетях :)
хз как сломать эту кнопку лайка
пул хороший, но медленный - O(n). потому как каждый раз в цикле ищет свободный элемент. если ввести индекс на текущую позицию в пуле, то отпадёт необходимость в цикле. и сложность алгоритма будет уже O(1). а это уже значительно веселее, т.к. скорость работы пула уже не будет зависеть от количества данных в нём.
@@sutr4531 отличное предложение
Классные видео! Удачный выбор ли в пользу массива типа List? Он имеет capacity и выделяет под него достаточно памяти, при большом количестве обьектов рациональнее, использовать Stack - при большем количестве и вытягивать от туда , ну или Linked List , но при обращении по индексу, сложность - линейная , но тут это не используется, Object Pull сам выпрашивает фабрику - это как бы входная точка для создания и вытягивания фабрик😀
👍👍👍
думаю включать элемент в HasElement() не очень логично, т.к. исходя из названия метода мы ожидаем получить ссылку на объект/либо нуль, а вовсе не проихводить с ним какие то действия (включение). Логичнее включать его в GetElement(), где уже логика подразумевает доставание/создание объекта и его активацию (в случае создания - флагом).
Полностью согласен, так не надо делать!
Отличные видео, спасибо! Но вопрос, зачем ты используешь " this" там где это не обязательно? привычка?
Супер! Спасибо за труд!
Вопрос. В методе CreateCube сначала создается обьект на сцене, а потом меняется его позиция, верно?
Объект не создаётся, он включается. Создаётся он при создании пула, то есть в старте. Да, он включается на сцене и затем меняется его позиция
Что делать, если скрипт (L10 Pool Example) отказывается принимать префаб?
Привет , для чего мы создали 2 конструктора PoolMono?
Чет я не понимаю, зачем использовать generic class в юнити, ведь все объекты на сцене имеют 1 тип GameObject.
привет, хорошее видео, но есть пару вопросов по СОЛИДности метода HasFreeElement он всё таки выглядит печально, так как имеет больше одной ответствнности, лучше его разделить, и out нас полностью обязывает использовать этот функционал
Привет! СОЛИДность в плане единой ответственности предназначается для классов, а не для методов. Да, соглашусь, что принцип нужно соблюдать и в методах, по-хорошему. Но бывает, что метод выполняет не одно действие, и HasFreeElement() не единственный такой случай. В таких случаях мы либо делаем соответствующее название метода (чтобы было понятно, что делается внутри), либо, как в моем случае, мы можем использовать обязательный вывод наружу через out. Таким образом, если элемент есть он сразу попадает к нам в руки.
Таким же способом устроен например Physics.Raycast() - внутренний метод Unity, где через out выводятся данные о попадании рейкаста, если таковое имеется.
Видео очень хорошее, для уровня уже выше начинающего, но вот вопрос что делать если разный префа и в разное время, стоит создать просто 2ва пула или уже в самом пуле менять
Построить иерархию, и управлять ей, например есть главный объект пул, внутри 4 объекта (4 типа), и в каждом типе группа своих объектов, через главный пул можно манипулировать всеми ветками по первому принципу Solid, если кроме как по типу, будут другие сортировщики, то тогда всё-ровно нету смысла создавать доп классы, достаточно сделать грамотный поиск внутри пула
Классный ролик! По Вашим видео изучаю Unity и C#. Имя пользователя - это Ваша мечта?)
Все верно)
Спасибо за видео, очень хорошая подача и материал, но подскажи пожалуйста: Почему prefab типа L10Cube, и когда в инспекторе вы его перетягиваете в Тестер - он тоже забирает только элемент L10Cube, но пул спавнит его вместе с 3D телом куба, как префаб ведь указан только скрипт
Привет, если нашел ответ на свой вопрос, скинь пожалуйста ссылку на ответ, или в каком направлении копать
А как ты заспавнишь один скрипт без объекта ? ))) это просто ссылка на объект с компонентом L10Cube. не было бы этого скрипта, не перетянул бы
@@Toki- внутри этого скрипта есть методы, которые управляют кубом, в конце показал он
С таким пулом могут быть проблемы.. например, я использую этот пул для пуль/ракет или т.п.
Снаряд, при попадании в коллайдер игрока должен отключиться и нанести урон.
Вот в чем ошибка: если игрок не двигается, то снаряд, который ранее в него попал и отключился снова берётся из пула и активируется там же, где все ещё стоит игрок. И событие OnTrigerEnter срабатывает ДО того как мы переместили снаряд в нужное место. Потому что он активируется сразу как берётся из пула, а перемещается в нужное место после активации
Хорошее замечание. Для такого случая можно дописать в пул дополнительный метод GetFreeElement с параметром Position. То есть по сути расширить его поведение для ваших целей.
Пул используют только для слабых телефонов? Для ПК не обязательно?
@@IgorKu-m4o их использование рекомендуется везде. Лаг может происходить и на ПК, он просто меньше будет.
Изменить порядок действий легко, это даже проблемой не назвать, кроме того можно просто хранить статичный класс с булевой которая отвечает за активность, а в тригере проверять активен он или нет, в таком случае первые условно 2 вызова ничего не успеют сделать т.к активен он станет после перемещения
Все круто и понятно, одно не понял, как происходит, что в проверке на 59 сточке , при вызове метода HasFree, возвращается елемент , тогда как он возващает bool. Просто не могу врубиться, если не трудно может кто то обьяснит в кратце
Все догнал) , коммент для продвижения)
касательно кубика, кто новичок, вместо корутин, установите себе unitask библиотеку
это гораздо удобнее, смотрите как у меня это выглядит, поверьте, вы везде будете это юзать
это в библиотеки
using UnityEngine;
using System;
using Cysharp.Threading.Tasks;
это в ваш класс
[SerializeField] private float _lifetime;
void OnEnable() { Destroy(); }
async void Destroy()
{
await UniTask.Delay(TimeSpan.FromSeconds(_lifetime));
this.Deactivate();
}
public void Deactivate()
{
this.gameObject.SetActive(false);
}
Здравствуйте, я новичок в Unity3D поэтому хотел бы узнать как сделать так чтобы добавлять не один объект а несколько объектов и вызывать их рандомна, спасибо за раннее за ответ.
Привет, если ты новенький в юнити то лучше не спеши с такими темами, это более продвинутый левел, только зря время потратишь.
Интересно мы после смерти обратно в пул попадаем или в сборщик мусора
Хороший ролик, но это пул через list, есть ли более быстрые реализации (драсти оптимизация)). Я как-то натыкался на pool через queue.
Есть загвоздка, ты не можешь пробежаться по Queue, чтобы найти неактивный элемент. Поэтому очередь не совсем подходит под большинство задач, связанных с пулом)
@@gamedevlavka а есть вообще варианты кроме списков?
@@PS-vj6jz список самый оптимальный, он быстрый, он динамический, и его достаточно. Лучше не получится, с тем функционалом, что представлен в видео
@@gamedevlavka окей.
@@PS-vj6jz List это по сути копирование массива в новый, и "удаление" предыдущего, максимально оптимально это использовать 1 массив за всю жизнь который выделит фиксированное количество памяти, а для этого надо с 100% уверенностью установить лимиты по количеству объектов
Для чего/Почему везде пишешь this - где это необязательно?)
Ответ на этот вопрос здесь => t.me/gamedevlavka/15
@@gamedevlavka но ведь для того чтобы отличать поля от локальных переменных, придумали называть поля с _, и вместо this.feild писать _feild и так и так понятно, что речь идёт о поле, а не переменной, но с подчеркиванием быстрее, и меньше раздуваются строки
@@leningradetsfromshusharsta985 это касается не только полей, но и методов. Вообще это индивидуальный подход, я ничего не имею против _ в общей практике.
Это больше для себя. Мне так читать удобнее, и пишу я this быстрее, чем ставлю _.
Зачем создавать 2 конструктора для PoolMono если можно по дефолту для контейнера поставить значение null?
public PoolMono(T prefab, int count, Transform container = null) {
this.container = container;
}
Потому что он может быть не null, но если не указан то будет null
@@neverworld8815 ну если укажешь то уже не будет null, в противном по дефолту подставится null
@@dmytromahas9207 я то-же самое сказал, только короче
@@neverworld8815 ахахах, так зачем 2 конструктора ??
@@dmytromahas9207 я уже ответил
а зачем два конструктора
охерел, что так вообще бывает
у нас, у HTML-программистов, все не так
Почему свойства именуются с маленькой буквы? Свойства принято именовать с большой, а поля с маленькой.
В типовом коде Юнити тоже с маленькой 🤔
Есть разные конвенции и стили написания кода. То, что Майкрософт так рекомендует - не значит, что это удобно всему миру. Юнити решили, что будут использовать camelCase для публичных полей и свойств, а я решил, что не хочу, чтобы мой стиль отличается от стиля юнити. Такие дела)
Это по сути косметика, в некоторых командах разработчиков могут быть свои собственные знаки или ключевые слова для удобства