Básicos do GDScript

Introdução

GDScript é uma linguagem de auto nível, dinâmicamente tipada, usada para criar conteúdo. Utiliza uma sintaxe similar a do Python (blocos são baseados em indentação e muitas palavras-chave são similares). Seu objetivo é ser otimizada para e firmemente integrada ao motor Godot, permitindo grande flexibilidade para a criação e integração de conteúdo.

História

Nota

A documentação sobre a história do GDScript foi movida para o Frequently Asked Questions.

Exemplo de GDScript

Algumas pessoas conseguem aprender melhor observando a sintaxe, então aqui está um simples exemplo de como o GDScript parece.

# A file is a class!

# Inheritance

extends BaseClass

# (optional) class definition with a custom icon

class_name MyClass, "res://path/to/optional/icon.svg"


# Member variables

var a = 5
var s = "Hello"
var arr = [1, 2, 3]
var dict = {"key": "value", 2: 3}
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

func some_function(param1, param2):
    var local_var = 5

    if param1 < local_var:
        print(param1)
    elif param2 > 5:
        print(param2)
    else:
        print("Fail!")

    for i in range(20):
        print(i)

    while param2 != 0:
        param2 -= 1

    var local_var2 = param1 + 3
    return local_var2


# Functions override functions with the same name on the base/parent class.
# If you still want to call them, use '.' (like 'super' in other languages).

func something(p1, p2):
    .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 linguagems 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.

Linguagem

A seguir, uma visão geral é dada sobre o GDScript. Detalhes, como quais métodos são disponíveis para arrays ou outros objetos, devem ser vistos nas descrições da classe relacionada.

Identificadores

