跨语言脚本

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.

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

GDScript

C#

  1. extends Node
  2. var str1 : String = "foo"
  3. var str2 : String setget ,get_str2
  4. func get_str2() -> String:
  5. return "foofoo"
  6. func print_node_name(node : Node) -> void:
  7. print(node.get_name())
  8. func print_array(arr : Array) -> void:
  9. for element in arr:
  10. print(element)
  11. func print_x_times(msg : String, n : int) -> void:
  12. for i in range(n):
  13. print(msg)
  1. public class MyCSharpNode : Node
  2. {
  3. public String str1 = "bar";
  4. public String str2 { get { return "barbar"; } }
  5. public void PrintNodeName(Node node)
  6. {
  7. GD.Print(node.GetName());
  8. }
  9. public void PrintArray(String[] arr)
  10. {
  11. foreach (String element in arr)
  12. {
  13. GD.Print(element);
  14. }
  15. }
  16. public void PrintNTimes(String msg, int n)
  17. {
  18. for (int i = 0; i < n; ++i)
  19. {
  20. GD.Print(msg);
  21. }
  22. }
  23. }

实例化节点

如果不使用场景树中的节点,则可能需要直接从代码实例化节点。

在 GDScript 中实例化 C# 节点

Using C# from GDScript doesn’t need much work. Once loaded (see 类作为资源), the script can be instantiated with new().

  1. var my_csharp_script = load("res://path_to_cs_file.cs")
  2. var my_csharp_node = my_csharp_script.new()
  3. 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.

在C#中实例化GDScript节点

在 C# 端,所有的工作方式相同。加载后,GDScript 可以被示例化,使用 GDScript.New()

  1. GDScript MyGDScript = (GDScript) GD.Load("res://path_to_gd_file.gd");
  2. 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 类型转换和强制转换.

访问字段

从 GDScript 中访问 C# 字段

从GDScript访问 C# 字段很简单,没什么可担心的。

  1. print(my_csharp_node.str1) # bar
  2. my_csharp_node.str1 = "BAR"
  3. print(my_csharp_node.str1) # BAR
  4. print(my_csharp_node.str2) # barbar
  5. # 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.

从 C# 中访问 GDSscript

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

  1. GD.Print(myGDScriptNode.Get("str1")); // foo
  2. myGDScriptNode.Set("str1", "FOO");
  3. GD.Print(myGDScriptNode.Get("str1")); // FOO
  4. GD.Print(myGDScriptNode.Get("str2")); // foofoo
  5. // myGDScriptNode.Set("str2", "FOOFOO"); // This line won't do anything

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 GDScript 基础 or classes extending Object.

调用方法

在GDScript中调用C#方法

Again, calling C# methods from GDScript should be straightforward. The marshalling process will do its best to cast the arguments to match function signatures. If that’s impossible, you’ll see the following error: Invalid call. Nonexistent function `FunctionName` .

  1. my_csharp_node.PrintNodeName(self) # myGDScriptNode
  2. # my_csharp_node.PrintNodeName() # This line will fail.
  3. my_csharp_node.PrintNTimes("Hello there!", 2) # Hello there! Hello there!
  4. my_csharp_node.PrintArray(["a", "b", "c"]) # a, b, c
  5. my_csharp_node.PrintArray([1, 2, 3]) # 1, 2, 3

从 C# 中 调用 GDScript 方法

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.

  1. myGDScriptNode.Call("print_node_name", this); // my_csharp_node
  2. // myGDScriptNode.Call("print_node_name"); // This line will fail silently and won't error out.
  3. myGDScriptNode.Call("print_n_times", "Hello there!", 2); // Hello there! Hello there!
  4. // When dealing with functions taking a single array as arguments, we need to be careful.
  5. // 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.
  6. String[] arr = new String[] { "a", "b", "c" };
  7. // myGDScriptNode.Call("print_array", arr); // This line will fail silently and won't error out.
  8. myGDScriptNode.Call("print_array", (object)arr); // a, b, c
  9. myGDScriptNode.Call("print_array", (object)new int[] { 1, 2, 3 }); // 1, 2, 3
  10. // 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#脚本继承。同样地,C#脚本可能无法从GDScript文件继承。由于实现起来非常复杂,因此将来不太可能取消此限制。详见`这个 GitHub issue <https://github.com/godotengine/godot/issues/38352>`__ 。