Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
跨语言脚本
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)
using Godot;
public partial class MyCSharpNode : Node
{
public string MyProperty { get; set; } = "my c# value";
[Signal] public delegate void MySignalEventHandler();
[Signal] public delegate void MySignalWithParamsEventHandler(string msg, int n);
public void PrintNodeName(Node node)
{
GD.Print(node.Name);
}
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);
}
}
public void MySignalHandler()
{
GD.Print("The signal handler was called!");
}
public void MySignalWithParamsHandler(string msg, int n)
{
PrintNTimes(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.
访问字段
从 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# 中访问 GDScript
由于 C# 是静态类型语言,在 C# 脚本里访问 GDScript 字段会有点复杂,此时必须使用 Object.Get() 和 Object.Set() 来读写字段,其首个参数为要访问的字段的名称。
// 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"));
需要牢记:在给字段赋值时只能使用 GDScript 已知的类型,实际上指的就是 GDScript 的内置类型 :内置类型 或 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));
继承
GDScript 脚本无法继承 C#脚本。同样,C#脚本也无法继承 GDScript 脚本。由于该机制实现起来非常复杂,故未来不太可能取消此限制,详见该 GitHub Issue。