Qualquer string que se restringe a caracteres alfabéticos("a" à "z" e "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. Identificadore são case-sensitive ("foo" é diferente de "FOO").

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.
break Sai da execução do atual laço for ou while.
continue Pula imediatamente a próxima iteração do laço for ou while.
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 Defines an inner class.
class_name Defines a class name and optional icon for your script.
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.
as Transmita o valor para um determinado tipo, se possível.
self Refere-se a instância atual da classe.
tool Executa o script no editor.
signal Define um sinal.
func Define uma função.
static Define uma função estática. Variáveis membro estáticas não são permitidas.
const Define uma constante.
enum Define um enumerador.
var Define uma variável.
onready Inicializa uma variável quando o Nó ao qual o script está anexado e os seus filhos fizerem parte da árvore da cena.
export Salva a variável junto com o recurso que ela está ligada e a torna visível e modificável no editor.
setget Define funções setter e getter para uma variável.
breakpoint Ajudante do Editor para debugar pontos de parada.
preload Pré-carrega uma classe ou uma variável. Consulte 'Classes como recursos' _.
conceder Co-rotina de suporte. Consulte " co-rotinas com o rendimento`_.
assert Declara uma condição, erro de logs em caso de falha. Ignorado em compilações de não-depuração. Consulte 'Afirmar a palavra-chave' _.
remote Anotação de RPC de redes. Consulte: ref: 'documentos de multijogador de alto nível <doc_high_level_multiplayer>'.
master Anotação de RPC de redes. Consulte: ref: 'documentos de multijogador de alto nível <doc_high_level_multiplayer>'.
fantoche Anotação de RPC de redes. Consulte: ref: 'documentos de multijogador de alto nível <doc_high_level_multiplayer>'.
remotesync Anotação de RPC de redes. Consulte: ref: 'documentos de multijogador de alto nível <doc_high_level_multiplayer>'.
mastersync Anotação de RPC de redes. Consulte: ref: 'documentos de multijogador de alto nível <doc_high_level_multiplayer>'.
puppetsync Anotação de RPC de redes. Consulte: ref: 'documentos de multijogador de alto nível <doc_high_level_multiplayer>'.
PI A constante PI.
TAU A constante TAU.
INF Constante de infinito. Usada para comparações.
NAN Constante de NAN (não um número). Usada para comparações.

Operadores

A seguir, está a lista de operadores suportados e sua precedência.

Operador Descrição
x[index] Inscrição (prioridade máxima)
x.attribute Referência de atributo
foo() Chamada de função
is Checagem de tipo de instância
~ NÃO Binário
-x Negativo / Negação unária
* / %

Multiplicação / Divisão / Resto

Esses operadores têm o mesmo comportamento que o C ++. A divisão inteira é truncada em vez de retornar um número fracionário, e o operador% está disponível apenas para ints ("fmod" para floats)

+ Adição / Concatenação de matrizes
- Subtração
<< >> Deslocamento de bits
& E Binário
^ OU EXCLUSIVO Binário
| OU Binário
< > == != >= <= Comparações
in Teste de conteúdo
! not NÃO Booleano
and && E Booleano
or || OU Booleano
if x else if/else Ternário
as Type casting
= += -= *= /= %= &= |= Atribuição (menor prioridade)

Literais

Literal Tipo
45 Inteiro Base 10
0x8f51 Inteiro de base 16 (hexadecimal)
0b101010 Inteiro de base 2 (binário)
3.14, 58.1e-10 Número de ponto flutuante (real)
"Olá", "Oi" Strings
"""Olá""" String com múltiplas linhas
@"Nodo/Rotulo" NodePath ou StringName
$NodePath Forma abreviada para get_node("NodePath")

Integers and floats can have their numbers separated with _ to make them more readable. The following ways to write numbers are all valid:

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.

Comentários

Qualquer coisa desde um # até o fim da linha é ignorada e é considerada como um comentário.

# This is a comment.

Tipos definidos por padrão

Tipos embutidos são alocados em pilha. Eles são passados como valores. Isso significa que uma cópia é criada em cada atribuição ou quando passadas como argumentos para funções. As únicas exceções são Arrays e Dictionaries, que são passados por referência e portanto são compartilhados. (Matrizes agrupadas como PoolByteArray ainda são passadas como valores.)

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.

bool

Abreviação de "booleano", pode conter apenas true ou false.

int

Abreviação de "inteiro", armazena valores inteiros(positivos e negativos). Ele é 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. Ele é armazenado como um valor de 64 bits, equivalente a "Double " em C++. Observação: atualmente, estruturas de dados, como Vector2, Vector3 e PoolRealArray armazenam 32 bit de ponto flutuante, ou seja 32 números após a virgula.

String

A sequence of characters in Unicode format. Strings can contain the following escape sequences:

Escape sequence Expands to
\n Newline (line feed)
\t Horizontal tab character
\r Carriage return
\a Alert (beep/bell)
\b Backspace
\f Formfeed page break
\v Vertical tab character
\" Double quote
\' Single quote
\\ Backslash
\uXXXX Unicode codepoint XXXX (hexadecimal, case-insensitive)

GDScript also supports Formatação de Strings em GDScript.

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.

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.

Transform2D

Matrix de 3x2 usada para transformações em 2D.

Plane

Tipo Plano 3D em formato normalizado que contém um campo vetorial "normal" e uma distância escalar "d".

Quat

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

Matrix 3x3 usada para rotação 3D e escala. Ela contem 3 campos vetoriais ("x", "y" e "z") e também pode ser acessada como um array de vetores 3D.

Transform

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.

NodePath

O caminho compilado para um nodo usado principalmente no sistema de cenas. Ele pode ser facilmente atribuído para, e a partir de, uma String.

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].

Matrizes em GDScript são alocadas linearmente na memória para aumentar sua velocidade. Matrizes muito grandes (mais de dezenas de milhares de elementos) podem, no entanto, causar fragmentação de memória. Se isso for uma preocupação, existem tipos especiais de matriz. Estas aceitam apenas um único tipo de dados. Elas evitam a fragmentação de memória e também usam menos memória, mas são atômicas e tendem a ser mais lentas que as matrizes genéricas. Portanto, elas são recomendadas somente para grandes conjuntos de dados:

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"
}

Sintaxe de tabela no estilo Lua também é suportada. O estilo Lua usa = ao invés de : e não usa aspas para marcar chaves que são strings (diminuindo a quantidade de escrita). Note, no entanto, que como qualquer identificador GDScript, chaves escritas desta forma não podem começar com dígitos.

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 isso como uma chave existente e atribua a isso:

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

The bracket syntax can be used to access properties of any Object, not just Dictionaries. Keep in mind it will cause a script error when attempting to index a non-existing property. To avoid this, use the Object.get() and Object.set() methods instead.

Dados

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 order.

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 = Sprite.new()

Se a variável for inicializada dentro da declaração, o tipo pode ser inferido, então é possível omitir o nome do tipo:

