Interacting with GD Script from C# (And The Reverse)

Hey guys, today we are going to talk about how to call GD Script code from C# and vise versa! This is an important part using C# inside of Godot because GD Script being the main supported language there is lots of features that are not available for C#.

C# GD Script support works by calling the method though the C++ code though a wrapper. This is very useful because it allow us to have interlanguage interoperability and we get all the advantages of C# with the flexibility of GD Script.

Getting Into Godot

First we will demonstrate how to call code from another node. We need to create a Node2D and to that Node2D we need to create a script, lets name it ToGDScript and we will make it a C# script and it will open Visual Studio Code. Now that we have that done we need to right click our Node2D and add a child node and attach a new script to it as well, lets call it GDScriptSample.

Calling GD Script using the Call Method Through Nodes

First we will need to create a var we will call it GD Script and we will assign it using find node. From here we can use the Call method followed by the functions name since we dont have a function to call yet lets just leave it blank.

public override void _Ready()
    {
var gdscript = FindNode("GDScript");
var returndata = gdscript.Call("from_cs", "Hello C# worked!");
GD.Print(returndata);
}

	func from_cs(name):
		print(name)
		return "from_cs worked!"

Now that we have our C# function set up lets go over to our GD Script script and lets add a function. This function will take in a value we will call it name and it will print that name. If we run our project it will go ahead and print “hello C# worked!” and it will take that return data from cs worked and print that value!

Calling Static Functions In GD Script using the Call Method

Using a static function will allow us to call the functions without having to add GD Script to our scene. This is huge because it allows us to have lots of flexibility with our coding.

Lets go back to our GDScriptSample.GD file and add a static function called print data(data) and we will go ahead and print the data.

	static func printData(data):
		print(data)

We will now go to our C# script, go into our ready fucntion and add in some code to load our script with ResourceLoader. When loading our script from resources we need to cast it using the as keyword, from here we can call the function we want using the call function like we did above!

Script gdclass = ResourceLoader.Load("res://GDScriptSample.gd") as Script;
gdclass.Call("printData", "Print Data Has Worked!");

From here you should see it work!

Calling C# Functions Though Nodes Using GD Script

Just like above we need to create a new node to pull our C# functions from, so lets create a node under our GDScript Node2D and lets name it CSharp . This will allow us to reference it in the below code.

Lets create a C# script and call it CSharpExample.cs we will create a few functions for this the first one will only print the values that are sent to it.


    public bool printCS(string print){
        GD.Print(print);
        return true;
    }
func _ready():
		var cs_node = $CSharp
		var ret = cs_node.printCS("hello from GD script")
		print(ret)

Much like before we need to go ahead and get a reference to our CSharp node. Once we have that we can go ahead and call it by calling the method itself. The nice thing about GD Script is it will automatically wrap our C# function so we don’t have to.

Once we run this function it will go ahead and print hello from GD script meaning it worked! You may notice that the GD Script scripts seem to run before the C# scripts in the execution order! This is interesting and a good thing to know!

Calling C# Static Functions Though Using GD Script

public static void PrintCSDemo(string print){
        GD.Print(print);
}

From here lets open up our CSharpExample.cs and add the following to the script.

This will allow us to have the function as a static function and allow it to be called without a node.

Much like before we can go to our GDScriptSample.gd and add the following to our ready function. This will allow us to load the resource script and call our function directly! This is very useful since we wont need to have our script in our scene to call it!

You can see it works!

var cs_class = preload("res://CSharpExample.cs")
cs_class.PrintCSDemo("hell from Static GD Script")

Final Scripts

Our final scripts are simple but very powerful.

CSharpExample.cs

using Godot;
using System;

public class CSharpExample : Node2D
{
    // Declare member variables here. Examples:
    // private int a = 2;
    // private string b = "text";

    // Called when the node enters the scene tree for the first time.
    public override void _Ready()
    {
        
    }

//  // Called every frame. 'delta' is the elapsed time since the previous frame.
//  public override void _Process(float delta)
//  {
//      
//  }

    public bool printCS(string print){
        GD.Print(print);
        return true;
    }

    public static void PrintCSDemo(string print){
        GD.Print(print);
    }
}

ToGDScript.CS

using Godot;
using System;

public class ToGDScript : Node2D
{
    // Declare member variables here. Examples:
    // private int a = 2;
    // private string b = "text";

    // Called when the node enters the scene tree for the first time.
    public override void _Ready()
    {
        var gdscript = FindNode("GDScript");
        var returndata = gdscript.Call("from_cs", "Hello C# worked!");
        GD.Print(returndata);
        Script gdclass = ResourceLoader.Load("res://GDScriptSample.gd") as Script;
        gdclass.Call("printData", "Print Data Has Worked!");
        
    }

//  // Called every frame. 'delta' is the elapsed time since the previous frame.
//  public override void _Process(float delta)
//  {
//      
//  }
}

GDScriptSample.gd


class GDScriptSample extends Node2D:

	# Declare member variables here. Examples:
	# var a = 2
	# var b = "text"


	# Called when the node enters the scene tree for the first time.
	func _ready():
		var cs_node = $CSharp
		var ret = cs_node.printCS("hello from GD script")
		print(ret)
		var cs_class = preload("res://CSharpExample.cs")
		cs_class.PrintCSDemo("hell from Static GD Script")
		pass # Replace with function body.


	# Called every frame. 'delta' is the elapsed time since the previous frame.
	#func _process(delta):
	#	pass

	func from_cs(name):
		print(name)
		return "from_cs worked!"

	static func printData(data):
		print(data)

Conclusion

This is an amazing thing! It allows us to get the advantages of both sides of the two languages. We can get the power of C# with the flexibility of GD Script just by calling each other. Its simple and easy to use and haves almost no downsides. The only major downside I have found doing this method is its slightly slower then calling code directly in here own language, however having flexibility is the most important thing in my opinion.

Companion Video

Leave a Reply

Your email address will not be published. Required fields are marked *