Написание скриптов

Введение

До Godot 3.0, единственным выбором для написания скриптов игры был GDScript. В настоящее время Godot официально поддерживает четыре (да, четыре!) языка и имеет возможность динамически добавлять дополнительные скриптовые языки!

Это здорово, в основном из-за большой гибкости, но это также затрудняет нашу работу по поддержке языков.

«Основные» языки в Godot - это GDScript и VisualScript. Основной причиной такого выбора является их уровень интеграции с Godot. Это делает процесс овладения Godot более плавным; они оба имеют полную интеграцию с редактором, в то время как для С# и С++ необходимо использовать отдельную IDE. Если вы большой поклонник статически типизированных языков, то используйте C# и С++.

GDScript

GDScript, как упоминалось выше, является основным языком, используемым в Godot. Его использование имеет некоторые положительные моменты по сравнению с другими языками из-за его высокой интеграции с Godot:

  • Он прост, элегантен и разработан, чтобы быть понятным для пользователей, знающих другие языки программирования, таких как Lua, Python, Squirrel и т. д.
  • Загружает и компилирует невероятно быстро.
  • Интеграция с редактором позволяет с удовольствием работать, с написанием кода для узлов, сигналов и многих других элементов, относящихся к редактируемой сцене.
  • Имеет встроенные векторные типы (например, Vectors, transforms и т. д.), что делает использование линейной алгебры эффективным.
  • Поддерживает несколько потоков так же эффективно, как статически типизированные языки - это одно из ограничений, которое заставило нас избегать виртуальных машин, таких как Lua, Squirrel и т. д.
  • Не использует сборщик мусора, поэтому он располагает небольшой автоматизацией (в любом случае большинство объектов подсчитываются ссылками), детерминизмом.
  • Его динамическая природа упрощает оптимизацию разделов кода на C++ (через GDNative), если требуется большая производительность, без перекомпиляции движка.

Если вы не определились с выбором языка, но имеете опыт программирования, особенно на динамически типизированных языках, попробуйте GDScript!

Визуальный Скриптинг

Начиная с версии 3.0, Godot предлагает Визуальный Скриптинг. Это типичная реализация языка «блоков и соединений», но адаптированная к тому, как работает Godot.

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

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

.NET / C#

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

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

Поскольку Godot использует среду выполнения Mono.NET, теоретически любая сторонняя библиотека .NET или программная платформа может использоваться для написания скриптов в Godot, так же как любой CLR-совместимый язык программирования, такой как F#, Boo или ClojureCLR. Однако, на практике C# является единственным официально поддерживаемым .NET вариантом.

GDNative / C++

Наконец, одно из наших самых ярких дополнений для версии 3.0: GDNative позволяет создавать скрипты на C++ без необходимости перекомпилировать (или даже перезапускать) Godot.

Любая версия C++ может быть использована, а смешение брендов и версий компиляторов для сгенерированных общих библиотек прекрасно работает благодаря нашему использованию внутреннего C API Моста.

Этот язык является лучшим выбором для производительности и не должен использоваться во всей игре, так как другие части могут быть написаны в GDScript или Visual Script. Однако API ясен и прост в использовании, так как по большей части он похож на C++ API Godot.

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

Создание сценариев сцены

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

  • Написание сценария и его привязку к узлу.
  • Подключение элементов пользовательского интерфейса через сигналы.
  • Написание сценария, который может получать доступ к другим узлам в сцене.

Прежде чем продолжить, обязательно прочитайте ссылку GDScript. Это язык, разработанный для того, чтобы быть простым а справочник краткий , поэтому для ознакомления с основными понятиями потребуется не более нескольких минут.

Настройка сцены

Используйте диалог «Добавить дочерний узел», доступ к которому осуществляется из вкладки «Сцена» (или нажатием Ctrl+A), чтобы создать иерархию со следующими узлами:

  • Панель
    • Ярлык
    • Кнопка

Дерево сцены должно выглядеть так:

../../_images/scripting_scene_tree.png

Используйте 2D-редактор для позиционирования и изменения размера Кнопки и Ярлыка, чтобы они выглядели как на изображении ниже. Вы можете набрать текст во вкладке «Инспектор».

../../_images/label_button_example.png

Наконец, сохраните сцену с именем sayhello.tscn.

Добавление сценария

Щелкните правой кнопкой мыши на узел Panel и выберите «Прикрепить скрипт» в контекстном меню:

../../_images/add_script.png

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

В GDScript файл представляет собой класс, поэтому поле имени класса не редактируется.

Узел, к которому мы прикрепляем скрипт, представляет собой панель, поэтому в поле «Наследование» будет автоматически вписано «Panel». Это то, что нам нужно, поскольку цель сценария заключается в расширении функциональности нашего узла панели.

Наконец, введите путь к сценарию и нажмите кнопку «Создать»:

../../_images/script_create.png

