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# 並不麻煩。腳本載入後(參見 以類別當作資源),即可直接用 new() 來實例化。
var MyCSharpScript = load("res://Path/To/MyCSharpNode.cs")
var my_csharp_node = MyCSharpScript.new()
警告
建立 .cs 腳本時,請務必確認類別名稱與 .cs 檔案名稱一致。若檔案內沒有同名類別,會出現這個錯誤:「Invalid call. Nonexistent function new in base」。
例如,MyCoolNode.cs 應包含名為 MyCoolNode 的類別。
C# 類別必須繼承自 Godot 的類別,例如 GodotObject。否則也會發生相同的錯誤。
你還要確認 .cs 檔案已經在專案的 .csproj 檔案中被正確引用。否則也會出現相同的錯誤。
從 C# 實例化 GDScript 節點
在 C# 端,流程也是一樣。腳本載入後,可以用 GDScript.New() 來實例化 GDScript。
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 欄位會稍微麻煩些。你需要使用 GodotObject.Get() 及 GodotObject.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 端所認得的型別。基本上,你應使用 內建型別 中描述的內建型別,或是繼承自 Object 的類別。
呼叫方法
從 GDScript 呼叫 C# 方法
同樣地,從 GDScript 呼叫 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 方法,需使用 GodotObject.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# 連接到 GDScript 訊號時,只能用 Connect 方法,因為 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。