In my previous post I've been playing with Godot's new feature - GDNative. GDNative module allows you to compile native C/C++ code into a library and use it together with your app. You can then call your custom C/C++ code from GDScript transparently as if it would be regular GDScript code. In comparison to regular C++ Godot modules, you don't need to touch Godot's source directly, and you don't need to recompile the engine after every change to your own project.
Besides calling C/C++ code from GDScript, it is also possible to do the opposite - to call GDScript methods from within C/C++ code. Today I would like to show how to do this. There might be more ways how to do this. I'll show you the first thing I've tried.
The following examples extend the code from my previous post, so if something is not clear, checking the previous post and also the official tutorial that the post is based on will probably help.
Create a Callback Method inside GDScript
...
func gdscript_callback(msg):
print ("Called back from native C++ code: " + msg)
...
You can place this method inside of the same script file where you load() your NativeScript .gdns file as described in previous post.
Pass Class Instance that Contains the Callback from GDScript to Native Code
Your custom native C/C++ function registered with GDNative can take parameters from GDScript which are passed to native code as godot_variant. To be able to call a method on a GDScript object, you can pass an instance of this object as parameter.
extends Node2D
onready var agdn = preload("res://lib/android_gdnative.gdns").new()
...
func _ready():
agdn.test(self)
...
Here I've passed the self variable to my test() function that I've created in the previous post. The method gdscript_callback()
shown in the previous step is also defined inside of this same script, therefore I'm passing self variable and not an instance of some other object.
How I changed the test()/android_gdnative_test() implementation from previous post is shown in the following step.
Cache the Instance in Native C/C++ code
I've used the GDNative api function godot_variant_new_copy() to create a copy of the self variable passed from GDScript and stored it inside a godot_variant struct(also named self
). The self variable was passed from GDScript as the first argument - p_args[0]
...
godot_variant self;
godot_variant android_gdnative_test(godot_object *p_instance, void *p_method_data
, void *p_user_data, int p_num_args, godot_variant **p_args)
{
// Cache object that can be used to call our method in GDScript
api->godot_variant_new_copy(&self, p_args[0]);
...
Call the GDScript Method from C/C++ code
Once you have an instance of the class that contains the callback code, you can use following snippet to call it back
...
// Prepare args to pass from native C++ to GDScript
godot_variant arg;
auto msg = api->godot_string_chars_to_utf8("Message from native C++ code");
api->godot_variant_new_string(&arg, &msg);
std::vector<godot_variant*> args{ &arg };
// Call our method in GDScript
auto cb_name = api->godot_string_chars_to_utf8("gdscript_callback");
godot_variant_call_error err;
api->godot_variant_call(&self, &cb_name, (const godot_variant**)args.data(),
args.size(), &err);
...
You can pass arguments from native C/C++ code to GDScript easily as a variant type. GDNative api provides various functions to convert from different types into a godot_variant. In this case I just passed a string as parameter.