Godot
November 7, 2022

ООП без трейтов - боль. Колхозим кастомизацию скиллов

Блин, как же в GDScript не хватает хотя бы трейтов.

То есть вот банально - есть у меня класс Action. Это базовый класс для всех действий.

Окей, какие-то действия являются атаками. Можно сделать класс Attack, унаследовать его от Action, и докинуть логику нанесения урона. Казалось бы, антибугурт.

Но некоторые скиллы в моей игре будут иметь таланты. Как у персонажей в доте - на каждой прокачке выбираешь одну из двух пассивок. Только у меня таланты будут на самих скиллах.

Поскольку наследоваться можно только от одного класса, а трейтов в GDScript нет, назревает очевидный вопрос - как мне это реализовать?

  • ActionWithTalent + AttackWithTalent? А когда ещё одна фича появится, комбинаторный взрыв делать?
  • Вшивать таланты в Action и добавлять флаг has_talents, раздувая его реализацию?

Ну пиздец же!

В итоге смастерил себе такой колхоз. Добавил в рут класса инстанс Traitor, в который под интересующими ключами добавляю инстансы специальных классов Trait. Traitor автоматически прокидывает в них инфу о юните + дёргает встроенные методы типа _physics_process, когда таковые дёргаются в юните

То есть, если я хочу, чтобы какой-то Action был прокачиваемой атакой - я навешиваю на него AttackTrait + TalentTrait. В них своя техническая логика (типа ловли коллизий, события прокачки талантов итд), на которую я в дальнейшем могу подписаться в своём RogueHitAction

Правда, это нихрена не трейты на самом деле, так что, наверное, потом переименую. А может, и так оставлю, название мемасное


Только вот редактор эти созданные из кода инстансы классов, очевидно, не увидит. Придётся в этом же коде навешивать события, а не соединять их через GUI. Их не будет видно в дереве нод. И так далее. А ещё пришлось дополнительно дописать шортхэнды для проверок на наличие специфичных трейтов, потому что сделать Action is Attack тут уже не прокатит

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

Гораздо проще работать с простыми статически типизированными объектами, трансформировать их через функции, а логику описывать декларативно через создания связей между событиями. Чо-то типа Effector

А с этими классами, которые вызывают или не вызывают родительские методы, которые нельзя расширить несколькими несвязанными друг с другом фичами, классо-интерфейсами-абстрактнымиклассами-трейтами - вот сколько не смотрел, везде сплошная монструозная еботня с сомнительной пользой, чесслово