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 writtenin different languages.

The following two scripts will be used as references throughout this page.

extendsNodevarmy_property:String="my gdscript value":get:returnmy_propertyset(value):my_property=valuesignalmy_signalsignalmy_signal_with_params(msg:String,n:int)funcprint_node_name(node:Node)->void:print(node.get_name())funcprint_array(arr:Array)->void:forelementinarr:print(element)funcprint_n_times(msg:String,n:int)->void:foriinrange(n):print(msg)funcmy_signal_handler():print("The signal handler was called!")funcmy_signal_with_params_handler(msg:String,n:int):print_n_times(msg,n)

Instantiating nodes

If you're not using nodes from the scene tree, you'll probably want toinstantiate nodes directly from the code.

Instantiating C# nodes from GDScript

Using C# from GDScript doesn't need much work. Once loaded(seeClasses as resources), the script can be instantiatedwithnew().

varMyCSharpScript=load("res://Path/To/MyCSharpNode.cs")varmy_csharp_node=MyCSharpScript.new()

Warning

When creating.cs scripts, you should always keep in mind that the classGodot will use is the one named like the.cs file itself. If that classdoes not exist in the file, you'll see the following error:Invalidcall.Nonexistentfunction`new`inbase.

For example, MyCoolNode.cs should contain a class named MyCoolNode.

The C# class needs to derive a Godot class, for exampleGodotObject.Otherwise, the same error will occur.

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

Instantiating GDScript nodes from C#

From the C# side, everything work the same way. Once loaded, the GDScript canbe instantiated withGDScript.New().

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

Here we are using anObject, but you can use type conversion likeexplained inType conversion and casting.

Accessing fields

Accessing C# fields from GDScript

Accessing C# fields from GDScript is straightforward, you shouldn't haveanything to worry about.

# 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)

Accessing GDScript fields from C#

As C# is statically typed, accessing GDScript from C# is a bit moreconvoluted. You will have to useGodotObject.Get()andGodotObject.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 theGDScript side knows about.Essentially, you want to work with built-in types as described inBuilt-in types or classes extendingObject.

Calling methods

Calling C# methods from GDScript

Again, calling C# methods from GDScript should be straightforward. Themarshalling process will do its best to cast the arguments to matchfunction signatures.If that's impossible, you'll see the following error:Invalidcall.Nonexistentfunction`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])

Calling GDScript methods from C#

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

// 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",newint[]{1,2,3});// Note how the type of each array entry does not matter// as long as it can be handled by the marshaller.

Connecting to signals

Connecting to C# signals from GDScript

Connecting to a C# signal from GDScript is the same as connecting to a signaldefined in GDScript:

my_csharp_node.MySignal.connect(my_signal_handler)my_csharp_node.MySignalWithParams.connect(my_signal_with_params_handler)

Connecting to GDScript signals from C#

Connecting to a GDScript signal from C# only works with theConnect methodbecause no C# static types exist for signals defined by GDScript:

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

Inheritance

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


User-contributed notes

Please read theUser-contributed notes policy before submitting a comment.