Не наноси урон втупую
Во многих туториалах по Godot/Unity итд. можно увидеть, что нанесение урона реализуют самым банальным образом
То есть просто вбрасывают голую цифру урона и на этом всё
Однако, такой подход плох тем, что у тебя нет возможности в общем виде модифицировать урон и подвязываться на различные события - от кого пришёл урон, чем его нанесли, "нужно удвоить, если юнит застанен" и так далее. И сам процесс вычисления урона остаётся необобщённым
У себя в игре весь урон я реализовываю через вот такой класс. Назвал его DamageTransaction
А так же ряд методов, чтобы можно было "собирать" транзакцию
Тут большая простыня Ctrl+C
Ctrl+V
, но да ладно:
commit
выглядит следующим образом:
Получаемый юнит же при вызове receive_damage_transaction
смотрит, должен ли он получить демедж (ибо у него может быть неуязвимость, например), прогоняет модификации (а-ля порезать урон, если это крит), и затем уже получает урон (или не получает)
В транзакции при этом сохраняется результат сего действия - сколько урона прошло, прошёл ли он вообще, был ли это крит, был ли урон летальным
Дополнительно дёргается сигнал в общей шине, на который можно подписаться из любого места
- Наносимый урон собирается по кусочкам
- Это даёт возможность модифицировать из любого источника в несколько этапов - будь то скилл; перк, его модифицирующий или же персонаж, его получающий
- Транзакция содержит в себе всю необходимую информацию
- Это даёт возможность делать тысячи модификаций в духе "если тычка была летальной", "если тычка ударила врага такого-то вида", "если на тебе висит какой-то статус-эффект" итд.
- Также, засчёт того, что источник урона тоже лежит в транзакции, можно класть информацию прямо в ноды снарядов/аоешек/итд. К примеру, хочешь ты, чтобы стрела стакала урон за каждого прошитого моба. Это очень легко реализовать на этапе сбора транзакции - просто добавляешь счётчик поражённых врагов снаряду, а на этапе сборки транзакции добавляешь множитель от
source.affected_units_count
- Результат нанесения урона также можно узнать из транзакции
- Глобальный сигнал
Напоследок - пару примеров утилизации
- Перед получением урона юнит дёргает метод
_can_hurt
каждого статус-эффекта, на нём висящего. Вот, к примеру, как легко реализуется "юнит может получить урон только от себя"
- У сущности
DamageDealer
, которая отвечает за нанесение урона (путём, как раз-таки, генерации транзакций), есть пайп, который вызывается с транзакцией перед её коммитом и считает суммарный множитель урона
Перки просто добавляют в этот пайп дополнительные шаги
Вот так, например, меняется урон тычки от количества врагов с меткой:
А вот так - если где-то прозвенел крит, можно обнулить кулдаун скиллов:
В общем, пользуйтесь!
И помните - чем больше вещей вы уведёте из произвольного формата в общий, формализованный, тем больше возможностей вы будете иметь в дальнейшем. И пока ваш конкурент тратит неделю на реализацию хитрого перка, написывая лапшекод, вы уже реализуете с пару десятков и в процессе написания вам ещё куча идей сверху придёт