8

Godot. Static, Tool и два Enums'a

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

Да, под  метагеймом я подразумеваю не MostEffectiveTactic, а абстрагированное развитие прогресса игрока, вне основной геймплейной сессии.


А потому в этом посте, будет простенькое хранение игровой валюты, отображение её на экране и кнопочка с помощью которой можно будет потратить эту валюту)
Создал пустой проект, в которых запихнул три иконочки.

Перво наперво надо её где-то хранить, запилим CurrencyStorage. Можно это конечно сделать синглтоном или ещё как, но в этом случае я сделаю, используя статичные функции, меня недавно распрашивали насчет них, кому-то видимо нужно и может пригодится, да и сам я ими пользуюсь в различных Utils классах.
Важное замечание, в gdscript есть статичные функции, но нет статичных переменных, что с одной стороны странно и неудобно, с другой стороны хорошо) Но эту неприятность легко можно обойти, например в константе хранить массив, словарь или свой пользовательский класс.

Использую словарик.

Обратите внимание, что класс CurrencyStorage, ни отчего не наследуется, его экземпляров мы создавать не будем, при попытке запихать его в AutoLoad будет ошибка.

Ну ладно. проверим что все работает как надо

Теперь сделаем универсальный Label, который будет показывать не только количество, но и содержать в себе иконку валюты.

Сейчас можно расставить наши IconLabel в сцене Main, запустить и игра упадет.

Связано это с порядком выполнения методов _ready() в дочерних и родительских нодах, а если помните то CurrencyStorage.store() я поместил именно в _ready.
Кстати непонимание этой разницы вызывает немало ошибок у новичков, поверьте я знаю с двумя новичками и сотрудничаю сейчас.
метод _ready() это не конструктор, он вызывается когда экземпляр уже добавился на сцену в результате add_child(). Конструктор, который вызывается при создании экземпляра это _init()
И порядок выполнения следующий:
parent -> _init()
child -> _init()

...

child -> _ready()

parent ->_ready()


_init родителя вызывается раньше чем _init потомка, но добавляются на сцену они в обратном порядке, что в принципе очень даже логично)
Перенесем загрузку стартовых данных в _init()

Для каждой IconLabel не забудьте указать разный тип. И я кстати косякнул, два раза в match указал Gold, вместо Silver.

Собственно результат при запуске.

В редакторе же мы видим далеко не такую красоту, там тлен и пустота.

Согласитесь очень неудобно, ведь надо же не только вывести, но и красиво расставить.

Для этого воспользуемся ключевым словом tool.

собственно результат

Картинками не показать, что меняется в редакторе, вот видосик держите.

Наберет если пост 15 лайков, то напишу и продолжение про пользовательскую кнопку для покупок за валюту, и покупке валюты за рубли)) Тонкий байт на лайки, эндорфинов не хватает, а каждый лайкосик дает немало)

Ну и ссылка на чатик сообщества в тг https://t.me/Godot_pikabu
Можно позадавать или поотвечать на вопросы или просто пофлудить, но без троллинга и токсичности плз.


p.s. А иногда tool не сразу почему-то работает после добавления его в скрипт, бывает нужно релоаднуть проект.

Свидетели Godot'овы

91 пост333 подписчика

Правила сообщества

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

Вы смотрите срез комментариев. Показать все
2
DELETED
Автор поста оценил этот комментарий

Не могу не покритиковать, уж извините

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


Тул для отображения контента кажется костылём, особенно с учётом того, что он модифицирует состояние нод в редакторе и может привести к весьма необычным багам. Достаточно просто забить дефолты прямо в редакторе. Когда контент в элемент устанавливает парент (инверсия зависимости), то проблем никаких с этим нет. Тем более что по сути вы именно дефолты в ноды и проставляете, просто из кода. Но повторюсь - это относительно опасно, неудачная модификация кода и можно сломать проект или поменять какие-то свойства, которые меняться не должны были.


И как сделать сигнал для обновления лейбы при работе с валютой? emit_signal из статического метода не вызовешь, т.к. сигналы это методы инстанса. _ready вызывается один раз, и как тогда в лейбе узнать об изменениях и перерисовать содержимое? в _process, 60 раз в секунду спрашивать, не поменялось ли чего? Боюсь, это быстро угробит FPS на некоторых системах, особенно в браузере на телефоне, например. В автолоаде, опять таки, никаких проблем с сигналами нет.

раскрыть ветку (3)
1
Автор поста оценил этот комментарий

Я вобще не против критики, напротив только за) Более того у меня все стораджи в своем проекте, сделаны именно через AutoLoad, это лишь вариант показать, что со статическими методами вполне можно городить)


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

Насчет сигнала, ну это совсем элементарно. У меня в каждом проекте есть синглтон Dispatcher, содержащий в себе только сигналы и обертку, через которую он эмитит эти сигналы, чтобы можно было легко отслеживать кто именно эмитит сигнал. Не утверждаю что это лучшее решение, но пользовался таким и 10 лет назад когда в GI работал и не вижу смысла не пользоваться и сейчас, коли мне привычно и удобно)) Кому надо эмитит эти сигналы, кому надо подписывается)

раскрыть ветку (2)
2
DELETED
Автор поста оценил этот комментарий

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


А сигналы можно хоть через funcref эмулировать, но это очень сильно напоминает "троллейбус из буханки хлеба jpg".

раскрыть ветку (1)
1
Автор поста оценил этот комментарий

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

И да, оно может странно выглядеть, что в посте я писал всякие словари enums и тд, а на скрине из реального проекта, для каждого типа своя переменная. Потому что так и есть, в реально проекте я никогда не буду городить словари, или ещё что-то для такого простого и в тоже время важного момента, как игровая валюта) Сколько надо столько и создам методов и переменных под её хранение)) Чем проще тем лучше, но для поста мудренный вариант, самое оно))

Иллюстрация к комментарию
Вы смотрите срез комментариев. Чтобы написать комментарий, перейдите к общему списку