Static typing in GDScript

In this guide, you will learn:

  • Como usar tipos no GDScript
  • Que os tipos estáticos podem ajudá-lo a evitar erros

A decisão de onde e como você usa esse novo recurso de linguagem é inteiramente sua: você pode usá-lo apenas em alguns arquivos GDScript sensíveis, usá-lo em qualquer lugar ou escrever códigos como sempre fez!

Tipos estáticos podem ser usados em variáveis, constantes, funções, parâmetros e tipos de retorno.

Nota

O GDScript digitado está disponível desde Godot 3.1.

Uma breve olhada na tipagem estática

Com GDScript digitado, Godot pode detectar ainda mais erros enquanto você escreve o código! Ele fornece a você e a seus colegas de equipe mais informações enquanto você trabalha, pois os tipos de argumentos aparecem quando você chama um método.

Imagine que você esteja programando um sistema de inventário. Você codifica um nó Item, depois um Inventário. Para adicionar itens ao inventário, as pessoas que trabalham com seu código devem sempre passar um Item para o método Inventário.add. Com tipos, você pode impor isso:

# In Item.gd
class_name Item

# In Inventory.gd
class_name Inventory

func add(reference: Item, amount: int = 1):
    var item = find_item(reference)
    if not item:
        item = _instance_item_from_db(reference)
    item.amount += amount

Outra vantagem significativa do GDScript digitado é o novo sistema de alerta. A partir da versão 3.1, Godot dá avisos sobre o seu código à medida que você o escreve: o motor identifica seções de seu código que podem levar a problemas em tempo de execução, mas permite que você decida se deseja ou não deixar o código como está. Mais sobre isso em um momento.

Os tipos estáticos também oferecem melhores opções de conclusão de código. Abaixo, você pode ver a diferença entre opções dinâmica e de estática completa para uma classe chamada PlayerController.

Você provavelmente armazenou um nó em uma variável antes e digitou um ponto para ficar sem sugestões de preenchimento automático:

code completion options for dynamic

Isto é devido ao código dinâmico. Godot não pode saber qual nó ou tipo de valor você está passando para a função. Se você escrever o tipo explicitamente no entanto, você obterá todos os métodos e variáveis públicos do nó:

code completion options for typed

No futuro, o GDScript digitado também aumentará o desempenho do código: a compilação Just-In-Time e outras melhorias do compilador já estão no roteiro!

No geral, a programação digitada proporciona uma experiência mais estruturada. Ajuda a evitar erros e melhora o aspecto de autodocumentação dos seus scripts. Isso é especialmente útil quando você trabalha em equipe ou em um projeto de longo prazo: estudos mostram que os desenvolvedores passam a maior parte do tempo lendo o código de outras pessoas ou scripts que escreveram no passado e esqueceram. Quanto mais claro e mais estruturado o código, mais rápido será entender, mais rápido você poderá avançar.

Como usar a digitação estática

Para definir o tipo de uma variável ou uma constante, escreva dois pontos após o nome da variável, seguido por seu tipo. Por exemplo. var health: int. Isso força o tipo da variável a permanecer sempre o mesmo:

var damage: float = 10.5
const MOVE_SPEED: float = 50.0

Godot tentará inferir tipos se você escrever dois pontos, mas omite o tipo:

var life_points := 4
var damage := 10.5
var motion := Vector2()

Atualmente você pode usar três tipos de… tipos:

  1. Embutido
  2. Classes e nós centrais (Objeto, , Area2D, Camera2D, etc.)
  3. Suas próprias classes personalizadas. Veja o novo recurso: ref: class_name <doc_scripting_continued_class_name> para registrar tipos no editor.

Nota

Você não precisa escrever dicas de tipo para constantes, já que Godot o define automaticamente a partir do valor atribuído. Mas você ainda pode fazer isso para tornar a intenção do seu código mais clara.

Custom variable types

