Scripting de varios lenguajes

Godot permite mezclar lenguajes de script según tus necesidades. Esto quiere decir que un proyecto puede definir nodos en C# y GDScript. Esta página mostrará las posibles interacciones entre dos nodos escritos en diferentes lenguajes.

Los siguientes dos scripts se utilizarán como referencias a lo largo de esta página.

extends Node

var str1 : String = "foo"
var str2 : String setget ,get_str2

func get_str2() -> String:
    return "foofoo"

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)

Instanciando nodos

Si no estás usando nodos del árbol de escena, probablemente quieras instanciar nodos directamente desde código.

Instanciando nodos C# desde GDScript

Usar C# de GDScript no necesita mucho trabajo. Una vez cargado (ver Clases como recursos), el script puede ser instanciado con new().

var my_csharp_script = load("res://path_to_cs_file.cs")
var my_csharp_node = my_csharp_script.new()
print(my_csharp_node.str2) # barbar

Advertencia

Cuando se crea un script .cs, ten siempre en mente que la clase que usará Godot es la que está nombrada como el archivo .cs. Si esa clase no existe en el archivo, verás el siguiente error: Invalid call. Nonexistent function `new` in base.

Por ejemplo, "MyCoolNode.cs"debe contener una clase llamada "MyCoolNode".

También necesitas revisar que tu archivo .cs esté referenciado en el archivo de proyecto``.csproj``. De otro modo sucederá el mismo error.

Instanciando nodos GDScript desde C#

Desde el lado de C#, todo funciona de la misma manera. Una vez cargado, el GDScript puede ser instanciado con GDScript.New().

GDScript MyGDScript = (GDScript) GD.Load("res://path_to_gd_file.gd");
Object myGDScriptNode = (Godot.Object) MyGDScript.New(); // This is a Godot.Object

Aquí usaremos un Object, pero puedes usar conversión de tipos como está explicado en Conversión de tipo y casting.

Accediendo campos

Accediendo campos C# desde GDScript

Acceder a los campos C# desde GDScript es sencillo, no deberías tener nada de qué preocuparte.

print(my_csharp_node.str1) # bar
my_csharp_node.str1 = "BAR"
print(my_csharp_node.str1) # BAR

print(my_csharp_node.str2) # barbar
# my_csharp_node.str2 = "BARBAR" # This line will hang and crash

Nota que no importa si el campo está definido como propiedad o atributo. Sin embargo, tratar de asignar un valor a una propiedad que no define un setter resultará en un crash.

Accediendo a los campos de GDScript desde C#

Como C# es tipado estáticamente, acceder GDScript desde C# es un poco complejo, deberás usar Object.Get() y Object.Set(). El primer argumento es el nombre del campo al que quieres acceder.

GD.Print(myGDScriptNode.Get("str1")); // foo
myGDScriptNode.Set("str1", "FOO");
GD.Print(myGDScriptNode.Get("str1")); // FOO

GD.Print(myGDScriptNode.Get("str2")); // foofoo
// myGDScriptNode.Set("str2", "FOOFOO"); // This line won't do anything

Ten en cuenta que al establecer un valor de campo sólo debes usar los tipos que el lado GDScript conoce. Esencialmente, quieres trabajar con tipos incorporados como se describe en Bases de GDScript o clases que se extienden Object.

Llamando métodos

Llamando métodos C# desde GDScript

Una vez más, llamar a métodos C# desde GDScript debería ser sencillo. El proceso de clasificación hará todo lo posible para convertir los argumentos para que coincidan con las firmas de funciones. Si eso es imposible, verá el siguiente error: Llamada no válida. Función `FunctionName` inexistente.

my_csharp_node.PrintNodeName(self) # myGDScriptNode
# my_csharp_node.PrintNodeName() # This line will fail.

my_csharp_node.PrintNTimes("Hello there!", 2) # Hello there! Hello there!

my_csharp_node.PrintArray(["a", "b", "c"]) # a, b, c
my_csharp_node.PrintArray([1, 2, 3]) # 1, 2, 3

Llamando métodos GDScript desde C#

Para llamar a los métodos de GDScript desde C# necesitarás usar Object.Call(). El primer argumento es el nombre del método que quieres llamar. Los siguientes argumentos se pasarán a dicho método.

myGDScriptNode.Call("print_node_name", this); // my_csharp_node
// myGDScriptNode.Call("print_node_name"); // This line will fail silently and won't error out.

myGDScriptNode.Call("print_n_times", "Hello there!", 2); // Hello there! Hello there!

// When dealing with functions taking a single array as arguments, we need to be careful.
// 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.
String[] arr = new String[] { "a", "b", "c" };
// myGDScriptNode.Call("print_array", arr); // This line will fail silently and won't error out.
myGDScriptNode.Call("print_array", (object)arr); // a, b, c
myGDScriptNode.Call("print_array", (object)new int[] { 1, 2, 3 }); // 1, 2, 3
// Note how the type of each array entry does not matter as long as it can be handled by the marshaller

Advertencia

Como puedes ver, si el primer argumento del método llamado es un array, necesitarás lanzarlo como "object". De lo contrario, cada elemento de tu array será tratado como un único argumento y la firma de la función no coincidirá.

Herencia

Un archivo GDSCript no puede heredar de un script C# del mismo en que un script C# no puede heredar de un archivo GDScript. Debido a la complejidad que llevaría implementarla, es poco probable que esta limitación sea cambiada en el futuro. Ver esta issue en GitHub para más información.