Cross-language scripting

Godot allows you to mix and match scripting languages to suit your needs. This means a single project can define nodes in both C# and GDScript. This page will go through the possible interactions between two nodes written in different languages.

Следующие два скрипта будут использоваться в качестве примера на этой странице.

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 nodes

Если вы не используете узлы из дерева сцены, вы, вероятно, захотите создать экземпляры узлов непосредственно из кода.

Instantiating C# nodes from GDScript

Using C# from GDScript doesn't need much work. Once loaded (see Классы как ресурсы), the script can be instantiated with 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

Предупреждение

When creating .cs scripts, you should always keep in mind that the class Godot will use is the one named like the .cs file itself. If that class does not exist in the file, you'll see the following error: Invalid call. Nonexistent function `new` in base.

Например, MyCoolNode.cs должен содержать класс с именем MyCoolNode.

You also need to check your .cs file is referenced in the project's .csproj file. Otherwise, the same error will occur.

Создание узлов GDScript из C#

Со стороны C# все работает точно также. После загрузки GDScript может быть создан с помощью GDScript.New().

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

Here we are using an Object, but you can use type conversion like explained in Type conversion and casting.

Доступ к полям

Доступ к полям 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

Note that it doesn't matter if the field is defined as a property or an attribute. However, trying to set a value on a property that does not define a setter will result in a 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.

Calling methods

Calling C# methods from GDScript

Again, calling C# methods from GDScript should be straightforward. The marshalling process will do its best to cast your the arguments to match function signatures. If that's impossible, you'll see the following error: Invalid call. Nonexistent function `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#

To call GDScript methods from C# you'll need to use Object.Call(). The first argument is the name of the method you want to call. The following arguments will be passed to said method.

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

Предупреждение

As you can see, if the first argument of the called method is an array, you'll need to cast it as object. Otherwise, each element of your array will be treated as a single argument and the function signature won't match.

Наследование

GDScript файлы не могу наследоваться от C# скриптов, аналогично и обратное. Из-за того, что такое сложно реализовать, это ограничение вряд ли будет снято в будущем. Для более подробной информации смотрите GitHub <https://github.com/godotengine/godot/issues/38352>.