var my_vector2 := Vector2() # 'my_vector2' is of type 'Vector2'.
var my_node := Sprite.new() # 'my_node' is of type 'Sprite'.

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 da engine (Node, Resource, Reference, etc.).
  • Nomes constantes se eles contiverem um recurso de script (`` MyScript`` se você declarar `` const MyScript = preload ("res: //my_script.gd") ``).
  • Outras classes no mesmo script, respeitando o escopo (InnerClass.NestedClass se você declarou classNestedClass dentro da classInnerClass no mesmo escopo).
  • Classes de script declaradas com a palavra-chave `` class_name``.

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 = $Sprite as Node2D # Works since Sprite is a subtype of Node2D.

Se o valor não for um subtipo, a operação de conversão 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.

Conversão também é útil para ter melhores variáveis de tipo seguro ao interagir com a árvore da cena:

# Will infer the variable to be of type Sprite.
var my_sprite := $Character as Sprite

# Will fail if $AnimPlayer is not an AnimationPlayer, even if it has the method 'play()'.
($AnimPlayer as AnimationPlayer).play("walk")

Constantes

Constants are values you cannot change when the game is running. Their value must be known at compile-time. Using the const keyword allows you to give a constant value a name. Trying to assign a value to a constant after it's declared will give you an error.

We recommend using constants whenever a value is not meant to change.

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 de constantes seja inferido a partir do valor atribuído, também é possível adicionar especificação de tipo explícito:

const A: int = 5
const B: Vector2 = Vector2()

Atribuir um valor de um tipo incompatível gerará um erro.

Nota

Since arrays and dictionaries are passed by reference, constants are "flat". This means that if you declare a constant array or dictionary, it can still be modified afterwards. They can't be reassigned with another value though.

Enumeradores

Enumeradores são basicamente alternativas para constantes, e são muito úteis se você quer atribuir inteiros consecutivos para alguma constante.

Se você passar um nome para um enum, ele irá colocar todas as chaves dentro de um dicionário constante com aquele nome.

Importante

A partir do Godot 3.1, chaves em um enum nomeado não são registradas como constantes globais. Elas devem ser acessadas com o prefixo do nome do enum (Name.KEY); veja no exemplo abaixo.

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

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.

Funções

Funções sempre pertencem a class. A prioridade de escopo para a procura de variáveis é: local → membro da classe → global. A variável self é sempre disponível e é fornecida como uma opção para acessar membros da classe, mas não é sempre necessária (e , diferente do Python, não deve ser enviada como o primeiro argumento de uma função).

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.

Funções também podem ter especificação de tipo para os argumentos e para o valor de retorno. Tipos de 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.

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

Ao contrário do Python, funções não são objetos de primeira-classe em GDScript. Isso significa que elas não podem ser armazenadas em variáveis, passadas como argumento para outras funções ou retornadas de outras funções. Essas limitações são por motivos de performance.

Para referenciar uma função pelo nome durante o tempo de execução, (ex: para armazenar em uma variável, ou passar para uma outra função como um argumento) você precisa usar os auxiliares call ou funcref:

# Call a function by name in one step.
my_node.call("my_function", args)

# Store a function reference.
var my_func = funcref(my_node, "my_function")
# Call stored function reference.
my_func.call_func(args)

Funções estáticas

Uma função pode ser declarada como estática. Quando uma função é estática, ela não possui acesso as variáveis de instância ou ao self. Isso é útil principalmente para a criação de bibliotecas de funções auxiliares:

static func sum2(a, b):
    return a + b

Expressões e fluxo de controle

Expressões são padrão e podem ser atribuições, chamadas de função, estruturas de controle, etc (veja abaixo). ; como um separador de expressões é inteiramente opcional.

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)

Expressões curtas podem ser escritas na mesma linha da 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 baseado em uma expressão booleana. Nesse caso, expressões do tipo if-ternário são úteis:

var x = [value] if [expression] else [value]
y += 3 if y < 10 else -1

while

Laços simples são criados utilizando a sintaxe while. Laços podem ser interrompidos utilizando break ou continuados utilizando continue:

while [expression]:
    statement(s)

for

To iterate through a range, such as an array or table, a for loop is used. When iterating over an array, the current array element is stored in the loop variable. When iterating over a dictionary, the key is stored in the loop variable.

for x in [5, 7, 11]:
    statement # Loop iterates 3 times with 'x' as 5, then 7 and finally 11.

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

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.

Sintaxe básica:

match [expression]:
    [pattern](s):
        [block]
    [pattern](s):
        [block]
    [pattern](s):
        [block]

