September 22, 2023

Я недооценивал ресурсы

И коротко о том, как я избавился от фризов при смене сцен и сделал почти мгновенную загрузку игры


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

Виной тому было моё распиздяйство по отношению к загрузке данных)0)

Что фризило?

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

Причина была в том, что я хранил данные о них (всякие иконки, названия итд.) прямо в классах.

То есть, в классе персонажа лежали сцены со скиллами, а так же класс PerksMap, в котором лежали все перки, доступные персонажу. Ну а информация о перке лежала в классе перка.

Таким образом, для того, чтобы выбрать персонажа и его скиллы, приходилось загружать соответствующие сцены. А для выдачи перков - загружать все перки.

Делал я так, потому что неправильно прочитал доку и полагал, что функция load() подгружает класс на момент создания инстанса.

Настоящая же разница между preload и load следующая:

  • preload() подгружает штуки на момент запуска сцены, в которой preload написан. Независимо от того, вызвалась ли строчка кода с preload() или нет;
  • load() подгружает штуки на момент выполнения строки, где load() использован;

В итоге вот эта херня:

при нажатии на кнопку "Play" фризила игру примерно секунд на 10. А загрузочный экран я никакой ещё не делал. Жопа!

Окей, а причём тут ресурсы?

Я решил оперативно избавиться от загрузок и хранения мета-инфы в классах, чтобы при выборе персов/скиллов/перков не было необходимости грузить классы.

Но чот вдруг решил полистать доку и наткнулся на Resource.

Я как-то обошёл их стороной в своё время - оперировал всё время либо нодами, либо RefCounted.

В общем, Resource - это класс, от которого можно наследоваться, чтобы создавать кастомные структуры данных.

Например, вот такой класс сделал под персонажа:

Затем мы можем создать .tres-файлик, который от него наследуется:

И в инспекторе мы можем с ним поиграться:

Обращаю внимание на "Scene Path" и "Perks Map Path" - вместо сцен/скриптов в эти переменные я сложил пути для них. Чтобы они не загружались при загрузке этого ресурса.

Теперь вместо прокидывания сцены с юнитом и скиллами в меню можно швыряться чисто этим ресурсом, и оно загрузится почти мгновенно.

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

Окей, но ты мог так сделать и с обычным классом

Мог, но у ресурсов есть ряд преимуществ.

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

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

Это дало бесплатную возможность запоминать, какие скиллы были выбраны в менюшке. Всего одна строчка кода и готово:

А что насчёт JSON?

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

Например, JSON ты можешь конвертировать в csv и экспортировать в Notion. Так ты получишь редактируемую табличку, которую можешь потом обратно скачать и сохранить для игры.

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

Однако, JSON хранит только тривиальные данные - числа, строки, булевые флаги и null. Ну и вложенные массивы с объектами.

То есть, ты не сможешь положить туда файл, скилл и так далее.

Всякие вспомогательные функции тоже придётся описывать отдельно.

Также, с JSON ты лишаешься редактирования внутри IDE и прочих QoL-штук.


Короче говоря, оба формата имеют свои плюсы и минусы. Я решил посидеть на ресурсах по итогу.

Осталось вытащить в них описание из 200+ перков. Ближайшие 2 дня будут очень увлекательными)0)