Как сделать бафы, дебафы, статусы или эффекты в Unity

  Рет қаралды 7,403

Лавка Разработчика

Лавка Разработчика

Күн бұрын

Пікірлер: 43
@nepochat
@nepochat Жыл бұрын
Спасибо Андрей, то, что надо)
@neosinpocket4184
@neosinpocket4184 Жыл бұрын
без сомнений один из самых нормальных каналов по юнити!!! было бы очень круто увидеть видео с DI и Zenject как его частный случай, а то инфы очень мало (ну или я тупой)
@Veles017
@Veles017 11 ай бұрын
Полностью солидарен!
@goshacar2273
@goshacar2273 Жыл бұрын
По итогам видоса возникли несколько вопросов: 1) Меня всегда учили, что если объект обладает неким поведением, то используем интерфейс. Если же объект в сущности своей является тем, от чего наследуется - используем абстрактный класс. Так вот не лучше ли вместо интерфейса IBuff использовать некий абстрактный класс Buff и от него наследовать? Так же туда можно завернуть свойства типа lifeTime, Type (Buff, Debuff) и т.д. 2) На сколько удобно/затратно постоянно пересчитывать каждый раз ВСЕ баффы? Не лучше ли считать один, тот который добавляем? 3) Как правильно связать бафы с интерфейсом? В большинстве игр при появлении бафа мы получаем об этом визуальное уведомление (ну например иконка бафа над персонажем). Как это лучше реализовать? P.s. я джун, на какое-то экспертное мнение не претендую
@gamedevlavka
@gamedevlavka Жыл бұрын
Отличные вопросы! 1. Сложный вопрос, потому что ответ зависит от требований. IBuff можно (и лучше) сделать генериком, чтобы совсем не зависеть от типа статов. Лайфтайм я бы вынес в родительский класс только если баффы живут между игровыми сессиями, иначе зачем там лайфтайм, ну и если необходимо свойство Buff/debuff - тоже в целом оправданно. Тут смотрите по требованиям, что лучше применить. Интерфейсы - не жестко педолируемая идея в этом видео) 2. Ни на сколько. Мы работаем с типом данных - значение, то есть мы даже не аллоцируем память (ну немножк через форыч, но там совсем крошки, см. далее). И второе, баф или дебаф - это не перманентновыполняемый код, он случается не каждый кадр (хотя даже в этом случае нагрузки бы не было). В общем за скорость работы не переживай. 3. Логика приложения делится на разные слои. И вот этот код, который я писал в CharacterView для тестов - он должен быть в бизнес логике (тут уже не смогу расписать подробно). Назовем его CharacterStatsService, и вот туда мы командуем CharacterStatsService.AddBuff(character, buff), а этот сервис имеет уведомлялку Action OnCharacterBuffed например, и сюда уже можно UI подвязывать. Это непростая тема, чтобы залететь с двух ног, но можно просто в Character, где у тебя AddBuff(IBuff) тоже ивент сделать и подписаться на персонажа.
@devilbob
@devilbob Жыл бұрын
Вроде смотрится здраво, но сильно не хватает, чтобы структура CharacterStats была у персонажа генериком. Из этого следует вопрос: Я бы при генерик реализации внутри баффов проверял *if (playerStats is CorrectPlayerStats)* и только при успешном касте продолжал работу. Есть ли более элегантная система или я +- правильно мыслю? Я неособо люблю касты, но иногда другие решения мне кажутся лишь более громоздкими.
@gamedevlavka
@gamedevlavka Жыл бұрын
Да, вопрос хороший, я в другом комменте уже ответил, что еще лучше сделать IBuff генериком, баффы все равно привязываются к конкретным статам, а вот интерфейс лучше сделать чем-то вроде IBuff where T : IStats, а конкретные баффы так: ImmortalityBuff : IBuff, ну и CharacterStats в свою очередь CharacterStats : IStats. Тогда везде можно использовать только IStats и только в реализациях манипулировать конкретикой, даже кастовать не надо
@РщивтИвоил
@РщивтИвоил Жыл бұрын
Дяденька я тебя нашёл, твой канал записан у меня в блокноте как посмотреть весь полностью, канал просто кладесь нужной мне информации
@krivodeling7925
@krivodeling7925 9 ай бұрын
+
@caveman7246
@caveman7246 Жыл бұрын
Только сегодня хотел сесть за написание системы баффов, и тут бац, видосик) Приятно
Жыл бұрын
Месяц уже хотел реализовать, но не знал как создать ультимативную систему, откладывал - спасибо
@zloybivshiy7236
@zloybivshiy7236 Жыл бұрын
Спасибо за видео! Принцип добавления баффов через интерфейсы столь же просты, как и через компоненты в ECS - очень понравилось!
@maximtronin4510
@maximtronin4510 Жыл бұрын
Лайк коммент не глядя
@finimensniper3322
@finimensniper3322 Жыл бұрын
Да прикольный способ сделать простую систему бафов для небольшой игры, но через декораторы будет конечно покруче, хотя не всегда и нужно
@people_fly13
@people_fly13 11 ай бұрын
хороший урок, в райдере когда создаете в конструкторе параметр можно нажать альт энтер и он сам предложит закэшировать его в классе, сам создаст поле и сам присвоит
@ivanshamanaev1112
@ivanshamanaev1112 10 ай бұрын
При удалении единственного дебаффа на скорость, базовой она не становится и висит, как будто этот дебаф висит до сих пор
@buran_m3248
@buran_m3248 9 ай бұрын
Возможно, я тоже дурак, но мне кажется, что в коде есть ошибка, и я её поправил. В класс объекта игрока передаётся декоратор баффа (TemporaryBuff) и лист _buffs заполняется экземплярами декоратора. Сам же класс TemporaryBuff по окончанию своей работы пытается вызвать owner.RemoveBuff(coreBuff), и это ошибка - owner не содержит экземпляры core баффа, он содержит декораторы. Нужно передать owner.RemoveBuff(this). Далее, сам описанный баг вызван тем, что функция RemoveBuff в классе персонажа не выполняет ApplyBuffs(), применяя отмену баффа, а просто удаляет его из списка и всё. Однако, если просто дописать такую строку, вы получите бесконечный луп (почти, там сложный эффект, но вам не понравится) - ведь вызывая... foreach (var buff in _buffs) { CurrentState = buff.ApllyBuff(CurrentState); } ... вы каждый раз перезапускаете таймер, так как вы обращаетесь не к баффу напрямую, а к декоратору, запускающему таймер. Я решил эту проблему, введя банальную булку, которая говорит, был ли уже запущен таймер. Если да - не трогать его, а просто пропустить через себя вызов и вернуть статы после применения core баффа. public EnemyStats ApllyBuff(EnemyStats stats) { var newStats = coreBuff.ApllyBuff(stats); if (!timerOn) { timerOn = true; monoTimer.StartTimer(lifeTime); monoTimer.Completed += () => owner.RemoveBuff(this); } return newStats; } В моей ситуации, некоторые баффы могут накладываться до 4-х раз в секунду, при том, они никак не должны взаимодействовать между собой - каждый таймер должен работать отдельно, и как только последний из них закончит свою работу - эффект должен сняться. Надеюсь, помог
@Rom3lk
@Rom3lk Жыл бұрын
Красавчик. так держать👍
@SergeyBobrov240
@SergeyBobrov240 Жыл бұрын
Отличное видео! Хорошо и приятно объясняешь 👍 Решил зайти на ютубчик дабы поизучать нового, пока тасок нету, и в рекомендациях прилетело твое видео :)
@devnem0y
@devnem0y Жыл бұрын
Отличное видео, спасибо! Хотелось бы узнать как реализовать правильно паузу, чтобы не использовать timescale, после которого и анимация перестает работать)
@neosinpocket4184
@neosinpocket4184 Жыл бұрын
у Максима Крюкова на канале есть неплохой подход к решению этой проблемы
@SlothHuntOnYou
@SlothHuntOnYou Жыл бұрын
кстати есть плагин Disable KZbin 60 FPS (Force 30 FPS) - а затем наслаждайтесь видео на KZbin без задержек, меньшим использованием процессора (в 2-4 раза), более длительным временем автономной работы и меньшим использованием полосы пропускания! :-)
@StratoCatster
@StratoCatster Жыл бұрын
Все таки придётся думать как написать правильный таймер😢
@gamedevlavka
@gamedevlavka Жыл бұрын
😆
@akella0073
@akella0073 Жыл бұрын
Спасибо за хорошее видео. Единственное не понял в конце почему это декоратор. Мне больше это напоминает прокси: TempBuff и CoreBuff(в нашем случае ImmortalityBuff) наследуются от IBuff, и TempBuff содержит ссылку на CoreBuff
@vitaliySobakinson
@vitaliySobakinson Жыл бұрын
Актуальная тема :)
@skadexgd5057
@skadexgd5057 Жыл бұрын
Спасибо за урок!
@-._63
@-._63 Жыл бұрын
Здравствуйте. Хотелось бы спросить: не проще сделать коэффициент корректировки здоровья, брони, дамага? Таким образом не нужно будет менять основную переменную. И эффекты смогут легко смешиваться.
@gamedevlavka
@gamedevlavka Жыл бұрын
Так это тоже самое, коэффициент корректировки - это тоже стата, можно менять её. В целом в статах можно хоть что менять, как использовать- это другой вопрос. Есть разные механики и разные геймдизайнерские извращения. В формулах расчётов того же урона может такой ад твориться, даже не представляешь. Но ответ на вопрос таков: не не проще, но и не сложнее, т.к. это одно и то же)
@-._63
@-._63 Жыл бұрын
@@gamedevlavka Хорошо. Спасибо за видос!
@moranyt8299
@moranyt8299 Жыл бұрын
Где вы были несколько дней назад... Я уже свою систему модулей наделал
@gamedevlavka
@gamedevlavka Жыл бұрын
Рефакторинг ещё не поздно сделать) или уже поздно?
@moranyt8299
@moranyt8299 Жыл бұрын
@@gamedevlavka Ну там как сказать. Там лучше вовсе весь проект переделать, ибо я опять напоролся на проблему спагетти кода. Вот даже из-за этого решил попробовать использовать какой ни будь архитектурный паттерн в будущих проектах. Я правильно понял что в примере вы использовали MVC? И еще вопросик по системе баффов. Не будет проблем с временным бафом? Ведь там при удалении/добавлении текущие и новый баффы добавляются заново и следовательно снова запускается таймер и к эвенту окончания добавляется удаление временного баффа
@ОлегНахаев-у7с
@ОлегНахаев-у7с Жыл бұрын
Отличный ролик, спасибо)
@nightyonetwothree
@nightyonetwothree Жыл бұрын
всё же очень слабое развитие темы. Для системы бафов хочется иметь: проверку на уже наличие бафа этого типа, на наличие бафа генерик-типа, возможность стакать баффы или переписывать (заменять/обновлять) их новыми. Хочется возможность снятия бафа по типу, ведь не всегда известен конкретный референс на бафф. Собственно элементарная поддержка поведений бафов при apply/remove/ontick.
@gamedevlavka
@gamedevlavka Жыл бұрын
Подразумевается, что все перечисленное - уже понятно как делать, это лишь проверки, условия, применения - полная конкретика под конкретные нужды. Если очень надо, я могу дополнить, но не уверен, что это востребовано
@Paulsams
@Paulsams Жыл бұрын
Вот прям очень большой косяк есть в данной реализации, что на каждое изменение любого параметра -- придётся писать новый бафф. Плюс -- сами бафы будут заниматься валидацией. То есть, чтобы просто сделать одну и ту же логику изменения, и для хп, и для здоровья, например -- нужно реализовать два баффа и мне кажется это овер неудобным и странным. Наверняка сделано для новичков, но всё равно выскажу, как я бы сделал: сразу бы написал какой-нибудь ValueWithModifications (с названиями всегда туго, так что не важно + я немного опишу его загружено, но это не важно для понимания концепции), где внутри был бы реализован список модификаций (это например ограничения по Min/Max или как раз бафы + им сделать нужно приоритет по операциям, чтобы баундс всегда был в конце). Получится по итогу, что можно сделать и обычный бафф с изменениями, и сделать баундс изменения значения, и сделать временный бафф и т. д. И можно всё что угодно придумать и добавлять. Конечно в Юньке всё ещё нет IValue (или как его там? Ну который реализуют все значимые типы и это позволяет в дженерик классах производить примитивные операции над параметром), так что придётся писать там под int и float, но что есть).
@gamedevlavka
@gamedevlavka Жыл бұрын
Не совсем понял о чем ты, модно написать баф на каждую параметр статов вместе с валидацией и комбинировать как душе угодно. Параметры батареи задаются снаружи, то есть они конфигурируемые. Где тут на каждое изменение параметра ещё один баф?
@Paulsams
@Paulsams Жыл бұрын
​@@gamedevlavka Сорри заранее, если моё сообщение показалось немного грубым или около того, хах). Просто я скорее говорил о тех реализациях, что есть в видео. Например DamageBuff -- там одновременно и валидация значения, так и одновременно и изменение значение на какое-то число. Но хотелось бы, например, сделать какую-то более глубокую систему, чтобы не писать под каждый стат -- новый бафф. К примеру если будет РПГ игра, где есть сила, ловкость, интеллект и т. д. (ну к примеру там 20 статов даже), то в таком ключе, который ты показал -- будет казаться, что надо делать один и тот же код под каждый такой стат, а это как-то... Ну не то же). И я просто предложил, что наверное стоит всё таки сам стат сделать хранилищем бафов/модификаций.
@Paulsams
@Paulsams Жыл бұрын
Возможно я не прав, потому что в видео предполагалась идея, что баффы будут иметь контекст именно через конкретные реализации, а я себе представляю баффы -- как контейнер модификаций. Например, как оружия в тех же РПГ -- это же по сути контейнер модификаций статов. Ты же не будешь под каждую оружку в игре -- делать наследника IWeapon какого-нибудь, например. Мы будем тогда не объектами, а классами орудовать). Конечно можно было для оружек сделать обёртку, со всеми 100 полями персонажи, где будут в большинстве нули или те же значения -- но это вообще не камельфо. Поэтому лучше будет, если ты сможешь выбирать что конкретно оружка изменяет и насколько. И мне кажется, что баффы и изменение статов -- это всё одна система).
@gamedevlavka
@gamedevlavka Жыл бұрын
​@@Paulsams Да, этого можно добиться просто расширив предложенную в видео систему) Например: в ScriptableObject делаешь список бафов, какие угодно. Можно даже сделать генерируемые параметры в рамках каких-то ограничений. Пишется заранее класс декоратор (как в видео TemporaryBuff), который будет применять группу баффов и ему на вход список бафов кидаешь. Внутри он применяется каждый баф к статам. Вся прелесть в том, что получается невероятно гибкий конструктор, который легко конфигурировать. Такой скриптабл можно дать тому же оружию. Можно завернуть эту группу в TemporaryBuff и вуаля - все параметры что ты поменял, поменялись на время. Я понимаю, что в видео показан жёсткий пример, предполагалось, что остальное можно "додумать", но я могу и расширение снять рассказать)
@Paulsams
@Paulsams Жыл бұрын
@@gamedevlavka Ну это были названы преимущества именно декоратора). Я с этим паттерном как раз и не спорил). Просто меня беспокоило больше то, что по видео кажется, что на каждый стат, например: интеллект, броня, сила и т. д. -- надо будет делать отдельную реализацию интерфейса. Хотя я и понимаю, что ничто не запрещает сделать дженерик обобщённый бафф аля, который будет уметь от любого стата прибавлять n-ое число, например. Я опять же скорее просто говорил о том, что мне больше нравится подход, не когда статы валяются в контейнере/группе (как PlayerStats, например) и у баффов есть доступ ко всей группе статов, а когда сами статы являются контейнером баффов, которые влияют только на этот стат). Как-будто больше гибкости мне видется).
Please Help This Poor Boy 🙏
00:40
Alan Chikin Chow
Рет қаралды 19 МЛН
Watermelon magic box! #shorts by Leisi Crazy
00:20
Leisi Crazy
Рет қаралды 16 МЛН
Inside Out 2: BABY JOY VS SHIN SONIC 3
00:19
AnythingAlexia
Рет қаралды 9 МЛН
Как сделать инвентарь в Unity. Часть 1: Модель, абстракция
35:03
MonoBehaviour и ScriptableObject. Для чего нужны и как использовать?
19:38
Руслан Смирнов • Game Development
Рет қаралды 9 М.
Паттерн Прокси (Proxy) в C#. Как использовать в Unity?
18:18
Лавка Разработчика
Рет қаралды 2 М.
Введение в addressables
28:24
Unity Оk
Рет қаралды 5 М.
Drag and drop in Unity UI - create your own inventory UI!
12:47
Coco Code
Рет қаралды 107 М.
Как сделать управление в Unity используя интерфейсы?
11:33
Лавка Разработчика
Рет қаралды 7 М.
Please Help This Poor Boy 🙏
00:40
Alan Chikin Chow
Рет қаралды 19 МЛН