Você pode usar qualquer classe, incluindo suas classes personalizadas, como tipos. Existem duas maneiras de usá-los em scripts. O primeiro método é pré-carregar o script que você deseja usar como um tipo em uma constante:

const Rifle = preload('res://player/weapons/Rifle.gd')
var my_rifle: Rifle

O segundo método é usar a palavra-chave `` class_name`` quando você cria. Para o exemplo acima, o seu Rifle.gd ficaria assim:

extends Node2D
class_name Rifle

Se você usa class_name, Godot registra o tipo Rifle globalmente no editor, e você pode usá-lo em qualquer lugar, sem ter que pré-carregá-lo em uma constante:

var my_rifle: Rifle

Variable casting

A conversão de tipos é um conceito-chave em idiomas tipados. Casting é a conversão de um valor de um tipo para outro.

Imagine an Enemy in your game, that extends Area2D. You want it to collide with the Player, a KinematicBody2D with a script called PlayerController attached to it. You use the on_body_entered signal to detect the collision. With typed code, the body you detect is going to be a generic PhysicsBody2D, and not your PlayerController on the _on_body_entered callback.

Você pode verificar se este PhysicsBody2D é o seu Jogador com a palavra-chave as e usando os dois pontos : novamente para forçar a variável a usar este tipo. Isso força a variável a se ater ao tipo PlayerController:

func _on_body_entered(body: PhysicsBody2D) -> void:
    var player := body as PlayerController
    if not player:
        return
    player.damage()

As we’re dealing with a custom type, if the body doesn’t extend PlayerController, the playervariable will be set to null. We can use this to check if the body is the player or not. We will also get full autocompletion on the player variable thanks to that cast.

Nota

Se você tentar moldar com um tipo embutido e falhar, Godot lançará um erro.

Safe lines

Você também pode usar a moldagem para garantir linhas seguras. As linhas seguras são uma nova ferramenta do Godot 3.1 para lhe dizer quando linhas de código ambíguas são seguras para o tipo. Como você pode misturar e combinar códigos digitados e dinâmicos, às vezes, Godot não tem informações suficientes para saber se uma instrução disparará um erro ou não em tempo de execução.

This happens when you get a child node. Let’s take a timer for example: with dynamic code, you can get the node with $Timer. GDScript supports duck-typing, so even if your timer is of type Timer, it is also a Node and an Object, two classes it extends. With dynamic GDScript, you also don’t care about the node’s type as long as it has the methods you need to call.

Você pode usar casting para dizer a Godot o tipo que você espera quando você obtém um nó: `` ($ Timer as Timer) ``, `` ($ Player as KinematicBody2D) `` etc. Godot irá assegurar que o tipo funcione e se sim , o número da linha ficará verde à esquerda do editor de script.

Safe vs Unsafe Line

Linha Segura vs Insegura

Nota

Você pode desativar linhas seguras ou alterar suas cores nas configurações do editor.

Defina o tipo de retorno de uma função com a seta ->

To define the return type of a function, write a dash and a right angle bracket -> after its declaration, followed by the return type:

func _process(delta: float) -> void:
    pass

O tipo void significa que a função não retorna nada. Você pode usar qualquer tipo, como com variáveis:

func hit(damage: float) -> bool:
    health_points -= damage
    return health_points <= 0

Você também pode usar seus próprios nós como tipos de retorno:

# Inventory.gd

# Adds an item to the inventory and returns it.
func add(reference: Item, amount: int) -> Item:
    var item: Item = find_item(reference)
    if not item:
        item = ItemDatabase.get_instance(reference)
    item.amount += amount
    return item

Tipada ou dinâmica: Adote um estilo

GDScript tipado e GDScript dinâmico podem coexistir em um mesmo projeto. Mas eu recomendo adotar um dos dois estilos para manter a consistência do seu código base. Facilita para todos trabalharem juntos se vocês seguirem as mesmas diretrizes, a acelera a leitura e o entendimento do código de outras pessoas.