После этого скрипт будет создан и добавлен к узлу. Вы можете понять это по значку «Открыть скрипт» рядом с узлом на вкладке «Сцена», а также в свойстве Script в «Инспекторе»:

../../_images/script_added.png

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

../../_images/script_template.png

Там не так много. Функция _ready() вызывается, когда узел и все его дочерние элементы входят в активную сцену. Примечание: _ready() не является конструктором; конструктором является _init().

Роль сценария

Скрипт добавляет узлу поведение. Он используется для управления функционированием узла, а также его взаимодействия с другими узлами: дочерними, родительскими, родственными и т.д. Локальная область скрипта - это узел. Другими словами, скрипт наследует функции, предоставляемые этим узлом.

../../_images/brainslug.jpg

Обработка сигнала

Сигналы «излучаются», когда происходит определенный вид действий, и они могут быть подключены к любой функции любого экземпляра сценария. Сигналы используются в основном в GUI-узлах, хотя они также есть и в других узлах, и вы даже можете определить пользовательские сигналы в своих собственных сценариях.

На этом этапе мы подключим сигнал «pressed» («нажато») к пользовательской функции. Формирование соединений - это первая часть, а определение пользовательской функции - вторая. Для первой части Godot предоставляет два способа создания соединений: через визуальный интерфейс, который редактор предоставляет, или через код.

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

Выберите узел Кнопка (Button) в дереве сцен и затем выберите вкладку «Узел». Далее, убедитесь, что вы выбрали «Сигналы».

../../_images/signals.png

Затем, если выберете «pressed()» в разделе «BaseButton» и нажмете кнопку «Подключить…» в правом нижнем углу, откроется диалог создания соединения.

../../_images/connect_dialogue.png

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

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

By default, the method name will contain the emitting node’s name («Button» in this case), resulting in _on_[EmitterNode]_[signal_name]. If you do have the «Make Function» check button checked, then the editor will generate the function for you before setting up the connection.

На этом завершим наше обучение по использованию визуального интерфейса. Все-таки это урок по написанию скриптов. Поэтому, ради лучшего понимания, давайте писать код самостоятельно!

Для этого мы познакомимся с функцией, которая, вероятно, наиболее часто используется программистами Godot: Node.get_node(). Эта функция использует пути для извлечения узлов из любого места сцены, относительно узла, которому принадлежит скрипт.

Для удобства удалите все под extends Panel. Вы заполните остальную часть сценария вручную.

Поскольку Button и Label являются детьми по отношению к Panel, к которой прикреплен скрипт, вы можете выбрать Button, написав следующее в функции _ready():

func _ready():
    get_node("Button")
public override void _Ready()
{
    GetNode("Button");
}

Затем напишите функцию, которая будет вызываться при нажатии кнопки:

func _on_Button_pressed():
    get_node("Label").text = "HELLO!"
public void _OnButtonPressed()
{
    GetNode<Label>("Label").Text = "HELLO!";
}

И наконец, подключите сигнал «pressed» от кнопок к функции _ready(), используя Object.connect().

func _ready():
    get_node("Button").connect("pressed", self, "_on_Button_pressed")
public override void _Ready()
{
    GetNode("Button").Connect("pressed", this, nameof(_OnButtonPressed));
}

В итоге скрипт должен выглядеть так:

extends Panel

func _ready():
    get_node("Button").connect("pressed", self, "_on_Button_pressed")

func _on_Button_pressed():
    get_node("Label").text = "HELLO!"
using Godot;

// IMPORTANT: the name of the class MUST match the filename exactly.
// this is case sensitive!
public class sayhello : Panel
{
    public override void _Ready()
    {
        GetNode("Button").Connect("pressed", this, nameof(_OnButtonPressed));
    }

    public void _OnButtonPressed()
    {
        GetNode<Label>("Label").Text = "HELLO!";
    }
}

Запустите сцену и нажмите кнопку. Вы должны получить следующий результат:

../../_images/scripting_hello.png

Поздравляем с написанием сценария к вашей первой сцене.

Примечание

Общим недопониманием в отношении этого урока является то, как работает get_node(path). Для данного узла get_node(path) ищет своих непосредственных детей. В приведенном выше коде это означает, что Button должен быть дочерним элементом Panel. Если бы Button был дочерним элементом Label, код для его получения выглядел бы так:

# Not for this case,
# but just in case.
get_node("Label/Button")
// Not for this case,
// but just in case.
GetNode("Label/Button")

Кроме того, помните, что узлы ссылаются по имени, а не по типу.

Примечание

Правая панель диалога подключения предназначена для привязки определенных значений к параметрам подключенной функции. Вы можете добавлять и удалять значения разных типов.

Если реализовывать это в коде, то можно работать с 4-м параметром Array, который по умолчанию пуст. Для получения дополнительной информации не забудьте ознакомиться с методом Object.connect.