Curso rápido para pessoas familiarizadas com expressões switch:

  1. Substitua switch por match.
  2. Remova case.
  3. Remova todos os breaks. Se você não quer interromper (break) por padrão, você pode usar continue para contornar.
  4. Troque default por um único sublinhado.

Controle de fluxo:

The patterns are matched from top to bottom. If a pattern matches, the first corresponding block will be executed. After that, the execution continues below the match statement. You can use continue to stop execution in the current block and check for an additional match in the patterns below it.

Há 6 tipos de padrões:

  • Padrão de constante

    Constantes primitivas, como números e textos:

    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 variável

    Compara o conteúdo de uma variável/enumeração:

    match typeof(x):
        TYPE_REAL:
            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 _ .

    Pode ser usado como equivalente ao default de uma expressão switch em 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 ligação introduz uma nova variável. Como o padrão coringa, ele coincide com tudo – e ainda dá a esse valor um nome. É útil especialmente para padrões de matriz e de dicionário.

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

Classes

Por padrão, todos os arquivos de scripts são classes sem nome. Neste caso, você só irá poder os referenciar usando o caminho do arquivo, usando tanto um caminho relativo como um absoluto. Por exemplo, se você nomear um arquivo de script 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()

No entanto, você pode dar um nome a sua classe para registrá-la como um novo tipo no editor do Godot. Para isso, você pode usar a palavra chave class_name. Você pode adicionar uma vírgula opcional seguida de um caminho para uma imagem, para utilizar como ícone. Sua classe, aparecerá, então, com seu novo ícone no editor:

# Item.gd

extends Node
class_name Item, "res://interface/icons/item.png"
../../../_images/class_name_editor_register_example.png

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)

Nota

A sintaxe da classe do Godot é compacta: ela só pode conter variáveis membros ou funções. Você pode utilizar funções estáticas, mas não membros variáveis não-estáticas. Do mesmo modo, o motor inicializará variáveis toda vez que você criar uma instância, e isso inclui arrays e dicionários. Isso serve para segurança de threads, já que scripts podem ser inicializados em threads separados sem que o usuário saiba.

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.

Herança usa 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

Para verificar se uma certa instância herda de uma certa classe, a palavra-chave is (é) pode ser usada:

# 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 classe base (ex: um extend-ido em sua classe atual), insira um . no início do nome da função:

.base_func(args)

Isso é especialmente útil porque funções em classes extendidas substituem as funções com o mesmo nome em suas classes de base. Então se você ainda quiser chamá-los, você pode usar . no início (como a palavra-chave super em outras linguagens):

func some_func(x):
    .some_func(x) # Calls the same function on the parent class.

Nota

Funções padrão como _init, e a maioria das notificações como _enter_tree, _exit_tree, _process, _physics_process, etc. são chamadas em todas as classes base automaticamente. Não é necessário chamá-las explicitamente quando estiver sobrecarregando-as.

Construtor de Classe

O construtor de classe, chamada ao criar uma instância da classe, é chamado de _init. Como mencionado anteriormente, os construtores de classes-pai são chamados automaticamente ao herdar uma classe. Então não costuma haver necessidade de chamar ._init() explicitamente.

Ao contrário da chamada de uma função normal, como no exemplo acima com .some_func, se o construtor da classe herdada tiver argumentos, serão passados da seguinte forma:

func _init(args).(parent_args):
   pass

Isso é melhor explicado através de exemplos. Suponha que tenhamos tal 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).(e):
    # Do something with 'e'.
    message = m

Têm algumas coisas para manter em mente aqui:

  1. Se a classe herdada (State.gd) definir um construtor _init que precisa de argumentos (e nesse caso) então a classe que herda (Idle.gd) precisa definir um _init também, e passar os parâmetros apropriados para o _init de State.gd.

  2. Idle.gd pode ter um número diferente de argumentos que a classe base State.gd.

  3. No exemplo acima, e passado para o construtor de State.gd é o mesmo e que foi passado para o Idle.gd.

  4. Se o construtor _init de Idle.gd não precisa de argumentos, ele ainda precisa passar algum valor para a classe base State.gd, mesmo que ele não faça nada. Isso nos leva ao fato que você pode passar valores literais ao construtor também, não só variáveis. ex:

    # Idle.gd
    
    func _init().(5):
        pass
    

Classes internas

Um arquivo de classe pode conter classes internas. Elas são definidas usando a palavra-chave class. Instâncias podem ser criadas usando a função NomeDaClasse.new().