Código tipado leva mais tempo para ser escrito, mas você terá os benefícios discutidos acima. Aqui está um exemplo do mesmo script vazio utilizando a tipagem dinâmica:

extends Node
    func _ready():
        pass
    func _process(delta):
        pass

E com a tipagem estática:

extends Node
    func _ready() -> void:
        pass
    func _process(delta: float) -> void:
        pass

Como você pode ver, você também pode usar tipos com os métodos virtuais da engine. Sinais de chamada de retorno, como qualquer método, também pode usar tipos. Aqui um sinal body_entered com a tipagem dinâmica:

func _on_Area2D_body_entered(body):
    pass

E a mesma chamada de retorno, com as dicas de tipo:

func _on_area_entered(area: CollisionObject2D) -> void:
    pass

You’re free to replace, e.g. the CollisionObject2D, with your own type, to cast parameters automatically:

func _on_area_entered(bullet: Bullet) -> void:
    if not bullet:
        return
    take_damage(bullet.damage)

Aqui a variável bullet pode guardar qualquer objeto CollisionObject2D, mas temos que garantir que é o nosso Bullet, um nó que criamos para o nosso projeto. Se for qualquer outra coisa, como uma Area2D, ou qualquer nó que não estenda Bullet, a variável bullet será null.

Warning system

O sistema de alerta complementa o GDScript tipado. Ele está aqui para te ajudar a evitar erros que são difíceis de perceber durante o desenvolvimento, e que podem levar a erros em tempo de execução.

Você pode configurar os alertas nas configurações do projeto, na nova seção chamada GDScript:

warning system project settings

warning system project settings

Na barra de status do editor de scripts, você pode achar uma lista de alertas para o arquivo GDScript ativo. O exemplo abaixo tem três alertas:

warning system example

warning system example

Para ignorar alertas específicos em um arquivo, insira um comentário especial na forma de #warning-ignore:warning-id, ou clique no link de ignorar, à direita da descrição do alerta, assim a Godot irá adicionar um comentário acima da linha correspondente e o código não irá mais disparar o alerta correspondente:

warning system ignore example

warning system ignore example

Alertas não irão previnir a execução do jogo, mas você pode transformá-los em erros se preferir. Dessa maneira seu jogo não irá compilar a menos que todos os alertas sejam corrigidos. Acesse a seção GDScript nas configurações do projeto para ativar essa opção. Aqui o mesmo arquivo do exemplo anterior configurado com os alertas sendo erros:

warnings as errors

alertas como erros

Casos onde você não pode especificar os tipos

Para finalizar essa introdução, vamos abordar alguns poucos casos onde você não pode usar tipos. Todos os exemplos abaixo vão disparar erros.

Você não pode usar Enums como tipos:

enum MoveDirection {UP, DOWN, LEFT, RIGHT}
var current_direction: MoveDirection

Você não pode especificar o tipo de cada elemento em uma matriz. Isso lhe dará um erro:

var enemies: Array = [$Goblin: Enemy, $Zombie: Enemy]

Você não pode forçar a atribuição de tipos em um laço for, pois cada elemento em que o laço for itera já possui um tipo diferente. Então você não pode escrever:

var names = ['John', 'Marta', 'Samantha', 'Jimmy']
for name: String in names:
    pass

Dois scripts não podem depender um do outro de forma cíclica:

# Player.gd
extends Area2D
class_name Player

var rifle: Rifle
# Rifle.gd
extends Area2D
class_name Rifle

var player: Player

Resumo

GDScript tipado é uma ferramenta poderosa. Disponível na versão 3.1 da Godot, lhe ajudará a escrever um código mais estruturado, evitando erros comuns, e a criar sistemas escaláveis. No futuro, a tipagem estática também te trará um bom aumento de desempenho graças às futuras otimizações do compilador.