Достаём информацию из классов и сцен без создания инстансов
Godot 4.1 наконец-то стал стабильнее и перестал вылетать, а ещё там завезли статичные переменные
Что это даёт?
class_name Projectile const MOVE_SPEED = 500
Эти константы были доступны как из инстанса класса, так и напрямую через Projectile.MOVE_SPEED
Однако, в константы можно было класть только примитивы
const foo = Node.new()
Но иногда статичная информация включает в себя не только примитивы
К примеру, у меня есть массивы перков/скиллов персонажей, которые состоят из load("../some_script.gd")
Теперь появился кейворд static, позволяющий как раз положить это в переменную:
class_name Rogue
extends Unit
static var perks_map = [load("..."), load("...")]И, соответственно, можно делать Rogue.perks_map, не создавая инстанс роги
В моём случае это очень важно, поскольку в персонажах лежат скиллы и перки, а в скиллах и перках лежит логика из кучи нод и объектов. Создавать инстанс = создать под 500 объектов, которые тебе по сути не нужны. А учитывая, что сборщик мусора в GDScript работает так себе, ты ещё и утечки памяти впридачу получал
Однако, есть одна проблема - если ты загружаешь сцену, а не класс, то ты всё ещё не можешь обращаться к статичным переменным
То есть вот такой код не сработает:
var Rogue = load("./rogue.tscn")
# Ошибка, несмотря на то, что рутовая нода имеет класс роги
Rogue.perks_mapЧтобы решить эту проблему, я пришёл к вот такому вспомогательному коду:
class_name Instance # Takes anything, and # - Returns class instance, if passed .gd script # - Returns smth.Scene.instantiate() and sets smth as script to scene root, if passed .gd script with Scene variable # - Returns scene instance, if passed PackedScene static func create(something): var instance if "Scene" in something: instance = something.Scene.instantiate() instance.set_script(something) elif "instantiate" in something: instance = something.instantiate() elif "new" in something: instance = something.new() else: instance = something return instance
И вместо того, чтобы навешивать класс роги на рутовую ноду сцены, я прописываю в самом классе роги
var Scene = load("./rogue.tscn")И везде вместо сцены загружаю класс:
var Rogue = load("./rogue.gd")
# `perks_map` доступен
Rogue.perks_map
# А вот так получаем инстанс сцены
var rogue = Instance.create(Rogue)