# 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 armazenadas em arquivos são tratadas como resources. Elas podem ser carregadas do disco para acessá-las em outras classes. Isso é feito ou pela função load ou pela preload (veja abaixo). Instâncias de uma classe carregada como recurso são feitas chamando a função new no objeto da classe:

# Load the class resource when calling load().
var my_class = 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 Exports no GDScript.

Setters (setadores) /getters (coletores)

É muito comum ser útil saber quando uma variável membro de classe se altera por qualquer que seja o motivo. Também pode ser desejado encapsular seu acesso de alguma forma.

Para isso, a GDScript provê uma sintaxe de setter/getter usando a palavra-chave setget, usada diretamente depois de uma definição de variável:

var variable = value setget setterfunc, getterfunc

Sempre que o valor da variável for modificado por uma fonte externa (não por uso local na classe), a função setter (setterfunc acima) será chamada. Isso acontece antes do valor ser mudado. O setter precisa decidir o que fazer com o novo valor. Do mesmo modo, quando variable é acessado, a função getter (getterfunc acima) precisa retornar (return) o valor desejado. A seguir um exemplo:

var my_var setget my_var_set, my_var_get


func my_var_set(new_value):
    my_var = new_value


func my_var_get():
    return my_var # Getter must return a value.

Qualquer uma das funções setter ou getter podem ser omitidas:

# Only a setter.
var my_var = 5 setget my_var_set
# Only a getter (note the comma).
var my_var = 5 setget ,my_var_get

Setters e getters são úteis especialmente ao exportar variáveis ao editor em scripts de ferramentas ou plugins, para validação de entrada.

Como dito, acesso local não irá iniciar o setter e getter. Aqui temos uma ilustração disso:

func _init():
    # Does not trigger setter/getter.
    my_integer = 5
    print(my_integer)

    # Does trigger setter/getter.
    self.my_integer = 5
    print(self.my_integer)

Modo de Ferramenta

Scripts, por padrão, não executam dentro do editor e apenas as propriedades exportadas podem ser modificadas. Em alguns casos, é desejável que eles rodem dentro do editor (enquanto eles não executem código do jogo ou evitem manualmente de fazer isso). Para isso, a palavra tool existe e deve ser colocada no topo do arquivo:

tool
extends Button


func _ready():
    print("Hello")

Veja Running code in the 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

If a class inherits from Reference, then instances will be freed when no longer in use. No garbage collector exists, just reference counting. By default, all classes that don't define inheritance extend Reference. If this is not desired, then a class must inherit Object manually and must call instance.free(). To avoid reference cycles that can't be freed, a weakref function is provided for creating weak references.

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 customizados 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.

Esses sinais podem ser conectados a métodos da mesma forma com que você conecta sinais embutidos de nós como Button ou RigidBody.

No exemplo abaixo, conectamos o sinal health_depleted de um nó Character a um nó Game. Quando o nó Character emite o sinal, a função _on_Character_health_depleted é chamada no nó Game:

# Game.gd

