Как же геморно создавать UI в Godot
Не, оно в целом выполнимо, конечно. Но насколько же много действий в редакторе + кода это требует по сравнению с фронтендом на условном React.js
Задача
- Перед началом игры тебе нужно выбрать персонажа
- У некоторых скиллов есть альтернативы. Их нужно выбрать перед забегом
- Ну и, соответственно, видеть информацию о скиллах перед началом забега тоже нужно
Велосипедим
Для начала я решил переиспользовать штуки из библиотеки, которую я набросал для описания логики скиллов и перков. В частности - DState и DCombine
DState- класс, которая имеет состояние + метод для его обновления + сигналupdated+ методwatch, который дёргает прокинутую в него функцию при обновлении стейтаDCombine- берёт пачку стейтов и собирает из них новыйDState, значение которого вычисляется из прокинутой функции
Код невероятно вербозный относительно задачи, которая стоит, но я хз как упростить в рамках GDScript.
На JS это было бы в 2 раза короче засчёт таких фич как:
- Деструктуризация (
const [a, b] = array) - Поддержка произвольного количества аргументов у функций
- Отсутствие багнутого приведения типов в массивах, с которым
Array[PackedScene]нельзя превратить вArray[ActionV2]с помощьюarray.map(func (scene): return scene.instantiate()) - Возможность обратиться к несуществующему айтему массива (например, если его длина меньше индекса) и просто получить пустоту вместо крашей.
В общем на JS это выглядело бы как-то так
Поскольку Godot не оперирует реактивными сущностями, синхронизировать обновления придётся руками. Причём в обоих направлениях
Здесь мы реагируем на обновления стейтов и "ререндерим" интерфейс - заменяем скиллы в переключалках при смене перса, заменяем карточки с описаниями скиллов при выборе скилла итд.
А здесь реагируем на события переключения персонажей, вкладок и выбора скиллов. Эта часть значительно проще, поскольку она лишь обновляет стейты:
В мире фронтенда всё гораздо проще - описал темплейт и данные, которые в него будут вставлены, и всё синхронизируется. По клику на кнопку обновил стейт - автоматом всё обновилось, не надо ничего руками привязывать.
Здесь, к сожалению, придётся делать всё руками. По крайней мере, если не собирать какую-то UI-библиотеку, которая сама занималась бы синхронизацией реактивных штук, но это, опять-таки, нужно изобрести.
Из похожего наткнулся на такую штуку, но она в экспериментальном состоянии + вышла в 2021м году и наверняка не работает в 4-й версии Godot.
Сама сцена
В целом Godot поставляет из коробки набор элементов UI. Среди них сетки с выравниванием, кнопки, текстовые поля, выбор элементов из списка итд.
Не могу сказать, что они настолько кастомизируемые, насколько хотелось бы. Но тут я, опять-таки, смотрю со своей избалованной фронтендерской колокольни. Может, этого в геймдеве и достаточно
Из советов, которые могу дать тем, кто будет тыкать - старайтесь при формировании лейаута пользоваться не абсолютным позиционированием, а относительным.
А не захардкоженные координаты
Так будет проще менять размер тех или иных блоков - не придётся каждый кусочек руками ресайзить и выравнивать, достаточно будет просто подвигать сам контейнер
Также заворачивайте весь интерфейс в Panel/PanelContainer, чтобы все эти штуки с позиционированием работали с самого "рута"
В общем, сцена с выбором персонажа выглядит вот так
Тут, к счастью, всё довольно просто.
Что получилось в итоге
Переключаем персонажей сверху, выбираем скиллы во вкладке "Select Skills", подробное описание во вкладке "Description"
C UX-овой точки зрения интерфейс, очевидно, такой себе - в идеале ты должен видеть, что выбираешь, сразу, а не идти за этим в другую вкладку
Но пока оставлю так. Функционально работает, а причёсывать буду позже, когда для интерфейса появится и графика. Историю с отображением инфы на этапе выбора думаю пофиксить обычными тултипами как в Risk of Rain 2
В целом, если в игре будет много логики, связанной с UI, то, вероятно, попробую запилить какие-нибудь примитивы, чтобы было проще жить, и не приходилось руками прописывать синхронизацию