Багатомовні скрипти

Godot дозволяє змішувати та поєднувати мови скриптів відповідно до ваших потреб. Це означає, що один проект може визначати вузли як у C#, так і в GDScript. Ця сторінка продемонструє можливі взаємодії між двома вузлами, написаними різними мовами.

Наступні два скрипти використовуватимуться як приклад на цій сторінці.

extends Node

var str1 : String = "foo"
var str2 : String setget ,get_str2

func get_str2() -> String:
    return "foofoo"

func print_node_name(node : Node) -> void:
    print(node.get_name())

func print_array(arr : Array) -> void:
    for element in arr:
        print(element)

func print_x_times(msg : String, n : int) -> void:
    for i in range(n):
        print(msg)
public class MyCSharpNode : Node
{
    public String str1 = "bar";
    public String str2 { get { return "barbar"; } }

    public void PrintNodeName(Node node)
    {
        GD.Print(node.GetName());
    }

    public void PrintArray(String[] arr)
    {
        foreach (String element in arr)
        {
            GD.Print(element);
        }
    }

    public void PrintNTimes(String msg, int n)
    {
        for (int i = 0; i < n; ++i)
        {
            GD.Print(msg);
        }
    }
}

Вставка екземплярів (Instantiating) вузлів

Якщо ви не використовуєте вузли з дерева сцени, ви, ймовірно, захочете вставляти їх екземляри (instantiate) безпосередньо з коду.

Вставка екземплярів (Instantiating) вузлів C# на GDScript

Використання C# на GDScript не потребує великих зусиль. Після завантаження (дивіться Класи як ресурси) скрипт може бути вставлений з допомогою new().

var my_csharp_script = load("res://path_to_cs_file.cs")
var my_csharp_node = my_csharp_script.new()
print(my_csharp_node.str2) # barbar

Попередження

Створюючи скрипти .cs, ви завжди повинні мати на увазі, що клас, який використовуватиме Godot, називається так же, як сам файл .cs. Якщо клас не існує в файлі, ви побачите наступне повідомлення про помилку: Invalid call. Nonexistent function `new` in base (Помилковий виклик. Не знайдено функцію new у базі).

Наприклад, MyCoolNode.cs повинен містити клас під назвою MyCoolNode.

Вам також потрібно перевірити, чи ваш файл .cs посилається на файл проекту .csproj. Інакше відбудеться та сама помилка.

Вставка екземплярів (Instantiating) вузлів GDScript на C#

З боку C# все працює так само. Після завантаження, GDScript може бути вставлений (instantiated) з GDScript.New ().

GDScript MyGDScript = (GDScript) GD.Load("res://path_to_gd_file.gd");
Object myGDScriptNode = (Godot.Object) MyGDScript.New(); // This is a Godot.Object

Тут ми використовуємо Object, але ви можете використовувати перетворення типів, як пояснено в Перетворення типів і кастинг.

Доступ до полів

Доступ до полів C# з GDScript

Доступ до полів C# з GDScript нескладний, вам нема про що хвилюватися.

print(my_csharp_node.str1) # bar
my_csharp_node.str1 = "BAR"
print(my_csharp_node.str1) # BAR

print(my_csharp_node.str2) # barbar
# my_csharp_node.str2 = "BARBAR" # This line will hang and crash

Зауважте, що не має значення, чи визначається поле як властивість, чи атрибут, але спроба встановити значення для властивості, яку не визначає сеттер, призведе до збою.

Доступ до полів GDScript з C#

Оскільки C# статично типізований, доступ до GDScript з C# трохи складніший, вам доведеться використовувати Object.Get() та Object.Set(). Перший аргумент - це ім'я поля, до якого ви хочете отримати доступ.

GD.Print(myGDScriptNode.Get("str1")); // foo
myGDScriptNode.Set("str1", "FOO");
GD.Print(myGDScriptNode.Get("str1")); // FOO

GD.Print(myGDScriptNode.Get("str2")); // foofoo
// myGDScriptNode.Set("str2", "FOOFOO"); // This line won't do anything

Майте на увазі, що при встановленні значення поля слід використовувати лише типи, про які знає сторона GDScript. По суті, ви хочете працювати з вбудованими типами, як описано Основи GDScript, або класах, що розширюють Object.

Методи виклику

Виклик методів C# з GDScript

Знову ж таки, виклик методів C# з GDScript повинен бути простим. Процес маршування зробить все можливе, щоб привести аргументи до відповідності підписів функцій. Якщо це неможливо, ви побачите наступне повідомлення про помилку: Invalid call. Nonexistent function `FunctionName` (Помилковий виклик. Не знайдено функцію FunctionName).

my_csharp_node.PrintNodeName(self) # myGDScriptNode
# my_csharp_node.PrintNodeName() # This line will fail.

my_csharp_node.PrintNTimes("Hello there!", 2) # Hello there! Hello there!

my_csharp_node.PrintArray(["a", "b", "c"]) # a, b, c
my_csharp_node.PrintArray([1, 2, 3]) # 1, 2, 3

Виклик методів GDScript з C#

Для виклику методів GDScript з C# вам потрібно буде використовувати Object.Call(). Перший аргумент - це назва методу, який ви хочете викликати. Наступні аргументи будуть передані вказаному методу.

myGDScriptNode.Call("print_node_name", this); // my_csharp_node
// myGDScriptNode.Call("print_node_name"); // This line will fail silently and won't error out.

myGDScriptNode.Call("print_n_times", "Hello there!", 2); // Hello there! Hello there!

// When dealing with functions taking a single array as arguments, we need to be careful.
// If we don't cast it into an object, the engine will treat each element of the array as a separate argument and the call will fail.
String[] arr = new String[] { "a", "b", "c" };
// myGDScriptNode.Call("print_array", arr); // This line will fail silently and won't error out.
myGDScriptNode.Call("print_array", (object)arr); // a, b, c
myGDScriptNode.Call("print_array", (object)new int[] { 1, 2, 3 }); // 1, 2, 3
// Note how the type of each array entry does not matter as long as it can be handled by the marshaller

Попередження

Як бачите, якщо перший аргумент викликаного методу є масивом, вам потрібно буде надати його як object. Інакше кожен елемент вашого масиву буде розглядатися як єдиний аргумент, і signature функції не збігатиметься.

Успадкування

Файл GDScript може не успадковуватися від скрипта C#. Подібним чином скрипт C# може не успадковуватись із файлу GDScript. Через те, наскільки складним буде це впровадження, це обмеження навряд чи буде знято в майбутньому. Для отримання додаткової інформації ознайомтеся з цією проблемою на GitHub.