Немного о классах в Godot 3.1
Не так давно в Годо была добавлена возможность создавать свои ноды одной строкой (а не только плагинами).
Теперь можно например в скрипте игрока написать class_name Player
и где-нибудь в другом месте получить экземпляр этого класса через Player.new()
.
Всё вроде бы хорошо, давайте далее.
А дальше камней только больше. Я задался задачей создания экземпляра, имея имя класса в виде строки (например вытянутой из конфига или базы данных). Немного поисков (а точнее достаточно много, раз я пишу это) и я обнаруживаю класс ClassDB
, который хранит в себе все доступные пользователю классы движка. Да ещё и есть метод instance()
, в который можно передать имя класса в виде строки и получить обратно экземпляр класса.
Начинаем разбираться в проблеме.
Победа? Не совсем. Мы можем написать например ClassDB.instance('Node2D')
и в ответ получить наш класс Node2D
, на если мы напишем ClassDB.instance('Node2D')
, то получим Null
. Дело в том, что ClassDB
хранит в себе только классы движка, а классы, созданные пользователем не попадают туда.
Если проблема и есть, то она где-то рядом. Идем в репозиторий Годо на GitHub и ищем как работает наш class_name
. После недолгих поисков я обнаружил, что пользовательские классы - не совсем классы, но всё же классы, потому что скрипт - это класс.
В общем я быстро поглядел на код и увидел, что пользовательские классы называются global_script_class
. Уже тепло. Теперь открываем документацию и пытаемся отыскать что-то подобное и обнаруживаем, что у нас есть доступ к ProjectSettings._global_script_classes
(вероятно это не правильно. Не зря же там _ в начале имени переменной). Принтуем это и получаем что-то вроде [(base:Area2D), (class:Chest), (language:GDScript), (path:res://chest.gd), (base:Sprite), (class:Didon), (language:GDScript), (path:res://spidt.gd)]
. Зрелище не очень, но если вывести это немного иначе, то получим весьма читаемое чудо:
Теперь мы видим, что это массив, где в каждой ячейке лежит словарь с четырьмя ключами. Таким образом, чтобы получить пользовательский класс нам необходимо создать экземпляр класса, который написал в 'base'
, и загрузить в него скрипт из 'path'
. Немного "улучшим эту идею" и сделаем из этого функцию:
Итого
Данный способ получился немного непредсказуемым, но зато я ещё немного прокачал свой скилл. Теперь об этом знаю не только я, но и ты, читатель.
На самом деле всё началось с того, что Хуан (разработчик Godot) добавил новый класс Expression и я хотел его попробовать, но конструкцию вроде "%s.new() % 'ClassName' "
класс конечно переваривал, но на выходе выдавал null
и я реши всё так и "докопаться до сути" и решить эту проблему. Вот так вот попытка изучить что-то одно позволила мне изучить что-то другое, но не менее нужное и важное.