func _ready():
    var character_node = get_node('Character')
    character_node.connect("health_depleted", self, "_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: ref: Object.emit_signal () <class_Object_method_emit_signal> e no nó `` Game`` acima na árvore de cenas, nós a conectamos à `` Lifebar`` usando o método: ref: Object.connect () <class_Object_method_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.
    emit_signal("health_changed", 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)
...

Nota

Para usar sinais, sua classe precisa estender a classe do``Object`` ou alguma classe como``Node``, KinematicBody, Control...

No nó `` Game``, obtemos os nós `` Character`` e `` Lifebar``, em seguida, conectamos o personagem, que emite o sinal ao receptor`` Lifebar`` nesse caso.

# Game.gd

func _ready():
    var character_node = get_node('Character')
    var lifebar_node = get_node('UserInterface/Lifebar')

    character_node.connect("health_changed", 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 nomes de argumento 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)

Estes argumentos aparecem na aba Nó do editor, e o Godot pode usá-los para criar funções para você. Entretanto, você ainda pode emitir qualquer número de argumento quando você emite sinais; é você quem tem que emitir os valores corretos.

../../../_images/gdscript_basics_signals_node_tab_1.png

GDScript pode passar uma matriz de argumentos a conexões entre um sinal e um método. Quando o sinal é emitido, chamando o método conectado, os argumentos são dados ao método. Esses argumentos são específicos a cada conexão, e os valores ficarão iguais.

Você pode usar essa matriz de valores para adicionar informações extras constantes à conexão, se o próprio sinal emitido não der acesso a todos os dados necessários.

Com base no exemplo acima, vamos dizer que queremos exibir um log dos danos recebidos por cada personagem na tela, como Player1 levou 22 de dano.. O sinal health_changed não fornece o nome do personagem que levou dano. Então quando conectamos o sinal ao console in-game, podemos adicionar o nome do personagem no argumento da matriz de ligações:

# Game.gd

func _ready():
    var character_node = get_node('Character')
    var battle_log_node = get_node('UserInterface/BattleLog')

    character_node.connect("health_changed", battle_log_node, "_on_Character_health_changed", [character_node.name])

Nosso nó ``BattleLog `` recebe cada elemento na matriz de vínculos como um argumento extra:

# BattleLog.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."

Corrotinas com yield

GDScript oferece suporte para corrotinas através do comando embutido yield. Chamar yield() irá sair imediatamente da função atual, com o estado atual congelado desta mesma função como valor de retorno. Chamar resume() neste objeto resultante irá continuar a execução da função original do ponto que parou e retornar o que quer que a função retorne. Assim que retomada a execução da função suspensa, o objeto de estado se torna inválido. Aqui está um exemplo:

func my_func():
    print("Hello")
    yield()
    print("world")


func _ready():
    var y = my_func()
    # Function state saved in 'y'.
    print("my dear")
    y.resume()
    # 'y' resumed and is now an invalid state.

Imprimirá:

Hello
my dear
world

Também é possível passar valores entre yield() e resume(), por exemplo:

func my_func():
    print("Hello")
    print(yield())
    return "cheers!"


func _ready():
    var y = my_func()
    # Function state saved in 'y'.
    print(y.resume("world"))
    # 'y' resumed and is now an invalid state.

Imprimirá:

Hello
world
cheers!

Lembre-se de salvar o estado da nova função, ao utilizar múltiplos yields:

func co_func():
    for i in range(1, 5):
        print("Turn %d" % i)
        yield();


func _ready():
    var co = co_func();
    while co is GDScriptFunctionState && co.is_valid():
        co = co.resume();

Corrotinas e sinais

O verdadeiro poder de utilizar yield é quando combinado com sinais. yield pode aceitar até dois parâmetros, um objeto e um sinal. Quando o sinal é recebido, a execução irá recomeçar. Abaixo temos alguns exemplos:

# Resume execution the next frame.
yield(get_tree(), "idle_frame")

# Resume execution when animation is done playing.
yield(get_node("AnimationPlayer"), "animation_finished")

# Wait 5 seconds, then resume execution.
yield(get_tree().create_timer(5.0), "timeout")

As próprias corrotinas usam o sinal `` completed`` quando fazem a transição para um estado inválido, por exemplo:

func my_func():
    yield(button_func(), "completed")
    print("All buttons were pressed, hurray!")


func button_func():
    yield($Button0, "pressed")
    yield($Button1, "pressed")

`` my_func`` somente continuará a execução assim que ambos os botões forem pressionados.

You can also get the signal's argument once it's emitted by an object:

# Wait for when any node is added to the scene tree.
var node = yield(get_tree(), "node_added")

If you're unsure whether a function may yield or not, or whether it may yield multiple times, you can yield to the completed signal conditionally:

func generate():
    var result = rand_range(-1.0, 1.0)

    if result < 0.0:
        yield(get_tree(), "idle_frame")

    return result


func make():
    var result = generate()

    if result is GDScriptFunctionState: # Still working.
        result = yield(result, "completed")

    return result

This ensures that the function returns whatever it was supposed to return regardless of whether coroutines were used internally. Note that using while would be redundant here as the completed signal is only emitted when the function didn't yield anymore.

Palavra-chave 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")

Isto pode ficar meio confuso, especialmente com muitos nós e referências externas. Para isso, GDScript tem a palavra-chave onready, que atrasa a inicialização da variável de um membro até que _ready() seja chamado. Ela pode substituir o código acima por uma única linha:

onready var my_label = get_node("MyLabel")

Palavra-chave assert

A palavra-chave assert pode ser usada para checar detalhes de depuração de builds. Essas asserções são ignoradas em compilações sem depuração. Isso significa que a expressão passada como argumento não vai ser compilada no projeto final. 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.