Godot
June 10, 2023

Another week - another bugs!

На этой неделе не так много было времени потупить над персом

Но то время, что было - я протупил основательно

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


Вот один только отскакивающий снаряд проблем принёс:

Эзотерическое застревание снаряда в мобах

Normally снаряд должен долетать до моба и сразу отскакивать в другого

Но иногда он просто застревал в юните и больше ничего не делал

Сначала я думал, что это снаряд как-то проскальзывает коллайдер. Особенно учитывая, что сначала он вообще истерически дёргался внутри юнита, пока я не добавил проверку, которая вталкивает снаряд в центр

Но это не помогло

Где-то неделю я периодически наблюдал, как эта хрень происходила абсолютно спонтанно, пока не понял, что здесь затесалась гонка состояний

Как вы помните, игра у меня с видом сверху, но спрайты с видом сбоку.

Соответственно, их хитбокс находится в середине тела, а точка, где они стоят, снизу

Что из этого следует? А то, что коллайдеры могут пересекаться!

И вот как раз когда снаряд попадал в такое перехлёстывание, оно и ломалось

  1. Снаряд прицелился в первого юнита
  2. Врезался в первого, но также задел и второго
  3. Таргет сменился на второго
  4. Игра ждёт коллизию со вторым, но она уже произошла
  5. Вуаля, снаряд завис

Этот баг на данный момент никак не пофикшен, т.к. с учётом того, как код написан, я пока не придумал, как безболезненно это зафиксить

Да и как оно работать должно, тоже пока хз

  • Засчитывать ли демедж сразу, когда два юнита перехлестнулись?
    Будет как-то стрёмно выглядеть, что снаряд, летя в одного юнита, продамажил другого
  • Засчитывать коллизию, только когда снаряд долетел до центра?
    Тогда им будет гораздо сложнее целиться, надо усилить аиминг. Услиить аиминг = получить избыточный аиминг там, где он не нужен

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

Коллизии с CharacterBody2D/Area2D

Ещё очень долгое время снаряд игнорировал края карты и просто в них упирался, и мне дико лень было это фиксить

Всё потому, что в Godot какой-то всратый подход с разделением на "тела" и "зоны". И где-то есть события нужных коллизий, а где-то нет

Ну вот, например, CharacterBody2D (ранее KinematicBody2D), коим является снаряд, не может трэкать, что он попал внутрь какой-то Area2D. Ну или хотя бы коснулся её. Почему? Если он может в неё зайти, почему бы не обработать это событие там же?

Сделали бы какой-то общий тип, от которого наследуются все эти зоны/юниты, проблемы бы не было. Но зачем-то разделили

В итоге код, отвечающий за коллизию, лежит не в снаряде, а в юнитах и в окружении

"Когда в зону хитбокса юнита/края карты попало тело, сообщи ему, что оно попало, если это снаряд" То ли лыжи не едут, то ли я...

Снова TargetStore

Но теперь прикол в другом

Для Bounce я добавил фильтр целей "отсутствует в списке задетых целей", чтобы снаряд отскакивал по уникальным противникам

Но это привело к тому, что снаряд либо аимился на врагов, но не дамажил их; либо, наоборот - дамажил, но летел по прямой

Убил на отладку снарядов/демедж дилера добрых 3 часика. В итоге проблема оказалась вот в этом банальном сегменте, который отвечает за внесение юнита в список:

Заметили ошибку?

targets - это массив всех целей, по которым попадал снаряд. После чего я на его основе делаю реактивнйы массив valid_targets - то есть, целей, которые проходят фильтры

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

А ещё себе фильтр "не содержится в списке задетых целей" в принципе схлопывает сам себя, ведь добавленный в список юнит тут же перестаёт быть валидным элементом этого списка

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

На самом деле, поправить не сложно - нужно всего лишь сделать valid_targets не реактивным, а добавлять/удалять вручную. Но на это место подвязано много чего, так что пока не трогаю


В общем, такие пироги. И это лишь Bounce, а там все 4 скилла довольно ребусными вышли

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

Персонаж почти готов, осталось дочинить остальное и добавить анимацию

Зацени, кстати, рунки!
Больше никаких разноцветных кружочков с квадратиками :)