Funcionalidades do C#

Esta página fornece uma visão geral sobre os recursos comumente usados no C# e no Godot e como eles são usados juntos.

Conversão de Tipos e Casting

C# é uma linguagem estaticamente tipada. Portanto, você não pode fazer o seguinte:

var mySprite = GetNode("MySprite");
mySprite.SetFrame(0);

O método GetNode() retorna uma instância do Node. Você deve explicitamente converter para o tipo derivado desejado, Sprite neste caso.

Para isso, você tem várias opções em C#.

Casting e Verificação de Tipo

Lança InvalidCastException se o nó retornado não puder ser convertido em Sprite. Você o usaria em vez do operador as se tiver certeza de que não falhará.

Sprite mySprite = (Sprite)GetNode("MySprite");
mySprite.SetFrame(0);

Usando o operador AS

O operador as retorna null se o nó não pode ser convertido para Sprite, e por esta razão, não pode ser usado com tipos de valor.

Sprite mySprite = GetNode("MySprite") as Sprite;
// Only call SetFrame() if mySprite is not null
mySprite?.SetFrame(0);

Usando os métodos genéricos

Métodos genéricos também são providenciados para fazer esse tipo de conversão transparente.

GetNode<T>() faz a conversão do nó antes de retorná-lo. Um erro do tipo InvalidCastException será retornado caso o nó não possa ser convertido para o tipo desejado.

Sprite mySprite = GetNode<Sprite>("MySprite");
mySprite.SetFrame(0);

GetNodeOrNull<T>() usa o operador as e retornará null se o código não puder ser convertido para o tipo desejado.

Sprite mySprite = GetNodeOrNull<Sprite>("MySprite");
// Only call SetFrame() if mySprite is not null
mySprite?.SetFrame(0);

Verificação de tipo usando o operador IS

Para verificar se o nó pode ser fundido para Sprite, você pode usar o operador is. O operador is retorna falso se o nó não pode ser fundido para Sprite, caso contrário, ele retorna verdadeiro.

if (GetNode("MySprite") is Sprite)
{
    // Yup, it's a sprite!
}

Para uma verificação de tipos mais avançada, você pode procurar em Correspondência de Padrões.

Sinais em C#

Para um exemplo completo de C#, veja a seção Manipulando um sinal no tutorial passo a passo Linguagens de script.

A declaração de um sinal em C# é feito com o atributo [Signal] em um delegate.

[Signal]
delegate void MySignal();

[Signal]
delegate void MySignalWithArguments(string foo, int bar);

Esses sinais podem então ser conectados no editor ou no código com Connect. Se você quiser conectar um sinal no editor, você precisa (re)build as DLLs do projeto para ver o novo sinal. Esta compilação pode ser acionada manualmente clicando no botão "Build" no canto superior direito da janela do editor.

public void MyCallback()
{
    GD.Print("My callback!");
}

public void MyCallbackWithArguments(string foo, int bar)
{
    GD.Print("My callback with: ", foo, " and ", bar, "!");
}

public void SomeFunction()
{
    instance.Connect("MySignal", this, "MyCallback");
    instance.Connect(nameof(MySignalWithArguments), this, "MyCallbackWithArguments");
}

A emissão de sinais é feita com o método EmitSignal.

public void SomeFunction()
{
    EmitSignal(nameof(MySignal));
    EmitSignal("MySignalWithArguments", "hello there", 28);
}

Observe que você sempre pode referenciar um nome de sinal com a palavra-chave nameof (aplicada no próprio delegate).

É possível vincular valores ao estabelecer uma conexão, passando uma matriz Godot.

public int Value { get; private set; } = 0;

private void ModifyValue(int modifier)
{
    Value += modifier;
}

public void SomeFunction()
{
    var plusButton = (Button)GetNode("PlusButton");
    var minusButton = (Button)GetNode("MinusButton");

    plusButton.Connect("pressed", this, "ModifyValue", new Godot.Collections.Array { 1 });
    minusButton.Connect("pressed", this, "ModifyValue", new Godot.Collections.Array { -1 });
}

Sinais suportam parâmetros e valores vinculados de todos os tipos internos e Classes derivadas de Godot.Object. Consequentemente, qualquer Node ou Reference será compatível automaticamente, mas os objetos de dados personalizados precisarão ser estendidos de Godot.Object ou de uma de suas subclasses.

public class DataObject : Godot.Object
{
    public string Field1 { get; set; }
    public string Field2 { get; set; }
}

Finalmente, os sinais podem ser criados chamando AddUserSignal, mas esteja ciente de que ele deve ser executado antes de qualquer uso de tais sinais (com Connect ou EmitSignal).

public void SomeFunction()
{
    AddUserSignal("MyOtherSignal");
    EmitSignal("MyOtherSignal");
}

Definições de pré-processamento

Godot tem um conjunto de definições que permite a você mudar seu código C# dependendo do ambiente para o qual está compilando.

Nota

Se você criou seu projeto antes do Godot 3.2, você tem que modificar ou regenerar seu arquivo csproj para utilizar esta funcionalidade (compare <DefineConstants>` com um novo projeto 3.2+).

Exemplos

Por exemplo, você pode alterar o código baseado na plataforma:

    public override void _Ready()
    {
#if GODOT_SERVER
        // Don't try to load meshes or anything, this is a server!
        LaunchServer();
#elif GODOT_32 || GODOT_MOBILE || GODOT_WEB
        // Use simple objects when running on less powerful systems.
        SpawnSimpleObjects();
#else
        SpawnComplexObjects();
#endif
    }

Ou você pode detectar em qual engine seu código está, útil para fazer bibliotecas cross-engine:

    public void MyPlatformPrinter()
    {
#if GODOT
        GD.Print("This is Godot.");
#elif UNITY_5_3_OR_NEWER
        print("This is Unity.");
#else
        throw new InvalidWorkflowException("Only Godot and Unity are supported.");
#endif
    }

Lista completa de definições

  • GODOT é sempre definido para projetos Godot.

  • Um dos GODOT_64 ou GODOT_32 são definidos dependendo se a arquitetura é 64-bit ou 32-bit.

  • Um dos GODOT_X11, GODOT_WINDOWS, GODOT_OSX, GODOT_ANDROID, GODOT_IOS, GODOT_HTML5, ou GODOT_SERVER dependendo do SO. Esses nomes podem mudar no futuro. Estes são criados a partir do método get_name() do singleton OS, mas nem todo SO possível que o método retorna é um SO que Godot com o Mono é executado.

Ao exportar, o seguinte também pode ser definido dependendo das características de exportação:

  • Um dos GODOT_PC, GODOT_MOBILE, ou GODOT_WEB, dependendo do tipo de plataforma.

  • Um dos GODOT_ARM64_V8A ou GODOT_ARMEABI_V7A apenas no Android dependendo da arquitetura.

  • Um dos GODOT_ARM64 ou GODOT_ARMV7 apenas no iOS, dependendo da arquitetura.

  • Um dos GODOT_S3TC, GODOT_ETC, ou GODOT_ETC2, dependendo do tipo de compressão de textura.

  • Quaisquer recursos personalizados adicionados no menu de exportação serão capitalizados e prefixados: foo -> GODOT_FOO.

Para ver um exemplo de projeto, veja um teste de demo de OS: https://github.com/godotengine/godot-demo-projects/tree/master/misc/os_test