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.
Checking the stable version of the documentation...
Referência do GDScript
O GDScript é uma linguagem de programação de alto nível, orientada a objetos, imperativa e de tipagem gradual, desenvolvida para o Godot. Ela utiliza uma sintaxe baseada em indentação semelhante a linguagens como Python. Seu objetivo é ser otimizada para e fortemente integrada ao Godot Engine, permitindo grande flexibilidade para a criação e integração de conteúdo.
O GDScript é inteiramente independente do Python e não é baseado nele.
Histórico
Nota
A documentação sobre a história do GDScript foi movida para o Frequently Asked Questions.
Exemplo de GDScript
Algumas pessoas aprendem melhor dando uma olhada na sintaxe, então aqui está um exemplo de como é a aparência do GDScript.
# Everything after "#" is a comment.
# A file is a class!
# (optional) icon to show in the editor dialogs:
@icon("res://path/to/optional/icon.svg")
# (optional) class definition:
class_name MyClass
# Inheritance:
extends BaseClass
# Member variables.
var a = 5
var s = "Hello"
var arr = [1, 2, 3]
var dict = {"key": "value", 2: 3}
var other_dict = {key = "value", other_key = 2}
var typed_var: int
var inferred_type := "String"
# Constants.
const ANSWER = 42
const THE_NAME = "Charly"
# Enums.
enum {UNIT_NEUTRAL, UNIT_ENEMY, UNIT_ALLY}
enum Named {THING_1, THING_2, ANOTHER_THING = -1}
# Built-in vector types.
var v2 = Vector2(1, 2)
var v3 = Vector3(1, 2, 3)
# Function, with a default value for the last parameter.
func some_function(param1, param2, param3 = 123):
const local_const = 5
if param1 < local_const:
print(param1)
elif param2 > 5:
print(param2)
else:
print("Fail!")
for i in range(20):
print(i)
while param2 != 0:
param2 -= 1
match param3:
3:
print("param3 is 3!")
_:
print("param3 is not 3!")
var local_var = param1 + 3
return local_var
# Functions override functions with the same name on the base/super class.
# If you still want to call them, use "super":
func something(p1, p2):
super(p1, p2)
# It's also possible to call another function in the super class:
func other_something(p1, p2):
super.something(p1, p2)
# Inner class
class Something:
var a = 10
# Constructor
func _init():
print("Constructed!")
var lv = Something.new()
print(lv.a)
Se você possui experiência prévia com linguagens estaticamente tipadas, como C, C++, ou C#, mas nunca utilizou uma linguagem dinamicamente tipada antes, é aconselhado que leia este tutorial: GDScript: Uma introdução às linguagens dinâmicas.
Identificadores
Qualquer String que se restringe a caracteres alfabéticos (a a z e A a Z), dígitos (0 a 9) e _ se qualifica como um identificador. Além disso, identificadores não devem começar com um dígito. Identificadores são [i]case-sensitive[/i] (foo é diferente de FOO).
Os identificadores também podem conter a maioria dos caracteres Unicode que fazem parte da UAX#31. Isso permite que você use nomes de identificadores escritos em outros idiomas além do inglês. Caracteres Unicode que são considerados "confundíveis" com caracteres ASCII e emojis não são permitidos em identificadores.
Palavras-chave
A seguir está a lista de palavras-chaves suportadas pela linguagem. Já que as palavras-chaves são palavras reservadas (código), elas não podem ser usadas como identificadores. Operadores (como in, not, and ou or) e nomes de tipos embutidos como os listados nas seções seguintes são também palavras reservadas.
Palavras chaves são definidas no tokenizador da GDScript no caso de você querer dar uma olhada nos bastidores.
Palavra-chave |
Descrição |
|---|---|
if |
Veja if/else/elif. |
elif |
Veja if/else/elif. |
else |
Veja if/else/elif. |
for |
Veja for. |
while |
Veja while. |
match |
Veja match. |
when |
Usado por guardas de padrão nas instruções |
break |
Sai da execução do atual laço |
continue |
Pula imediatamente a próxima iteração do laço |
pass |
Usado onde uma declaração é requerida sintaticamente, mas a execução do código é indesejada ,por exemplo em funções vazias. |
return |
Retorna um valor de uma função. |
class |
Define uma classe interna (inner class). Veja Inner classes. |
class_name |
Define o script como uma classe globalmente acessível com o nome especificado. Veja Registering named classes. |
extends |
Define qual classe estender com a classe atual. |
is |
Testa se uma variável extende de uma classe dada, ou é de um certo tipo embutido. |
in |
Testa se um valor está dentro de uma string, array, intervalo (range), dicionário ou nó. Quando usado com |
as |
Casts the value to a given type if possible. |
self |
Refere-se à instância da classe atual. Veja self. |
super |
Resolve o escopo do método pai. Veja Inheritance. |
signal |
Define um sinal. Veja Signals. |
func |
Defines a function. See Functions. |
static |
Define uma função estática ou uma variável de membro estática. |
const |
Define uma constante. Veja Constants. |
enum |
Define um enum. Veja Enums. |
var |
Define uma variável. Veja Variables. |
breakpoint |
Auxiliar do editor para breakpoints do depurador. Ao contrário dos breakpoints criados ao clicar na margem (gutter), o |
preload |
Pré-carrega uma classe ou variável. Veja Classes as resources. |
await |
Aguarda um sinal ou uma corrotina terminar. Veja Awaiting signals or coroutines. |
yield |
Anteriormente usado para corrotinas. Mantido como palavra-chave para transição. |
assert |
Assegura uma condição, registrando um erro em caso de falha. Ignorado em builds de produção (não-debug). Veja Assert keyword. |
void |
Usado para representar que uma função não retorna nenhum valor. |
PI |
A constante PI. |
TAU |
A constante TAU. |
INF |
Infinity constant. Used for comparisons and as a result from calculations. |
NAN |
NaN (Not a Number) constant. Used as an impossible result from calculations. |
Operadores
A seguir está a lista de operadores suportados e sua precedência. Todos os operadores binários são associativos à esquerda, incluindo o operador **. Isso significa que 2 ** 2 ** 3 é igual a (2 ** 2) ** 3. Use parênteses para especificar explicitamente a precedência de que precisa, por exemplo 2 ** (2 ** 3). O operador ternário if/else é associativo à direita.
Operador |
Descrição |
|---|---|
|
Agrupamento (maior prioridade) Os parênteses não são realmente um operador, mas permitem que você especifique explicitamente a precedência de uma operação. |
|
Subscrição |
|
Referência de atributo |
|
Chamada de função |
|
|
x is Nodex is not Node |
Checagem de tipo Veja também a função is_instance_of(). |
|
Potência Multiplica |
|
NÃO Binário |
+x-x |
Identidade / Negação |
x * yx / yx % y |
Multiplicação / Divisão / Resto O operador Nota: Esses operadores têm o mesmo comportamento que no C++, o que pode ser inesperado para usuários vindos do Python, JavaScript, etc. Veja uma nota detalhada após a tabela. |
x + yx - y |
Adição (ou Concatenação) / Subtração |
x << yx >> y |
Deslocamento de bits |
|
E Binário |
|
OU EXCLUSIVO Binário |
|
OU Binário |
x == yx != yx < yx > yx <= yx >= y |
Comparação Veja uma nota detalhada após a tabela. |
x in yx not in y |
Checagem de inclusão
|
not x!x |
NOT booleano e seu alias não recomendado |
x and yx && y |
AND booleano e seu alias não recomendado |
x or yx || y |
OR booleano e seu alias não recomendado |
|
if/else Ternário |
|
|
x = yx += yx -= yx *= yx /= yx **= yx %= yx &= yx |= yx ^= yx <<= yx >>= y |
Atribuição (menor prioridade) Você não pode usar um operador de atribuição dentro de uma expressão. |
Nota
O comportamento de alguns operadores pode diferir do que você espera:
Se ambos os operandos do operador
/forem do tipo int, então uma divisão inteira é realizada em vez de uma divisão fracionária. Por exemplo,5 / 2 == 2, e não2.5. Se isso não for desejado, use pelo menos um literal float (x / 2.0), conversão de tipo (float(x) / y) ou multiplique por1.0(x * 1.0 / y).O operador
%está disponível apenas para números inteiros (ints); para números decimais (floats), use a função fmod().Para valores negativos, o operador
%e a funçãofmod()usam truncamento em vez de arredondamento em direção ao infinito negativo. Isso significa que o resto mantém o sinal. Se você precisar do resto no sentido matemático, use as funções posmod() e fposmod().Os operadores
==e!=às vezes permitem comparar valores de tipos diferentes (por exemplo,1 == 1.0é verdadeiro), mas em outros casos isso pode causar um erro em tempo de execução. Se você não tiver certeza sobre os tipos dos operandos, pode usar com segurança a função is_same() (mas note que ela é mais estrita em relação a tipos e referências). Para comparar floats, use as funções is_equal_approx() e is_zero_approx().
Literais
Exemplo(s) |
Descrição |
|
Valor nulo (Null) |
|
Valores booleanos |
|
Inteiro Base 10 |
|
Inteiro de base 16 (hexadecimal) |
|
Inteiro de base 2 (binário) |
|
Número de ponto flutuante (real) |
|
Strings regulares |
|
Strings regulares com aspas triplas |
|
Strings brutas (Raw strings) |
|
Strings brutas com aspas triplas |
|
|
|
Existem também duas estruturas que parecem literais, mas na verdade não são:
Exemplo |
Descrição |
|
Forma abreviada para |
|
Abreviação para |
Inteiros e floats podem ter seus números separados com _ para torná-los mais legíveis. As seguintes maneiras de escrever números são todas válidas:
12_345_678 # Equal to 12345678.
3.141_592_7 # Equal to 3.1415927.
0x8080_0000_ffff # Equal to 0x80800000ffff.
0b11_00_11_00 # Equal to 0b11001100.
Literais de string regulares podem conter as seguintes sequências de escape:
Sequência de escape |
Se expande para |
|
Nova linha (feed de linha) |
|
Caractere tab horizontal |
|
Retorno de transporte |
|
Alerta (bipe/campainha) |
|
Retroceder |
|
Quebra de página do feed de formulário |
|
Caractere tab vertical |
|
Citação dupla |
|
Citação única |
|
Barra invertida |
|
Codepoint Unicode UTF-16 |
|
Codepoint Unicode UTF-32 |
Existem duas maneiras de representar um caractere Unicode de escape acima de 0xFFFF:
como um par de substitutos UTF-16
\uXXXX\uXXXX.como um único ponto de código UTF-32
\UXXXXXX.
Além disso, usar \\ seguido por uma quebra de linha dentro de uma string permitirá que você a continue na próxima linha, sem inserir um caractere de nova linha na própria string.
Uma string delimitada por aspas de um tipo (por exemplo, \") pode conter aspas de outro tipo (por exemplo, ') sem necessidade de escape. Strings com aspas triplas permitem evitar o escape de até duas aspas consecutivas do mesmo tipo (a menos que estejam adjacentes às bordas da string).
Literais de string brutas (raw strings) sempre codificam a string exatamente como ela aparece no código-fonte. Isso é especialmente útil para expressões regulares. Um literal de string bruta não processa sequências de escape, porém ele reconhece \\\\ e \\\" (\\') e os substitui por si mesmos. Assim, uma string pode conter uma aspa que corresponda à de abertura, mas apenas se for precedida por uma barra invertida.
print("\tchar=\"\\t\"") # Prints ` char="\t"`.
print(r"\tchar=\"\\t\"") # Prints `\tchar=\"\\t\"`.
Nota
Algumas strings não podem ser representadas usando literais de string bruta: você não pode ter um número ímpar de barras invertidas no final de uma string ou ter uma aspa de abertura sem escape dentro da string. No entanto, na prática isso não importa, pois você pode usar um tipo de aspa diferente ou usar a concatenação com um literal de string regular.
O GDScript também suporta strings de formatação.
Anotações
As anotações são tokens especiais no GDScript que agem como modificadores para um script inteiro, uma declaração, uma instrução ou um local no código-fonte. As anotações podem afetar a forma como o script é tratado pelo editor do Godot e pelo compilador do GDScript.
Cada anotação começa com o caractere @ e é especificada por um nome. Uma descrição detalhada e exemplos para cada anotação podem ser encontrados na referência da classe GDScript.
Por exemplo, você pode usá-la para exportar um valor para o editor:
@export_range(1, 100, 1, "or_greater")
var ranged_var: int = 50
Para mais informações sobre como exportar propriedades, leia o artigo GDScript exports.
Qualquer expressão constante compatível com o tipo de argumento exigido pode ser passada como valor de argumento de uma anotação:
const MAX_SPEED = 120.0
@export_range(0.0, 0.5 * MAX_SPEED)
var initial_speed: float = 0.25 * MAX_SPEED
As anotações podem ser especificadas uma por linha ou todas na mesma linha. Elas afetam a próxima instrução que não seja uma anotação. As anotações podem ter argumentos enviados entre parênteses e separados por vírgulas.
Ambos os casos abaixo são iguais:
@annotation_a
@annotation_b
var variable
@annotation_a @annotation_b var variable
Anotação @onready
Ao usar nós, é comum desejar manter referências a partes da cena em uma variável. Como as cenas só podem ser configuradas ao entrar na árvore da cena ativa, os subnós só podem ser obtidos quando uma chamada para Node._ready() é feita.
var my_label
func _ready():
my_label = get_node("MyLabel")
Isso pode se tornar um pouco trabalhoso, especialmente quando nós e referências externas se acumulam. Para isso, o GDScript conta com a anotação @onready, que adia a inicialização de uma variável de membro até que _ready() seja chamado. Ela permite substituir o código acima por uma única linha:
@onready var my_label = get_node("MyLabel")
Aviso
Aplicar a anotação @onready e qualquer anotação @export à mesma variável não funciona como você poderia esperar. A anotação @onready fará com que o valor padrão seja definido após o @export entrar em vigor, substituindo-o:
@export var a = "init_value_a"
@onready @export var b = "init_value_b"
func _init():
prints(a, b) # init_value_a <null>
func _notification(what):
if what == NOTIFICATION_SCENE_INSTANTIATED:
prints(a, b) # exported_value_a exported_value_b
func _ready():
prints(a, b) # exported_value_a init_value_b
Por isso, o aviso ONREADY_WITH_EXPORT é gerado, o qual é tratado como erro por padrão. Não recomendamos desativar ou ignorar este aviso.
Regiões de código
As regiões de código são tipos especiais de comentários que o editor de script entende como regiões recolhíveis. Isso significa que, após escrever comentários de região de código, você pode recolher e expandir a região clicando na seta que aparece à esquerda do comentário. Essa seta aparece dentro de um quadrado roxo para ser distinguível do recolhimento de código padrão.
A sintaxe é a seguinte:
# Important: There must be *no* space between the `#` and `region` or `endregion`.
# Region without a description:
#region
...
#endregion
# Region with a description:
#region Some description that is displayed even when collapsed
...
#endregion
Dica
Para criar uma região de código rapidamente, selecione várias linhas no editor de script, clique com o botão direito na seleção e escolha Create Code Region. A descrição da região será selecionada automaticamente para edição.
É possível aninhar regiões de código dentro de outras regiões de código.
Aqui está um exemplo de uso concreto de regiões de código:
# This comment is outside the code region. It will be visible when collapsed.
#region Terrain generation
# This comment is inside the code region. It won't be visible when collapsed.
func generate_lakes():
pass
func generate_hills():
pass
#endregion
#region Terrain population
func place_vegetation():
pass
func place_roads():
pass
#endregion
Isso pode ser útil para organizar grandes blocos de código em seções mais fáceis de entender. No entanto, lembre-se de que editores externos geralmente não suportam esse recurso, portanto, certifique-se de que seu código seja fácil de acompanhar, mesmo quando não depender do recolhimento de regiões de código.
Nota
Funções individuais e seções recuadas (como if e for) sempre podem ser recolhidas no editor de script. Isso significa que você deve evitar o uso de uma região de código para conter apenas uma única função ou seção recuada, pois isso não trará grandes benefícios. As regiões de código funcionam melhor quando usadas para agrupar múltiplos elementos.
Continuação de linha
Uma linha de código no GDScript pode ser continuada na próxima linha usando uma barra invertida (\\). Adicione uma ao final de uma linha e o código na linha seguinte agirá como se estivesse no lugar da barra invertida. Aqui está um exemplo:
var a = 1 + \
2
Uma linha pode ser continuada várias vezes dessa forma:
var a = 1 + \
4 + \
10 + \
4
Tipos definidos por padrão
Tipos integrados (built-in) são alocados na pilha (stack-allocated). Eles são passados como valores. Isso significa que uma cópia é criada a cada atribuição ou ao passá-los como argumentos para funções. As exceções são Object, Array, Dictionary e arrays compactados (como PackedByteArray), que são passados por referência para que sejam compartilhados. Todos os arrays, Dictionary e alguns objetos (Node, Resource) possuem um método duplicate() que permite fazer uma cópia.
Tipos básicos definidos por padrão
Uma variável no GDScript pode ser atribuída a vários tipos definidos por padrão.
null
null é um tipo de dados vazio que não contém informação nenhuma e que não pode ser atribuído nenhum outro valor.
Apenas tipos que herdam de Object podem ter um valor null (Object é, portanto, chamado de um tipo "anulável" ou "nullable"). Os tipos Variant devem ter um valor válido em todos os momentos e, por isso, não podem ter um valor null.
bool
Abreviação de "booleano", pode conter apenas true ou false.
int
Abreviatura de "integer" (inteiro), armazena números inteiros (positivos e negativos). É armazenado como um valor de 64 bits, equivalente a int64_t em C++.
float
Armazena números reais, incluindo decimais, usando valores de ponto flutuante. É armazenado como um valor de 64 bits, equivalente a double in C++. Nota: Atualmente, estruturas de dados como Vector2, Vector3 e PackedFloat32Array armazenam valores float de precisão simples de 32 bits.
String
Uma sequência de caracteres no formato Unicode.
StringName
Uma string imutável que permite apenas uma instância de cada nome. Elas são mais lentas para criar e podem resultar em espera por travas (locks) ao usar multithreading. Em troca, elas são muito rápidas para comparar, o que as torna ótimas candidatas para chaves de dicionário.
NodePath
Um caminho pré-analisado para um nó ou propriedade de nó. Pode ser facilmente atribuído a partir de, e para, uma String. São úteis para interagir com a árvore de cena para obter um nó ou afetar propriedades, como acontece com Tweens.
Tipos básicos de vetor
Vector2
O tipo vetor 2D contém os campos x e y. Também pode ser acessado como uma matriz.
Vector2i
O mesmo que um Vector2, mas os componentes são inteiros. Útil para representar itens em uma grade 2D.
Rect2
O tipo 2D Rectangle contém dois campos vetoriais: position e size. Contém também um campo end que é position + size.
Vector3
O tipo de vetor 3D contém os campos x, y e z. Isso também pode ser acessado como um array.
Vector3i
O mesmo que um Vector3, mas os componentes são inteiros. Pode ser usado para indexar itens em uma grade 3D.
Transform2D
Matrix de 3x2 usada para transformações em 2D.
Plane
Tipo de plano 3D em forma normalizada que contém um campo vetorial normal e uma distância escalar d.
Quaternion
Quaternion é um tipo de dado utilizado para representar uma rotação 3D. Isto é útil para interporlar rotações.
AABB
Caixa delimitadora alinhada por eixo (ou caixa 3D) contém 2 campos vetoriais: position e size. Contém também um campo end que é position + size.
Basis
Matriz 3x3 usada para rotação e escala em 3D. Ela contém 3 campos vetoriais (x, y e z) e também pode ser acessada como um array de vetores 3D.
Transform3D
Transformadas 3D contem um campo Basis basis e um campo Vector3 origin.
Tipos definidos por padrão da Engine
Color
O tipo de dados Color contem campos r, g, b e a para vermelho, verde, azul e transparência respectivamente. E podem também ser acessados como h, s, e v para matiz, saturação e valor respectivamente.
RID
ID de Recurso (RID). Servidores usam RIDs genéricos para referenciar dados opacos.
Object
Classe base para qualquer coisa que não seja um tipo básico.
Tipos contêiner definidos por padrão
Array
Sequência genérica de tipos de objeto arbitrária, incluindo outras matrizes ou dicionários (veja abaixo). A matriz pode redimensionar dinamicamente. Matrizes são indexados iniciando do índice 0. Índices negativos contam do final.
var arr = []
arr = [1, 2, 3]
var b = arr[1] # This is 2.
var c = arr[arr.size() - 1] # This is 3.
var d = arr[-1] # Same as the previous line, but shorter.
arr[0] = "Hi!" # Replacing value 1 with "Hi!".
arr.append(4) # Array is now ["Hi!", 2, 3, 4].
Arrays tipados
O Godot também possui suporte para arrays tipados. Nas operações de escrita, o Godot verifica se os valores dos elementos correspondem ao tipo especificado, para que o array não contenha valores inválidos. O analisador estático do GDScript leva os arrays tipados em consideração, no entanto, métodos de array como front() e back() ainda possuem o tipo de retorno Variant.
Arrays tipados usam a sintaxe Array[Type], onde Type pode ser qualquer tipo Variant, classe nativa ou de usuário, ou enum. Tipos de array aninhados (como Array[Array[int]]) não são suportados.
var a: Array[int]
var b: Array[Node]
var c: Array[MyClass]
var d: Array[MyEnum]
var e: Array[Variant]
Array e Array[Variant] são a mesma coisa.
Nota
Os arrays são passados por referência, portanto, o tipo do elemento do array também é um atributo da estrutura na memória referenciada por uma variável em tempo de execução. O tipo estático de uma variável restringe as estruturas que ela pode referenciar. Portanto, você não pode atribuir um array com um tipo de elemento diferente, mesmo se o tipo for um subtipo do tipo exigido.
Se você deseja converter um array tipado, pode criar um novo array e usar o método Array.assign():
var a: Array[Node2D] = [Node2D.new()]
# (OK) You can add the value to the array because `Node2D` extends `Node`.
var b: Array[Node] = [a[0]]
# (Error) You cannot assign an `Array[Node2D]` to an `Array[Node]` variable.
b = a
# (OK) But you can use the `assign()` method instead. Unlike the `=` operator,
# the `assign()` method copies the contents of the array, not the reference.
b.assign(a)
A única exceção foi feita para o tipo Array (Array[Variant]), para conveniência do usuário e compatibilidade com códigos antigos. No entanto, operações em arrays não tipados são consideradas inseguras.
Arrays compactados
Os PackedArrays geralmente são mais rápidos para iterar e modificar em comparação com um Array tipado do mesmo tipo (por exemplo, PackedInt64Array versus Array[int]) e consomem menos memória. No pior caso, espera-se que sejam tão rápidos quanto um Array não tipado. Por outro lado, Arrays não-Packed (tipados ou não) possuem métodos de conveniência extras, como Array.map, que faltam nos PackedArrays. Consulte a referência de classe para detalhes sobre os métodos disponíveis. Arrays tipados geralmente são mais rápidos para iterar e modificar do que os Arrays não tipados.
Embora todos os Arrays possam causar fragmentação de memória quando ficam grandes o suficiente, se uso de memória e desempenho (velocidade de iteração e modificação) forem uma preocupação e o tipo de dado que você está armazenando for compatível com um dos tipos de Array Packed, então usá-los pode trazer melhorias. No entanto, se você não tiver essas preocupações (por exemplo, o tamanho do seu array não chega a dezenas de milhares de elementos), provavelmente é mais útil usar Arrays normais ou tipados, pois eles fornecem métodos de conveniência que podem tornar seu código mais fácil de escrever e manter (e potencialmente mais rápido se seus dados exigirem essas operações com frequência). Se os dados que você armazenará forem de um tipo conhecido (incluindo suas próprias classes definidas), prefira usar um Array tipado, pois isso pode trazer melhor desempenho em iteração e modificação em comparação com um Array não tipado.
PackedByteArray: Um array de bytes (inteiros de 0 a 255).
PackedInt32Array: Um array de inteiros de 32 bits.
PackedInt64Array: Um array de inteiros de 64 bits.
PackedFloat32Array: Um array de floats de 32 bits.
PackedFloat64Array: Um array de floats de 64 bits.
PackedStringArray: Um array de strings.
PackedVector2Array: Um array de valores Vector2.
PackedVector3Array: Um array de valores Vector3.
PackedVector4Array: Um array de valores Vector4.
PackedColorArray: Um array de valores Color.
Dictionary
Contêiner associativo que armazena valores referenciados por chaves únicas.
var d = {4: 5, "A key": "A value", 28: [1, 2, 3]}
d["Hi!"] = 0
d = {
22: "value",
"some_key": 2,
"other_key": [2, 3, 4],
"more_key": "Hello"
}
A sintaxe de tabela no estilo Lua também é suportada. O estilo Lua usa = em vez de : e não usa aspas para marcar chaves de string (o que reduz um pouco a escrita). No entanto, chaves escritas nesta forma não podem começar com um dígito (como qualquer identificador do GDScript) e devem ser strings literais.
var d = {
test22 = "value",
some_key = 2,
other_key = [2, 3, 4],
more_key = "Hello"
}
Para adicionar uma chave a um dicionário existente, acesse-a como se fosse uma chave já existente e atribua um valor a ela:
var d = {} # Create an empty Dictionary.
d.waiting = 14 # Add String "waiting" as a key and assign the value 14 to it.
d[4] = "hello" # Add integer 4 as a key and assign the String "hello" as its value.
d["Godot"] = 3.01 # Add String "Godot" as a key and assign the value 3.01 to it.
var test = 4
# Prints "hello" by indexing the dictionary with a dynamic key.
# This is not the same as `d.test`. The bracket syntax equivalent to
# `d.test` is `d["test"]`.
print(d[test])
Nota
A sintaxe de colchetes pode ser usada para acessar propriedades de qualquer Object, não apenas Dictionaries. Tenha em mente que isso causará um erro de script ao tentar indexar uma propriedade inexistente. Para evitar isso, use os métodos Object.get() e Object.set() em seu lugar.
Dicionários tipados
O Godot 4.4 adicionou suporte para dicionários tipados. Nas operações de escrita, o Godot verifica se as chaves e valores dos elementos correspondem ao tipo especificado, para que o dicionário não contenha chaves ou valores inválidos. O analisador estático do GDScript leva em consideração os dicionários tipados. No entanto, métodos de dicionário que retornam valores ainda possuem o tipo de retorno Variant.
Dicionários tipados possuem a sintaxe Dictionary[KeyType, ValueType], onde KeyType e ValueType podem ser qualquer tipo Variant, classe nativa ou de usuário, ou enum. Tanto o tipo da chave quanto o do valor devem ser especificados, mas você pode usar Variant para deixar qualquer um deles não tipado. Coleções tipadas aninhadas (como Dictionary[String, Dictionary[String, int]]) não são suportadas.
var a: Dictionary[String, int]
var b: Dictionary[String, Node]
var c: Dictionary[Vector2i, MyClass]
var d: Dictionary[MyEnum, float]
# String keys, values can be any type.
var e: Dictionary[String, Variant]
# Keys can be any type, boolean values.
var f: Dictionary[Variant, bool]
Dictionary e Dictionary[Variant, Variant] são a mesma coisa.
Signal
Um sinal é uma mensagem que pode ser emitida por um objeto para aqueles que desejam escutá-la. O tipo Signal pode ser usado para passar o emissor adiante.
Os sinais são melhor utilizados quando obtidos de objetos reais, por exemplo, $Button.button_up.
Callable
Contém um objeto e uma função, o que é útil para passar funções como valores (por exemplo, ao conectar a sinais).
Obter um método como um membro retorna um callable. var x = $Sprite2D.rotate definirá o valor de x para um callable com $Sprite2D como o objeto e rotate como o método.
Você pode chamá-lo usando o método call: x.call(PI).
Variáveis
Variáveis podem existir como membros de classe ou locais em funções. Elas são criadas com a palavra-chave var e podem, opcionalmente, ser atribuídas com um valor durante a inicialização.
var a # Data type is 'null' by default.
var b = 5
var c = 3.8
var d = b + c # Variables are always initialized in direct order (see below).
As variáveis podem, opcionalmente, ter uma especificação de tipo. Quando um tipo é especificado, a variável será forçada a ter sempre esse mesmo tipo, e tentar atribuir um valor incompatível gerará um erro.
Os tipos são especificados na declaração da variável usando um símbolo : (dois-pontos) após o nome da variável, seguido pelo tipo.
var my_vector2: Vector2
var my_node: Node = Sprite2D.new()
Se a variável for inicializada na declaração, o tipo pode ser inferido; portanto, é possível omitir o nome do tipo:
var my_vector2 := Vector2() # 'my_vector2' is of type 'Vector2'.
var my_node := Sprite2D.new() # 'my_node' is of type 'Sprite2D'.
A inferência de tipos só é possível se o valor atribuído tiver um tipo definido, caso contrário, irá gerar um erro.
Tipos válidos são:
Tipos embutidos (Array, Vector2, int, String, etc.).
Classes do motor (Node, Resource, RefCounted, etc.).
Nomes constantes se eles contiverem um recurso de script (
MyScriptse você declararconst MyScript = preload("res://my_script.gd")).Outras classes no mesmo script, respeitando o escopo (
InnerClass.NestedClassse você declarouclassNestedClassdentro daclassInnerClassno mesmo escopo).Classes de script declaradas com a palavra-chave
class_name.Autoloads registrados como singletons.
Nota
Embora Variant seja uma especificação de tipo válida, ela não é um tipo real. Significa apenas que não há um tipo definido e é equivalente a não ter um tipo estático. Portanto, a inferência não é permitida por padrão para Variant, já que provavelmente se trata de um erro.
Você pode desativar essa verificação, ou torná-la apenas um aviso, alterando-a nas configurações do projeto. Veja Sistema de alertas do GDScript para mais detalhes.
Ordem de inicialização
As variáveis membro são inicializadas na seguinte ordem:
Dependendo do tipo estático da variável, a variável ou é
null(variáveis não tipadas e objetos) ou possui um valor padrão do tipo (0paraint,falseforbool, etc.).Os valores especificados são atribuídos na ordem das variáveis no script, de cima para baixo.
(Apenas para classes derivadas de
Node) Se a anotação@onreadyfor aplicada a uma variável, sua inicialização é adiada para o passo 5.
Se definido, o método
_init()é chamado.Ao instanciar cenas e recursos, os valores exportados são atribuídos.
(Apenas para classes derivadas de
Node) As variáveis@onreadysão inicializadas.(Apenas para classes derivadas de
Node) Se definido, o método_ready()é chamado.
Aviso
Você pode especificar uma expressão complexa como inicializador de variável, incluindo chamadas de função. Certifique-se de que as variáveis sejam inicializadas na ordem correta, caso contrário, seus valores podem ser substituídos. Por exemplo:
var a: int = proxy("a", 1)
var b: int = proxy("b", 2)
var _data: Dictionary = {}
func proxy(key: String, value: int):
_data[key] = value
print(_data)
return value
func _init() -> void:
print(_data)
Imprimirá:
{ "a": 1 }
{ "a": 1, "b": 2 }
{ }
Para corrigir isso, mova a definição da variável _data para cima da definição de a ou remova a atribuição de dicionário vazio (= {}).
Variáveis estáticas
Uma variável de membro de classe pode ser declarada como estática:
static var a
Variáveis estáticas pertencem à classe, não às instâncias. Isso significa que as variáveis estáticas compartilham valores entre múltiplas instâncias, ao contrário das variáveis de membro comuns.
De dentro de uma classe, você pode acessar variáveis estáticas a partir de qualquer função, tanto estáticas quanto não estáticas. De fora da classe, você pode acessar variáveis estáticas usando a classe ou uma instância (a segunda opção não é recomendada, pois é menos legível).
Nota
As anotações @export e @onready não podem ser aplicadas a uma variável estática. Variáveis locais não podem ser estáticas.
O exemplo a seguir define uma classe Person com uma variável estática chamada max_id. Nós incrementamos o max_id na função _init(). Isso facilita o rastreamento do número de instâncias de Person em nosso jogo.
# person.gd
class_name Person
static var max_id = 0
var id
var name
func _init(p_name):
max_id += 1
id = max_id
name = p_name
Neste código, criamos duas instâncias da nossa classe Person e verificamos que a classe e cada instância possuem o mesmo valor de max_id, porque a variável é estática e acessível a todas as instâncias.
# test.gd
extends Node
func _ready():
var person1 = Person.new("John Doe")
var person2 = Person.new("Jane Doe")
print(person1.id) # 1
print(person2.id) # 2
print(Person.max_id) # 2
print(person1.max_id) # 2
print(person2.max_id) # 2
Variáveis estáticas podem ter dicas de tipo (type hints), setters e getters:
static var balance: int = 0
static var debt: int:
get:
return -balance
set(value):
balance = -value
Uma variável estática de uma classe base também pode ser acessada por meio de uma classe filha:
class A:
static var x = 1
class B extends A:
pass
func _ready():
prints(A.x, B.x) # 1 1
A.x = 2
prints(A.x, B.x) # 2 2
B.x = 3
prints(A.x, B.x) # 3 3
Nota
Ao referenciar uma variável estática a partir de um script de ferramenta (tool script), o outro script que contém a variável estática deve também ser um script de ferramenta. Veja Running code in the editor para mais detalhes.
Anotação @static_unload
Como as classes GDScript são recursos, ter variáveis estáticas em um script impede que ele seja descarregado da memória, mesmo que não haja mais instâncias daquela classe e nenhuma outra referência restante. Isso pode ser importante se as variáveis estáticas armazenarem grandes quantidades de dados ou mantiverem referências a outros recursos do projeto, como cenas. Você deve limpar esses dados manualmente ou usar a anotação @static_unload se as variáveis estáticas não armazenarem dados importantes e puderem ser reiniciadas.
Aviso
Atualmente, devido a um bug, os scripts nunca são liberados, mesmo que a anotação @static_unload seja usada.
Note que @static_unload se aplica a todo o script (incluindo classes internas) e deve ser colocada no topo do script, antes de class_name e extends:
@static_unload
class_name MyNode
extends Node
Veja também Static functions e Static constructor.
Conversão
Valores atribuídos a variáveis digitadas devem ter um tipo compatível. Se for necessário forçar um valor a ser de um determinado tipo, em particular para tipos de objetos, você pode usar o operador de conversão as.
A conversão entre tipos de objetos resulta no mesmo objeto se o valor for do mesmo tipo ou um subtipo do tipo de conversão.
var my_node2D: Node2D
my_node2D = $Sprite2D as Node2D # Works since Sprite2D is a subtype of Node2D.
Se o valor não for um subtipo, a operação de conversão de tipo resultará em um valor null.
var my_node2D: Node2D
my_node2D = $Button as Node2D # Results in 'null' since a Button is not a subtype of Node2D.
Para tipos internos, eles serão convertidos à força, se possível, caso contrário, o mecanismo gerará um erro.
var my_int: int
my_int = "123" as int # The string can be converted to int.
my_int = Vector2() as int # A Vector2 can't be converted to int, this will cause an error.
O casting também é útil para obter variáveis com melhor segurança de tipos ao interagir com a árvore de cena:
# Will infer the variable to be of type Sprite2D.
var my_sprite := $Character as Sprite2D
# Will fail if $AnimPlayer is not an AnimationPlayer, even if it has the method 'play()'.
($AnimPlayer as AnimationPlayer).play("walk")
Constantes
Constantes são valores que você não pode alterar quando o jogo está em execução. Seu valor deve ser conhecido na hora da compilação. Usar a palavra-chave const lhe permite dar um nome a um valor constante. Tentar atribuir uma valor a uma constante depois de declarada resultará em um erro.
Recomendamos usar constantes sempre que um valor não deve ser alterado.
const A = 5
const B = Vector2(20, 20)
const C = 10 + 20 # Constant expression.
const D = Vector2(20, 30).x # Constant expression: 20.
const E = [1, 2, 3, 4][0] # Constant expression: 1.
const F = sin(20) # 'sin()' can be used in constant expressions.
const G = x + 20 # Invalid; this is not a constant expression!
const H = A + 20 # Constant expression: 25 (`A` is a constant).
Embora o tipo das constantes seja inferido a partir do valor atribuído, também é possível adicionar uma especificação de tipo explícita:
const A: int = 5
const B: Vector2 = Vector2()
Atribuir um valor de um tipo incompatível gerará um erro.
Você também pode criar constantes dentro de uma função, o que é útil para nomear valores mágicos locais.
Enumeradores
Enumeradores são basicamente alternativas para constantes, e são muito úteis se você quer atribuir inteiros consecutivos para alguma constante.
enum {TILE_BRICK, TILE_FLOOR, TILE_SPIKE, TILE_TELEPORT}
# Is the same as:
const TILE_BRICK = 0
const TILE_FLOOR = 1
const TILE_SPIKE = 2
const TILE_TELEPORT = 3
Se você passar um nome para o enum, ele colocará todas as chaves dentro de um Dictionary constante com esse nome. Isso significa que todos os métodos constantes de um dicionário também podem ser usados com um enum nomeado. Isso só funciona para enums do GDScript, não para enums de classes integradas.
Importante
As chaves em um enum nomeado não são registradas como constantes globais. Elas devem ser acessadas prefixadas pelo nome do enum (Nome.CHAVE).
enum State {STATE_IDLE, STATE_JUMP = 5, STATE_SHOOT}
# Is the same as:
const State = {STATE_IDLE = 0, STATE_JUMP = 5, STATE_SHOOT = 6}
# Access values with State.STATE_IDLE, etc.
func _ready():
# Access values with Name.KEY, prints '5'
print(State.STATE_JUMP)
# Use dictionary methods:
# prints '["STATE_IDLE", "STATE_JUMP", "STATE_SHOOT"]'
print(State.keys())
# prints '{ "STATE_IDLE": 0, "STATE_JUMP": 5, "STATE_SHOOT": 6 }'
print(State)
# prints '[0, 5, 6]'
print(State.values())
Se você não atribuir um valor a uma chave de um enum, será atribuído a ela o valor anterior mais um, ou 0 se for a primeira entrada no enum. Múltiplas chaves com o mesmo valor são permitidas.
Funções
As funções sempre pertencem a uma classe. A prioridade de escopo para a busca de variáveis é: local → membro da classe → global. A variável self está sempre disponível e é fornecida como uma opção para acessar os membros da classe (consulte self), mas nem sempre é necessária (e não deve ser passada como o primeiro argumento da função, ao contrário do Python).
func my_function(a, b):
print(a)
print(b)
return a + b # Return is optional; without it 'null' is returned.
Uma função pode retornar em qualquer ponto. O valor padrão de retorno é null.
Por padrão, todos os parâmetros de função são obrigatórios. Você pode tornar um ou mais parâmetros ao final opcionais atribuindo um valor padrão a eles:
# Since the last two parameters are optional, all these calls are valid:
# - my_function(1)
# - my_function(1, 20)
# - my_function(1, 20, 100)
func my_function(a_required, b_optional = 10, c_optional = 42):
print(a_required)
print(b_optional)
print(c_optional)
Se uma função contiver apenas uma linha de código, ela pode ser escrita em uma única linha:
func square(a): return a * a
func hello_world(): print("Hello World")
func empty_function(): pass
As funções também podem ter especificação de tipo para os argumentos e para o valor de retorno. Os tipos para os argumentos podem ser adicionados de forma semelhante às variáveis:
func my_function(a: int, b: String):
pass
Se um argumento de função tiver um valor padrão, é possível inferir o tipo:
func my_function(int_arg := 42, String_arg := "string"):
pass
O tipo de retorno da função pode ser especificado após a lista de argumentos usando o token de seta (->):
func my_int_function() -> int:
return 0
Funções que possuem um tipo de retorno devem retornar um valor adequado. Definir o tipo como void significa que a função não retorna nada. As funções void podem retornar cedo com a palavra-chave return, mas não podem retornar nenhum valor.
func void_function() -> void:
return # Can't return a value.
Nota
Funções não void devem sempre retornar um valor, então se seu código possui instruções de ramificação (como um construtor if / else), todos os caminhos possíveis devem ter um retorno. Por exemplo, se você tiver um return dentro de um bloco if, mas não depois, o editor irá gerar um erro, porque se o bloco não for executado, a função não terá um valor válido para retornar.
Referenciando funções
As funções são valores de primeira classe em termos do objeto Callable. Referenciar uma função pelo nome sem chamá-la gerará automaticamente o callable adequado. Isso pode ser usado para passar funções como argumentos.
func map(arr: Array, function: Callable) -> Array:
var result = []
for item in arr:
result.push_back(function.call(item))
return result
func add1(value: int) -> int:
return value + 1
func _ready() -> void:
var my_array = [1, 2, 3]
var plus_one = map(my_array, add1)
print(plus_one) # Prints `[2, 3, 4]`.
Nota
Os Callables devem ser chamados com o método call(). Você não pode usar o operador () diretamente. Esse comportamento foi implementado para evitar problemas de desempenho em chamadas diretas de função.
Funções lambda
As funções lambda permitem declarar funções que não pertencem a uma classe. Em vez disso, um objeto Callable é criado e atribuído diretamente a uma variável. Isso pode ser útil para criar callables para passar adiante sem poluir o escopo da classe.
var lambda = func (x):
print(x)
Para chamar a lambda criada, você pode usar o método call():
lambda.call(42) # Prints `42`.
As funções lambda podem ser nomeadas para fins de depuração (o nome é exibido no Depurador):
var lambda = func my_lambda(x):
print(x)
Você pode especificar dicas de tipo (type hints) para funções lambda da mesma forma que para as funções comuns:
var lambda := func (x: int) -> void:
print(x)
Note que se você quiser retornar um valor de uma função lambda, um return explícito é obrigatório (você não pode omitir o return):
var lambda = func (x): return x ** 2
print(lambda.call(2)) # Prints `4`.
As funções Lambda capturam o ambiente local:
var x = 42
var lambda = func ():
print(x) # Prints `42`.
lambda.call()
Aviso
As variáveis locais são capturadas por valor uma única vez, quando a lambda é criada. Portanto, elas não serão atualizadas na lambda se forem reatribuídas na função externa:
var x = 42
var lambda = func (): print(x)
lambda.call() # Prints `42`.
x = "Hello"
lambda.call() # Prints `42`.
Além disso, uma lambda não pode reatribuir uma variável local externa. Após sair da lambda, a variável permanecerá inalterada, porque a captura da lambda implicitamente cria uma sombra (shadows) sobre ela:
var x = 42
var lambda = func ():
print(x) # Prints `42`.
x = "Hello" # Produces the `CONFUSABLE_CAPTURE_REASSIGNMENT` warning.
print(x) # Prints `Hello`.
lambda.call()
print(x) # Prints `42`.
No entanto, se você usar tipos de dados passados por referência (arrays, dicionários e objetos), as alterações de conteúdo serão compartilhadas até que você reatribua a variável:
var a = []
var lambda = func ():
a.append(1)
print(a) # Prints `[1]`.
a = [2] # Produces the `CONFUSABLE_CAPTURE_REASSIGNMENT` warning.
print(a) # Prints `[2]`.
lambda.call()
print(a) # Prints `[1]`.
Funções estáticas
Uma função pode ser declarada como estática. Quando uma função é estática, ela não tem acesso às variáveis de instância nem ao self. Uma função estática tem acesso a variáveis estáticas. Além disso, funções estáticas são úteis para criar bibliotecas de funções auxiliares:
static func sum2(a, b):
return a + b
As funções lambda não podem ser declaradas como estáticas.
Veja também Static variables e Static constructor.
Funções variádicas
Uma função variádica é uma função que pode receber um número variável de argumentos. Desde o Godot 4.5, o GDScript suporta funções variádicas. Para declarar uma função variádica, você precisa usar o parâmetro rest, que coleta todos os argumentos excedentes em um array.
func my_func(a, b = 0, ...args):
prints(a, b, args)
func _ready():
my_func(1) # 1 0 []
my_func(1, 2) # 1 2 []
my_func(1, 2, 3) # 1 2 [3]
my_func(1, 2, 3, 4) # 1 2 [3, 4]
my_func(1, 2, 3, 4, 5) # 1 2 [3, 4, 5]
Uma função pode ter no máximo um parâmetro rest, que deve ser o último na lista de parâmetros. O parâmetro rest não pode ter um valor padrão. Funções estáticas e lambdas também podem ser variádicas.
A tipagem estática também funciona para funções variádicas. No entanto, arrays tipados atualmente não são suportados como o tipo estático do parâmetro rest:
# You cannot specify `...values: Array[int]`.
func sum(...values: Array) -> int:
var result := 0
for value in values:
assert(value is int)
result += value
return result
Nota
Although you can declare functions as variadic using the rest parameter, unpacking parameters
when calling a function using spread syntax that exists in some languages (JavaScript, PHP)
is currently not supported in GDScript. However, you can use callv() to call a function
with an array of arguments:
func test_func(...args):
#log_data(...args) # This won't work.
log_data.callv(args) # This will work.
func log_data(...values):
# You should use `callv()` if you want to pass `values` as the argument list,
# rather than passing the array as the first argument.
prints.callv(values)
# You can use array concatenation to prepend/append the argument list.
write_data.callv(["user://log.txt"] + values)
func write_data(path, ...values):
# ...
Funções abstratas
Expressões e fluxo de controle
Statements are standard and can be assignments, function calls, control
flow structures, etc. (see below). ; as a statement separator is
entirely optional.
Expressões
Expressões são sequências de operadores e seus operandos de maneira ordenada. Uma expressão por si só também pode ser uma instrução, embora apenas chamadas de função façam sentido como instruções, já que outras expressões não possuem efeitos colaterais.
As expressões retornam valores que podem ser atribuídos a alvos válidos. Os operandos de algum operador podem ser outra expressão. Uma atribuição não é uma expressão e, portanto, não retorna nenhum valor.
Aqui estão alguns exemplos de expressões:
2 + 2 # Binary operation.
-5 # Unary operation.
"okay" if x > 4 else "not okay" # Ternary operation.
x # Identifier representing variable or constant.
x.a # Attribute access.
x[4] # Subscript access.
x > 2 or x < 5 # Comparisons and logic operators.
x == y + 2 # Equality test.
do_something() # Function call.
[1, 2, 3] # Array definition.
{A = 1, B = 2} # Dictionary definition.
preload("res://icon.svg") # Preload builtin function.
self # Reference to current instance.
Identificadores, atributos e subscritos são alvos de atribuição válidos. Outras expressões não podem estar no lado esquerdo de uma atribuição.
self
self pode ser usado para se referir à instância atual e geralmente é equivalente a se referir diretamente aos símbolos disponíveis no script atual. No entanto, o self também permite acessar propriedades, métodos e outros nomes que são definidos dinamicamente (ou seja, que se espera que existam em subtipos da classe atual, ou que são fornecidos usando _set() e/ou _get()).
extends Node
func _ready():
# Compile time error, as `my_var` is not defined in the current class or its ancestors.
print(my_var)
# Checked at runtime, thus may work for dynamic properties or descendant classes.
print(self.my_var)
# Compile time error, as `my_func()` is not defined in the current class or its ancestors.
my_func()
# Checked at runtime, thus may work for descendant classes.
self.my_func()
Aviso
Beware that accessing members of child classes in the base class is often considered a bad practice, because this blurs the area of responsibility of any given piece of code, making the overall relationship between parts of your game harder to reason about. Besides that, one can simply forget that the parent class had some expectations about its descendants.
if/else/elif
Condições simples são criadas usando a sintaxe if/else/elif. Parênteses ao redor de condições são permitidos, mas não obrigatórios. Dada a natureza dos recuos baseados em tabs, elif pode ser usado ao invés de else/if para manter o nível de recuo.
if (expression):
statement(s)
elif (expression):
statement(s)
else:
statement(s)
Instruções curtas podem ser escritas na mesma linha que a condição:
if 1 + 1 == 2: return 2 + 2
else:
var x = 3 + 3
return x
Às vezes, você pode querer atribuir um valor inicial diferente com base em uma expressão booleana. Nesse caso, as expressões condicionais ternárias são úteis:
var x = (value) if (expression) else (value)
y += 3 if y < 10 else -1
Expressões condicionais ternárias (ternary-if) podem ser aninhadas para lidar com mais de 2 casos. Ao aninhar expressões ternárias, recomenda-se quebrar a expressão completa em várias linhas para preservar a legibilidade:
var count = 0
var fruit = (
"apple" if count == 2
else "pear" if count == 1
else "banana" if count == 0
else "orange"
)
print(fruit) # banana
# Alternative syntax with backslashes instead of parentheses (for multi-line expressions).
# Less lines required, but harder to refactor.
var fruit_alt = \
"apple" if count == 2 \
else "pear" if count == 1 \
else "banana" if count == 0 \
else "orange"
print(fruit_alt) # banana
Você também pode desejar verificar se um valor está contido dentro de algo. Você pode usar uma instrução if combinada com o operador in para fazer isso:
# Check if a letter is in a string.
var text = "abc"
if 'b' in text: print("The string contains b")
# Check if a variable is contained within a node.
if "varName" in get_parent(): print("varName is defined in parent!")
while
Loops simples são criados usando a sintaxe while. Os loops podem ser interrompidos usando break ou continuados usando continue (que pula para a próxima iteração do loop sem executar mais nenhum código na iteração atual):
while (expression):
statement(s)
for
Para iterar através de uma faixa de valores, como em arrays ou tabelas, um loop for é usado. Quando iterando por um array, o elemento atual é armazenado na variável do loop. Ao iterar por um dicionário, a chave é armazenada na variável do loop.
for x in [5, 7, 11]:
statement # Loop iterates 3 times with 'x' as 5, then 7 and finally 11.
var names = ["John", "Marta", "Samantha", "Jimmy"]
for name: String in names: # Typed loop variable.
print(name) # Prints name's content.
var dict = {"a": 0, "b": 1, "c": 2}
for i in dict:
print(dict[i]) # Prints 0, then 1, then 2.
for i in range(3):
statement # Similar to [0, 1, 2] but does not allocate an array.
for i in range(1, 3):
statement # Similar to [1, 2] but does not allocate an array.
for i in range(2, 8, 2):
statement # Similar to [2, 4, 6] but does not allocate an array.
for i in range(8, 2, -2):
statement # Similar to [8, 6, 4] but does not allocate an array.
for c in "Hello":
print(c) # Iterate through all characters in a String, print every letter on new line.
for i in 3:
statement # Similar to range(3).
for i in 2.2:
statement # Similar to range(ceil(2.2)).
Se você deseja atribuir valores em um array enquanto ele está sendo iterado, é melhor usar for i in array.size().
for i in array.size():
array[i] = "Hello World"
A variável do loop é local para o loop for e atribuir a ela não alterará o valor no array. Objetos passados por referência (como nós) ainda podem ser manipulados chamando métodos na variável do loop.
for string in string_array:
string = "Hello World" # This has no effect
for node in node_array:
node.add_to_group("Cool_Group") # This has an effect
match
Uma expressão match é usada para ramificar a execução de um programa. É equivalente à expressão switch encontrada em muitas outras linguagens de programação, mas oferece algumas funcionalidades adicionais.
Aviso
O match é mais estrito com tipos do que o operador ==. Por exemplo, 1 não corresponderá a 1.0. A única exceção é a correspondência de String vs StringName: por exemplo, a String \"hello\" é considerada igual ao StringName &\"hello\".
Sintaxe básica
match <test value>:
<pattern(s)>:
<block>
<pattern(s)> when <pattern guard>:
<block>
<...>
Curso rápido para pessoas familiarizadas com expressões switch
Substitua
switchpormatch.Remova
case.Remova quaisquer
breaks.Troque
defaultpor um único sublinhado.
Controle de fluxo
Os padrões são correspondidos de cima para baixo. Se um padrão corresponder, o primeiro bloco correspondente será executado. Depois disso, a execução continua abaixo da instrução match.
Nota
O comportamento especial do continue em instruções match, que era suportado na versão 3.x, foi removido no Godot 4.0.
Os seguintes tipos de padrão estão disponíveis:
- Padrão literal
Corresponde a um literal:
match x: 1: print("We are number one!") 2: print("Two are better than one!") "test": print("Oh snap! It's a string!")
- Padrão de expressão
Corresponde a uma expressão constante, um identificador ou um acesso de atributo (
A.B):match typeof(x): TYPE_FLOAT: print("float") TYPE_STRING: print("text") TYPE_ARRAY: print("array")
- Padrão coringa
Este padrão compara/coincide com tudo. É escrito com uma única sublinha _ .
Ele pode ser usado como o equivalente ao
defaultem uma instruçãoswitchde outras linguagens:match x: 1: print("It's one!") 2: print("It's one times two!") _: print("It's not 1 or 2. I don't care to be honest.")
- Padrão de ligação
Um padrão de binding introduz uma nova variável. Assim como o padrão curinga, ele corresponde a qualquer valor - e também atribui um nome a esse valor. É especialmente útil em padrões de arrays e dicionários:
match x: 1: print("It's one!") 2: print("It's one times two!") var new_var: print("It's not 1 or 2, it's ", new_var)
- Padrão de matriz
Compara com um matriz. Cada elemento do padrão é um padrão por si só, para que você possa aninhá-los.
O comprimento da matriz é testado primeiro, ele tem que ter o mesmo tamanho do padrão, senão o padrão não coincide.
Matriz sem término: Uma matriz pode ser maior que o padrão deixando como último subpadrão
...Todo subpadrão precisa ser separado por vírgulas.
match x: []: print("Empty array") [1, 3, "test", null]: print("Very specific array") [var start, _, "test"]: print("First element is ", start, ", and the last is \"test\"") [42, ..]: print("Open ended array")
- Padrão de dicionário
Funciona da mesma forma que o padrão de array. Toda chave precisa ser um padrão constante.
O tamanho do dicionário é testado primeiro, ele tem que ser o mesmo tamanho do padrão, senão o padrão não coincide.
Dicionário sem término: Um dicionário pode ser maior que o padrão deixando como último subpadrão
...Qualquer subpadrão precisa ser separado por vírgulas.
Se você não especificar um valor, só a existência da chave é conferida.
Um padrão de valor é separado do padrão de chave com
:.match x: {}: print("Empty dict") {"name": "Dennis"}: print("The name is Dennis") {"name": "Dennis", "age": var age}: print("Dennis is ", age, " years old.") {"name", "age"}: print("Has a name and an age, but it's not Dennis :(") {"key": "godotisawesome", ..}: print("I only checked for one entry and ignored the rest")
- Multipadrões
Você pode especificar múltiplos padrões separando-os por uma vírgula. Esses padrões não são permitidos de ter quaisquer ligações.
match x: 1, 2, 3: print("It's 1 - 3") "Sword", "Splash potion", "Fist": print("Yep, you've taken damage")
Guardas de padrão (Pattern guards)
Uma guarda de padrão (pattern guard) é uma condição opcional que segue a lista de padrões e permite que você faça verificações adicionais antes de escolher um bloco do match. Ao contrário de um padrão, uma guarda de padrão pode ser uma expressão arbitrária.
Apenas um bloco pode ser executado por match. Assim que um bloco é escolhido, os demais não são verificados. Se você quiser usar o mesmo padrão para múltiplos blocos ou para evitar a escolha de um bloco com um padrão genérico demais, você pode especificar uma guarda de padrão após a lista de padrões usando a palavra-chave when:
match point:
[0, 0]:
print("Origin")
[_, 0]:
print("Point on X-axis")
[0, _]:
print("Point on Y-axis")
[var x, var y] when y == x:
print("Point on line y = x")
[var x, var y] when y == -x:
print("Point on line y = -x")
[var x, var y]:
print("Point (%s, %s)" % [x, y])
Se não houver um padrão correspondente para o bloco atual, a guarda de padrão não é avaliada e os padrões do próximo bloco são verificados.
Se um padrão correspondente for encontrado, a guarda de padrão é avaliada.
Se for verdadeira, o corpo do bloco é executado e o
matchtermina.Se for falso, os padrões do próximo ramo serão verificados.
Classes
Por padrão, todos os arquivos de script são classes sem nome. Nesse caso, você só pode referenciá-los usando o caminho do arquivo, seja um caminho relativo ou absoluto. Por exemplo, se você nomear um arquivo de script como character.gd:
# Inherit from 'character.gd'.
extends "res://path/to/character.gd"
# Load character.gd and create a new node instance from it.
var Character = load("res://path/to/character.gd")
var character_node = Character.new()
Registrando classes nomeadas
Você pode dar um nome à sua classe para registrá-la como um novo tipo no editor do Godot. Para isso, utiliza-se a palavra-chave class_name. Opcionalmente, você pode usar a anotação @icon com o caminho para uma imagem, para utilizá-la como ícone. Assim, sua classe aparecerá com o novo ícone no editor:
# item.gd
@icon("res://interface/icons/item.png")
class_name Item
extends Node
Dica
Imagens SVG que são usadas como ícones de nó personalizados devem ter as opções de importação Editor > Redimensionar com a Escala do Editor e Editor > Converter Cores com Tema do Editor habilitadas. Isso permite que os ícones sigam a escala do editor e as configurações de tema se os ícones foram feitos com a mesma paleta de cores que os próprios ícones do Godot.
Aqui está um exemplo de um arquivo de classe:
# Saved as a file named 'character.gd'.
class_name Character
var health = 5
func print_health():
print(health)
func print_this_script_three_times():
print(get_script())
print(ResourceLoader.load("res://character.gd"))
print(Character)
Se você quiser usar extends também, pode manter ambos na mesma linha:
class_name MyNode extends Node
Classes nomeadas são registradas globalmente, o que significa que ficam disponíveis para uso em outros scripts sem a necessidade de usar load ou preload:
var player
func _ready():
player = Character.new()
Nota
O Godot inicializa variáveis não estáticas toda vez que você cria uma instância, e isso inclui arrays e dicionários. Isso está no espírito da segurança de threads (thread safety), já que os scripts podem ser inicializados em threads separadas sem que o usuário saiba.
Aviso
O editor do Godot ocultará essas classes customizadas com nomes que começam com o prefixo "Editor" nas janelas de diálogo 'Create New Node' ou 'Create New Scene'. As classes estão disponíveis para instanciação em tempo de execução através de seus nomes de classe, mas são ocultadas automaticamente pelas janelas do editor, juntamente com os nós integrados do editor usados pelo próprio editor do Godot.
Classes e métodos abstratos
Desde o Godot 4.5, você pode definir classes e métodos abstratos usando a anotação @abstract.
Uma classe abstrata é uma classe que não pode ser instanciada diretamente. Em vez disso, ela foi feita para ser herdada por outras classes. Tentar instanciar uma classe abstrata resultará em um erro.
Um método abstrato é um método que não possui implementação. Portanto, espera-se uma nova linha ou um ponto e vírgula após o cabeçalho da função. Isso define um contrato que as classes herdeiras devem cumprir, pois a assinatura do método deve ser compatível ao ser sobrescrita.
As classes herdeiras devem fornecer implementações para todos os métodos abstratos, ou a própria classe herdeira deve ser marcada como abstrata. Se uma classe tiver pelo menos um método abstrato (seja seu próprio ou um herdado e não implementado), ela também deve ser marcada como abstrata. No entanto, o inverso não é verdadeiro: uma classe abstrata tem permissão para não ter métodos abstratos.
Dica
Se você quiser declarar um método como opcional para ser sobrescrito, deve usar um método não abstrato e fornecer uma implementação padrão.
Por exemplo, você poderia ter uma classe abstrata chamada Shape que define um método abstrato chamado draw(). Você pode então criar subclasses como Circle e Square que implementam o método draw() à sua própria maneira. Isso permite definir uma interface comum para todas as formas sem ter que implementar todos os detalhes na própria classe abstrata:
@abstract class Shape:
@abstract func draw()
# This is a concrete (non-abstract) subclass of Shape.
# You **must** implement all abstract methods in concrete classes.
class Circle extends Shape:
func draw():
print("Drawing a circle.")
class Square extends Shape:
func draw():
print("Drawing a square.")
Tanto as classes internas quanto as classes criadas usando class_name podem ser abstratas. Este exemplo cria duas classes abstratas, onde uma é uma subclasse de outra classe abstrata:
@abstract
class_name AbstractClass
extends Node
@abstract class AbstractInnerClass:
func _ready():
pass
# This is an example of a concrete subclass of `AbstractInnerClass`.
# This class can be instantiated using `AbstractClass.ConcreteInnerClass.new()`
# in other scripts, even though it's part of an abstract `class_name` script.
class ConcreteInnerClass extends AbstractInnerClass:
func _ready():
print("Concrete class ready.")
Aviso
Como uma classe abstrata não pode ser instanciada, não é possível anexar uma classe abstrata a um nó. Se você tentar fazer isso, o motor exibirá um erro ao rodar a cena:
Cannot set object script. Script '<path to script>' should not be abstract.
Classes sem nome também podem ser definidas como abstratas; a anotação @abstract deve preceder a palavra-chave extends:
@abstract
extends Node
Herança
Uma classe (salva como um arquivo) pode herdar de:
Uma classe global.
Um outro arquivo de classe.
Uma classe interna dentro de outro arquivo de classe.
Herança múltipla não é permitida.
A herança utiliza a palavra-chave extends:
# Inherit/extend a globally available class.
extends SomeClass
# Inherit/extend a named class file.
extends "somefile.gd"
# Inherit/extend an inner class in another file.
extends "somefile.gd".SomeInnerClass
Nota
Se a herança não for explicitamente definida, a classe herdará por padrão a classe RefCounted.
Para verificar se uma determinada instância herda de uma determinada classe, pode-se utilizar a palavra-chave is:
# Cache the enemy class.
const Enemy = preload("enemy.gd")
# [...]
# Use 'is' to check inheritance.
if entity is Enemy:
entity.apply_damage()
Para chamar uma função em uma superclasse (ou seja, extend-ida pela sua classe atual), use a palavra-chave super:
super(args)
Isso é especialmente útil porque funções em classes derivadas substituem funções de mesmo nome em suas superclasses. Se você ainda quiser chamá-las, pode usar super:
func some_func(x):
super(x) # Calls the same function on the super class.
Se você precisar chamar uma função diferente da superclasse, pode especificar o nome da função com o operador de atributo:
func overriding():
return 0 # This overrides the method in the base class.
func dont_override():
return super.overriding() # This calls the method as defined in the base class.
Aviso
Um dos equívocos comuns é tentar sobrescrever métodos do motor que não são virtuais, como get_class(), queue_free(), etc. Isso não é suportado por razões técnicas.
No Godot 3, você pode criar uma sombra (shadow) de métodos do motor no GDScript, e isso funcionará se você chamar esse método dentro do GDScript. No entanto, o motor não executará o seu código se o método for chamado dentro do motor em algum evento.
No Godot 4, até mesmo criar essa sombra pode não funcionar sempre, já que o GDScript otimiza as chamadas de métodos nativos. Por isso, adicionamos o aviso NATIVE_METHOD_OVERRIDE, que é tratado como um erro por padrão. Recomendamos fortemente que não desative ou ignore esse aviso.
Note que isso não se aplica a métodos virtuais como _ready(), _process() e outros (marcados com o qualificador virtual na documentação e cujos nomes começam com um sublinhado). Esses métodos são especificamente para customizar o comportamento do motor e podem ser sobrescritos no GDScript. Sinais e notificações também podem ser úteis para esses propósitos.
Construtor de classe
O construtor da classe, chamado na instanciação da classe, é nomeado _init. Se você quiser chamar o construtor da classe base, também pode usar a sintaxe super. Note que cada classe possui um construtor implícito que sempre é chamado (definindo os valores padrão das variáveis de classe). super é usado para chamar o construtor explícito:
func _init(arg):
super("some_default", arg) # Call the custom base constructor.
Isso é melhor explicado por meio de exemplos. Considere este cenário:
# state.gd (inherited class).
var entity = null
var message = null
func _init(e = null):
entity = e
func enter(m):
message = m
# idle.gd (inheriting class).
extends "state.gd"
func _init(e = null, m = null):
super(e)
# Do something with 'e'.
message = m
Têm algumas coisas para manter em mente aqui:
Se a classe herdada (
state.gd) define um construtor_initque aceita argumentos (eneste caso), então a classe que herda (idle.gd) deve definir_inittambém e passar os parâmetros apropriados para_inita partir destate.gd.idle.gdpode ter um número de argumentos diferente da classe basestate.gd.No exemplo acima, o
epassado para o construtor destate.gdé o mesmoepassado paraidle.gd.Se o construtor
_initdeidle.gdnão receber argumentos, ele ainda precisa passar algum valor para a classe basestate.gd, mesmo que não faça nada. Isso nos leva ao fato de que você também pode passar expressões para o construtor da classe base, e não apenas variáveis; por exemplo:
# idle.gd
func _init():
super(5)
Construtor estático
Um construtor estático é uma função estática _static_init que é chamada automaticamente quando a classe é carregada, após as variáveis estáticas terem sido inicializadas:
static var my_static_var = 1
static func _static_init():
my_static_var = 2
Um construtor estático não pode receber argumentos e não deve retornar nenhum valor.
Classes internas
A class file can contain inner classes. Inner classes are defined using the
class keyword. They are instantiated using the ClassName.new()
function.
# Inside a class file.
# An inner class in this class file.
class SomeInnerClass:
var a = 5
func print_value_of_a():
print(a)
# This is the constructor of the class file's main class.
func _init():
var c = SomeInnerClass.new()
c.print_value_of_a()
Classes como recursos
Classes stored as files are treated as GDScripts. They
must be loaded from disk to access them in other classes. This is done using
either the load or preload functions (see below). Instantiation of a loaded
class resource is done by calling the new function on the class object:
# Load the class resource when calling load().
var MyClass = load("myclass.gd")
# Preload the class only once at compile time.
const MyClass = preload("myclass.gd")
func _init():
var a = MyClass.new()
a.some_function()
Exportações
Nota
A documentação sobre a exportação foi movida para Propriedades exportadas do GDScript.
Propriedades (setters e getters)
Às vezes, você quer que a variável de membro de uma classe faça mais do que apenas guardar dados e realmente execute alguma validação ou computação sempre que seu valor mudar. Também pode ser desejável encapsular seu acesso de alguma forma.
Para isso, o GDScript fornece uma sintaxe especial para definir propriedades usando as palavras-chave set e get após a declaração de uma variável. Você pode então definir um bloco de código que será executado quando a variável for acessada ou atribuída.
Exemplo:
var milliseconds: int = 0
var seconds: int:
get:
return milliseconds / 1000
set(value):
milliseconds = value * 1000
Nota
Ao contrário do setget nas versões anteriores do Godot, os métodos set e get são sempre chamados (exceto conforme observado abaixo), mesmo quando acessados dentro da mesma classe (com ou sem o prefixo self.). Isso torna o comportamento consistente. Se você precisar de acesso direto ao valor, use outra variável para o acesso direto e faça o código da propriedade usar esse nome.
Sintaxe alternativa
Também há outra notação para usar funções de classe existentes se você quiser separar o código da declaração da variável ou se precisar reutilizar o código em múltiplas propriedades (mas você não poderá distinguir para qual propriedade o setter/getter está sendo chamado):
var my_prop:
get = get_my_prop, set = set_my_prop
Isso também pode ser feito na mesma linha:
var my_prop: get = get_my_prop, set = set_my_prop
O setter e o getter devem usar a mesma notação; misturar estilos para a mesma variável não é permitido.
Nota
Você não pode especificar dicas de tipo (type hints) para setters e getters inline. Isso é feito de propósito para reduzir o excesso de código (boilerplate). Se a variável for tipada, o argumento do setter será automaticamente do mesmo tipo, e o valor de retorno do getter deve corresponder a ele. Funções setter/getter separadas podem ter dicas de tipo, e o tipo deve corresponder ao tipo da variável ou ser um tipo mais amplo.
Quando o setter/getter não é chamado
When a variable is initialized, the value of the initializer will be written directly to the variable.
This occurs even if the @onready or @export annotation is applied to the variable.
Using the variable's name to set it inside its own setter or to get it inside its own getter will directly access the underlying member. This prevents infinite recursion and saves you from explicitly declaring another variable:
signal changed(new_value)
var warns_when_changed = "some value":
get:
return warns_when_changed
set(value):
changed.emit(value)
warns_when_changed = value
Isso também se aplica à sintaxe alternativa:
var my_prop: set = set_my_prop
func set_my_prop(value):
my_prop = value # No infinite recursion.
Aviso
A exceção não se propaga para outras funções chamadas no setter/getter. Por exemplo, o código a seguir causará uma recursão infinita:
var my_prop:
set(value):
set_my_prop(value)
func set_my_prop(value):
my_prop = value # Infinite recursion, since `set_my_prop()` is not the setter.
Modo de Ferramenta
Por padrão, scripts não são executados dentro do editor e apenas as propriedades exportadas podem ser alteradas. Em alguns casos, deseja-se que eles sejam executados dentro do editor (desde que não executem código do jogo ou que evitem fazê-lo manualmente). Para isso, existe a anotação @tool, que deve ser colocada no topo do arquivo:
@tool
extends Button
func _ready():
print("Hello")
Veja Executando código no editor para mais informações.
Aviso
Seja cauteloso ao liberar nós com queue_free() ou free() em um script de ferramenta (especialmente o próprio dono do script). Como os scripts de ferramentas executam o seu código no editor, o seu uso indevido pode causar falhas no editor.
Gerenciamento de memória
O Godot implementa contagem de referências (reference counting) para liberar certas instâncias que não estão mais em uso, em vez de um coletor de lixo (garbage collector) ou de exigir um gerenciamento puramente manual. Qualquer instância da classe RefCounted (or qualquer classe que a herde, como Resource) será liberada automaticamente quando não estiver mais em uso. Para uma instância de qualquer classe que não seja um RefCounted (como Node ou o tipo base Object), ela permanecerá na memória até ser deletada com free() (ou queue_free() para Nodes).
Nota
Se um Node for deletado via free() ou queue_free(), todos os seus filhos também serão deletados recursivamente.
To avoid reference cycles that can't be freed, a weakref() function is provided for creating weak references, which allow access to the object without preventing a RefCounted from freeing. Here is an example:
extends Node
var my_file_ref
func _ready():
var f = FileAccess.open("user://example_file.json", FileAccess.READ)
my_file_ref = weakref(f)
# the FileAccess class inherits RefCounted, so it will be freed when not in use
# the WeakRef will not prevent f from being freed when other_node is finished
other_node.use_file(f)
func _this_is_called_later():
var my_file = my_file_ref.get_ref()
if my_file:
my_file.close()
Alternativamente, quando não estiver usando referências, o is_instance_valid (instance) pode ser usado para verificar se um objeto foi liberado.
Sinais
Sinais são um modo de enviar mensagens de um objeto para que outros objetos possam reagir. Crie sinais personalizados para uma classe usando a palavra-chave signal.
extends Node
# A signal named health_depleted.
signal health_depleted
Nota
Sinais são um mecanismo de Callback. Eles também preenchem o papel de observadores, um padrão de programação comum. Para mais informações, leia o tutorial Observer tutorial no ebook Game Programming Patterns.
Você pode conectar esses sinais a métodos da mesma forma que conecta sinais integrados de nós como Button ou RigidBody3D.
In the example below, we connect the health_depleted signal from a
Character node to a Game node. When the Character node emits the
signal, the Game node's _on_character_health_depleted is called:
# game.gd
func _ready():
var character_node = get_node('Character')
character_node.health_depleted.connect(_on_character_health_depleted)
func _on_character_health_depleted():
get_tree().reload_current_scene()
Você pode emitir quantos argumentos desejar com um sinal.
Aqui está um exemplo em que isso é útil. Digamos que queremos que uma barra de vida na tela reaja às mudanças de saúde com uma animação, mas queremos manter a interface do usuário separada do player em nossa árvore de cenas.
Em nosso script character.gd, definimos um sinal health_changed e o emitimos com Signal.emit(); então, a partir de um nó Game em um nível superior da árvore de cenas, conectamo-lo à Lifebar usando o método Signal.connect():
# character.gd
...
signal health_changed
func take_damage(amount):
var old_health = health
health -= amount
# We emit the health_changed signal every time the
# character takes damage.
health_changed.emit(old_health, health)
...
# lifebar.gd
# Here, we define a function to use as a callback when the
# character's health_changed signal is emitted.
...
func _on_Character_health_changed(old_value, new_value):
if old_value > new_value:
progress_bar.modulate = Color.RED
else:
progress_bar.modulate = Color.GREEN
# Imagine that `animate` is a user-defined function that animates the
# bar filling up or emptying itself.
progress_bar.animate(old_value, new_value)
...
No nó Game, obtemos ambos os nós Character e Lifebar, em seguida, conectamos o personagem, que emite o sinal ao receptor, o nó Lifebar nesse caso.
# game.gd
func _ready():
var character_node = get_node('Character')
var lifebar_node = get_node('UserInterface/Lifebar')
character_node.health_changed.connect(lifebar_node._on_Character_health_changed)
Isso permite que a Lifebar reaja às alterações de saúde sem acoplá-la ao nó Character.
Você pode escrever os nomes dos argumentos opcionais entre parênteses após a definição do sinal:
# Defining a signal that forwards two arguments.
signal health_changed(old_value, new_value)
Esses argumentos aparecem na aba Sinais (Signals) do editor, e o Godot pode usá-los para gerar funções de callback para você. No entanto, você ainda pode emitir qualquer número de argumentos ao emitir sinais; cabe a você emitir os valores corretos.
Você também pode criar cópias de objetos Callable do GDScript que aceitam argumentos adicionais usando Callable.bind(). Isso permite adicionar informações extras à conexão se o próprio sinal emitido não der acesso a todos os dados que você precisa.
Quando o sinal é emitido, o método de callback recebe os valores vinculados (bound values), além daqueles fornecidos pelo sinal.
Com base no exemplo acima, digamos que queiramos exibir na tela um registro do dano sofrido por cada personagem, como Player1 sofreu 22 de dano. O sinal health_changed não nos fornece o nome do personagem que sofreu o dano. Portanto, ao conectar o sinal ao console do jogo em execução, podemos adicionar o nome do personagem usando o método bind:
# game.gd
func _ready():
var character_node = get_node('Character')
var battle_log_node = get_node('UserInterface/BattleLog')
character_node.health_changed.connect(battle_log_node._on_Character_health_changed.bind(character_node.name))
Nosso nó BattleLog recebe cada elemento vinculado como um argumento adicional:
# battle_log.gd
func _on_Character_health_changed(old_value, new_value, character_name):
if not new_value <= old_value:
return
var damage = old_value - new_value
label.text += character_name + " took " + str(damage) + " damage."
Aguardando sinais ou corrotinas (Awaiting)
A palavra-chave await pode ser usada para criar corrotinas que aguardam até que um sinal seja emitido antes de continuar a execução. Usar a palavra-chave await com um sinal ou uma chamada para uma função que também é uma corrotina retornará imediatamente o controle para quem fez a chamada. Quando o sinal for emitido (ou a corrotina chamada terminar), a execução será retomada a partir do ponto onde parou.
Por exemplo, para parar a execução até que o usuário pressione um botão, você pode fazer algo assim:
func wait_confirmation():
print("Prompting user")
await $Button.button_up # Waits for the button_up signal from Button node.
print("User confirmed")
return true
Neste caso, a função wait_confirmation se torna uma corrotina, o que significa que quem a chama também precisa usar o await nela:
func request_confirmation():
print("Will ask the user")
var confirmed = await wait_confirmation()
if confirmed:
print("User confirmed")
else:
print("User canceled")
Note que solicitar o valor de retorno de uma corrotina sem o await gerará um erro:
func wrong():
var confirmed = wait_confirmation() # Will give an error.
No entanto, se você não depender do resultado, pode apenas chamá-la de forma assíncrona, o que não interromperá a execução e não transformará a função atual em uma corrotina:
func okay():
wait_confirmation()
print("This will be printed immediately, before the user press the button.")
If you use await with an expression that isn't a signal nor a coroutine, the value will be returned immediately and the
function won't give the control back to the caller:
func no_wait():
var x = await get_five()
print("This doesn't make this function a coroutine.")
func get_five():
return 5
Isso também significa que retornar um sinal de uma função que não é uma corrotina fará com que quem chamou aguarde (await) por esse sinal:
func get_signal():
return $Button.button_up
func wait_button():
await get_signal()
print("Button was pressed")
Nota
Ao contrário do yield nas versões anteriores do Godot, você não pode obter o objeto de estado da função (function state object). Isso é feito para garantir a segurança de tipos. Com essa segurança de tipos em vigor, uma função não pode dizer que retorna um int enquanto na verdade retorna um objeto de estado de função em tempo de execução.
Você pode armazenar os argumentos passados para os parâmetros do sinal. Se houver apenas um parâmetro, o valor aguardado terá o mesmo tipo que o argumento:
func toggled():
var signal_args = await $Button.toggled
assert(typeof(signal_args) == TYPE_BOOL)
Se houver mais de um parâmetro, o valor aguardado será do tipo Array:
func request_completed():
var signal_args = await $HTTPRequest.request_completed
assert(typeof(signal_args) == TYPE_ARRAY)
Caso contrário, o valor aguardado será null:
func button_up():
var signal_args = await $Button.button_up
assert(signal_args == null)
Palavra-chave assert
A palavra-chave assert pode ser usada para checar detalhes em compilações de depuração. Essas asserções são ignoradas em compilações sem depuração. Isso significa que a expressão passada como argumento não será avaliada num projeto exportado em modo de lançamento. Por esse motivo, elas não devem conter expressões que sejam importantes para o código funcionar. Caso contrário, o comportamento do script variará dependendo se está compilando em modo depuração ou não.
# Check that 'i' is 0. If 'i' is not 0, an assertion error will occur.
assert(i == 0)
Se ocorrer um erro de asserção enquanto estiver no modo de edição, o projeto sera pausado.
Você pode opcionalmente passar uma mensagem de erro personalizada para ser exibida se a asserção falhar:
assert(enemy_power < 256, "Enemy is too powerful!")
Comentários
Qualquer coisa desde um
#até o fim da linha é ignorada e é considerada como um comentário.# This is a comment.Dica
No editor de script do Godot, palavras-chave especiais são destacadas dentro de comentários para chamar a atenção do usuário para comentários específicos:
Crítico (aparece em vermelho):
ALERT,ATTENTION,CAUTION,CRITICAL,DANGER,SECURITYAviso (aparece em amarelo):
BUG,DEPRECATED,FIXME,HACK,TASK,TBD,TODO,WARNINGAviso/Nota (aparece em verde):
INFO,NOTE,NOTICE,TEST,TESTINGEssas palavras-chave diferenciam maiúsculas de minúsculas, portanto devem ser escritas em letras maiúsculas para serem reconhecidas:
A lista de palavras-chave destacadas e suas cores pode ser alterada na seção Text Editor > Theme > Comment Markers das Configurações do Editor.
Use dois símbolos de cerquilha (
##) em vez de um (#) para adicionar um comentário de documentação, que aparecerá na documentação do script e na descrição do inspetor de uma variável exportada. Os comentários de documentação devem ser colocados diretamente acima de um item documentável (como uma variável de membro) ou no topo de um arquivo. Opções de formatação dedicadas também estão disponíveis. Veja Comentários de documentação do GDScript para mais detalhes.