跨语言脚本

Godot 允许混合、匹配使用脚本语言以满足你的需求,也就是说,一个项目可以同时用 C# 和 GDScript 定义节点。本页将用不同语言编写的两个脚本来介绍这两种语言之间可进行的交互。

以下两个脚本在整个页面中用作参考。

extends Node

var my_property: String = "my gdscript value":
    get:
        return my_property
    set(value):
        my_property = value

signal my_signal
signal my_signal_with_params(msg: String, n: int)

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_n_times(msg: String, n: int) -> void:
    for i in range(n):
        print(msg)

func my_signal_handler():
    print("The signal handler was called!")

func my_signal_with_params_handler(msg: String, n: int):
    print_n_times(msg, n)

实例化节点

如果不想通过场景树来使用节点,则可能需要直接通过代码来实例化节点。

在 GDScript 中实例化 C# 节点

在 GDScript 中使用 C# 脚本并不麻烦,C# 脚本经加载后(见 类作为资源)便可使用 new() 来进行实例化。

var MyCSharpScript = load("res://Path/To/MyCSharpNode.cs")
var my_csharp_node = MyCSharpScript.new()

警告

创建 .cs 脚本时,要始终记住:Godot 会使用和这个 .cs 文件名相同的类进行相关操作。如果文件中不存在该类,那么你将会看到以下错误: Invalid call. Nonexistent function `new` in base

例如:MyCoolNode.cs 应该包含一个名为 MyCoolNode 的类。

C# 类也需要获取 Godot 类,如GodotObject,否则将触发同样的错误。

你还需要检查在项目的 .csproj 文件中是否引用了该 .cs 文件的内容,否则将触发同样的错误。

在 C# 中实例化 GDScript 节点

在 C# 侧的实例化方式与 GDScript 的基本相同,加载 GDScript 脚本后,该 GDScript 脚本就可以使用GDScript.New()实例化。

var myGDScript = GD.Load<GDScript>("res://path/to/my_gd_script.gd");
var myGDScriptNode = (GodotObject)myGDScript.New(); // This is a GodotObject.

在这里我们用 Object 进行转型,但是也可以使用 Godot 所提供的类型转换语法转型,见类型转换和强制转换章节。

访问字段

从 GDScript 中访问 C# 字段

从 GDScript 访问 C# 字段非常简单,大可不必担心会出现什么问题。

# Output: "my c# value".
print(my_csharp_node.MyProperty)
my_csharp_node.MyProperty = "MY C# VALUE"
# Output: "MY C# VALUE".
print(my_csharp_node.MyProperty)

从 C# 中访问 GDSscript

As C# is statically typed, accessing GDScript from C# is a bit more convoluted. You will have to use GodotObject.Get() and GodotObject.Set(). The first argument is the name of the field you want to access.

// Output: "my gdscript value".
GD.Print(myGDScriptNode.Get("my_property"));
myGDScriptNode.Set("my_property", "MY GDSCRIPT VALUE");
// Output: "MY GDSCRIPT VALUE".
GD.Print(myGDScriptNode.Get("my_property"));

Keep in mind that when setting a field value you should only use types the GDScript side knows about. Essentially, you want to work with built-in types as described in 内置类型 or classes extending Object.

调用方法

在 GDScript 中调用 C# 方法

在 GDScript 里调用 C# 方法同样非常简单,调用 C# 脚本的方法时将尽可能地将你的参数类型进行强制转型以匹配函数签名。如果调用失败,则会看到以下错误 Invalid call. Nonexistent function `FunctionName`

# Output: "my_gd_script_node" (or name of node where this code is placed).
my_csharp_node.PrintNodeName(self)
# This line will fail.
# my_csharp_node.PrintNodeName()

# Outputs "Hello there!" twice, once per line.
my_csharp_node.PrintNTimes("Hello there!", 2)

# Output: "a", "b", "c" (one per line).
my_csharp_node.PrintArray(["a", "b", "c"])
# Output: "1", "2", "3"  (one per line).
my_csharp_node.PrintArray([1, 2, 3])

从 C# 中 调用 GDScript 方法

在 C# 脚本中调用 GDScript 脚本的方法时需要使用 Object.Call() 函数,该方法的第一个参数为想要调用方法的名称,之后的其他参数会顺次传递给被调用的方法。

// Output: "MyCSharpNode" (or name of node where this code is placed).
myGDScriptNode.Call("print_node_name", this);
// This line will fail silently and won't error out.
// myGDScriptNode.Call("print_node_name");

// Outputs "Hello there!" twice, once per line.
myGDScriptNode.Call("print_n_times", "Hello there!", 2);

string[] arr = ["a", "b", "c"];
// Output: "a", "b", "c" (one per line).
myGDScriptNode.Call("print_array", arr);
// Output: "1", "2", "3"  (one per line).
myGDScriptNode.Call("print_array", new int[] { 1, 2, 3 });
// Note how the type of each array entry does not matter
// as long as it can be handled by the marshaller.

连接信号

在 GDScript 中连接 C# 信号

在 GDScript 中连接 C# 信号和连接 GDScript 中定义的信号是一样的:

my_csharp_node.MySignal.connect(my_signal_handler)

my_csharp_node.MySignalWithParams.connect(my_signal_with_params_handler)

在 C# 中连接 GDScript 信号

在 C# 中只能通过 Connect 方法连接 GDScript 信号,因为 GDScript 定义的信号并没有对应的 C# 静态类型:

myGDScriptNode.Connect("my_signal", Callable.From(MySignalHandler));

myGDScriptNode.Connect("my_signal_with_params", Callable.From<string, int>(MySignalWithParamsHandler));

继承

A GDScript file may not inherit from a C# script. Likewise, a C# script may not inherit from a GDScript file. Due to how complex this would be to implement, this limitation is unlikely to be lifted in the future. See this GitHub issue for more information.