Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Scripting entre linguagens

O Godot permite que você misture e combine linguagens de script para atender às suas necessidades. Isso significa que um único projeto pode definir nós tanto em C# quanto em GDScript. Esta página passará pelas possíveis interações entre dois nós escritos em diferentes linguagens.

Os dois scripts a seguir serão usados como referências ao longo desta página.

extends Node

var my_property: String = "my gdscript value":
    get:
        return my_property
    set(value):
        my_property = value

signal my_signal
signal my_signal_with_params(msg: String, n: int)

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)

func my_signal_handler():
    print("The signal handler was called!")

func my_signal_with_params_handler(msg: String, n: int):
    print_n_times(msg, n)

Instanciando nós

Se você não estiver usando nós da árvore da cena, provavelmente vai querer instanciar os nós diretamente do código.

Instanciando nós C# a partir do GDScript

Usar C# a partir do GDScript não precisa de muito trabalho. Uma vez carregado (veja Classes como recursos) o script pode ser instanciado com new().

var MyCSharpScript = load("res://Path/To/MyCSharpNode.cs")
var my_csharp_node = MyCSharpScript.new()

Aviso

Ao criar scripts .cs você deve sempre ter em mente que a classe que o Godot usará é a nomeada como o próprio arquivo .cs. Se essa classe não existir no arquivo, você verá o seguinte erro: Chamada inválida. Função inexistente `new` na base.

Por exemplo, MyCoolNode.cs deve conter uma classe chamada MyCoolNode.

A classe C# precisa derivar de uma classe Godot, por exemplo GodotObject. Caso contrário, o mesmo erro ocorrerá.

Você também precisa verificar se seu arquivo .cs é referenciado no arquivo .csproj do projeto. Caso contrário, o mesmo erro ocorrerá.

Instanciando nós GDScript a partir do C#

Do lado C#, tudo funciona da mesma maneira. Uma vez carregado, um GDScript pode ser instanciado com GDScript.New().

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

Aqui estamos usando um Object mas você pode usar conversão de tipo como explicado em Conversão de Tipos e Casting.

Acessando campos

Acessando campos C# a partir do GDScript

Acessar os campos do C# no GDScript é simples, você não deve ter nada com que se preocupar.

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

Acessando campos do GDScript no C#

Como C# é estaticamente tipado, acessar GDScript a partir de C# é um pouco mais complexo. Você terá que usar GodotObject.Get() e GodotObject.Set(). O primeiro argumento é o nome do campo que você deseja acessar.

// 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"));

Tenha em mente que, ao definir o valor de um campo, você deve usar apenas tipos que o lado do GDScript conhece. Essencialmente, você quer trabalhar com tipos nativos conforme descrito em Tipos definidos por padrão ou classes que estendem Object.

Chamando métodos

Chamando métodos C# a partir do GDScript

Novamente, chamar métodos de C# no GDScript deve ser simples. O processo de marshalling fará o seu melhor para converter seu argumento para bater com as assinaturas de funções. Se isso for impossível, você verá o seguinte erro: Chamada inválida. Função inexistente `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])

Chamando métodos de GDScript no C#

Para chamar métodos de GDScript a partir de C#, você precisará usar GodotObject.Call(). O primeiro argumento é o nome do método que você deseja chamar. Os argumentos a seguir serão passados para o referido método.

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

Conectando-se a sinais

Conectando a sinais C# a partir de GDScript

Conectar-se a um sinal de C# a partir do GDScript é o mesmo que se conectar a um sinal definido no GDScript:

my_csharp_node.MySignal.connect(my_signal_handler)

my_csharp_node.MySignalWithParams.connect(my_signal_with_params_handler)

Conectando a sinais GDScript a partir de C#

Conectar-se a um sinal de GDScript a partir do C# só funciona com o método Connect porque não existem tipos estáticos em C# para sinais definidos pelo GDScript:

myGDScriptNode.Connect("my_signal", Callable.From(MySignalHandler));

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

Herança

Um arquivo GDscript não pode herdar de um script em C#. De forma semelhante, um script C# também não pode herdar de um arquivo GDscript. Devido a complexidade de sua implementação, essa limitação tem poucas chances de permanecer no futuro. Veja esse problema na plataforma GitHub para mais informações.