GDScript basics

Introdução

GDScript is a high-level, dynamically typed programming language used to create content. It uses a syntax similar to Python (blocks are indent-based and many keywords are similar). Its goal is to be optimized for and tightly integrated with Godot Engine, allowing great flexibility for content creation and integration.

História

In the early days, the engine used the Lua scripting language. Lua is fast, but creating bindings to an object oriented system (by using fallbacks) was complex and slow and took an enormous amount of code. After some experiments with Python, it also proved difficult to embed.

A última linguagem script de terceiros que foi utilizada para jogos lançados foi Squirrel, mas ela também for largada. Naquele ponto, se tornou evidente que uma linguagem script personalizada poderia fazer um melhor uso da arquitetura particular do Godot:

  • Godot embute scripts em nós. A maioria das linguagem não é projetada com isso em mente.
  • Godot usa vários tipos de dados embutidos para realizar operações matemáticas 2D e 3D. Linguagems de script não forneçem isso, e realizar ligações para obtê-los é ineficiente.
  • Godot faz uso pesado de threads para o levantamento e inicialização de dados vindos da rede ou do disco. Os interpretadores de script das linguagens comuns não são amigáveis com isso.
  • Godot já possui um modelo de gerenciamento de memória para recursos, a maioria das linguagens de script forneçem o próprio, o que resulta em esforços duplicados e bugs.
  • Realizar a ligação de código é algo sempre bagunçado e resulta em vários pontos de falha, bugs inesperados e , de maneira geral, baixa manutenabilidade.

O resultado dessas considerações é o GDScript. A linguagem e o interpretados para GDScript acabaram sendo menores que o código de ligação para Lua e Squirrel, ao mesmo tempo que possuia a mesma funcionalidade. Com o tempo, ter uma linguagem embutida provou ser uma grande vantagem.

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 Define uma classe.
extends Define qual classe estender com a classe atual.
is Tests whether a variable extends a given class, or is of a given built-in type.
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>’.
sincronização de fantoches 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] Subscription (highest priority)
x.attribute Attribute reference
foo() Function call
is Instance type checker
~ NÃO Binário
-x Negative / Unary negation
* / %

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)

+ Addition / Concatenation of arrays
- Subtraction
<< >> Bit shifting
& E Binário
^ OU EXCLUSIVO Binário
| OU Binário
< > == != >= <= Comparações
in Content test
! not NÃO Booleano
and && E Booleano
or || OU Booleano
if x else if/else Ternário
= += -= *= /= %= &= |= Assignment (lowest priority)

Literais

Literal Tipo
45 Inteiro Base 10
0x8F51 Base 16 (hexadecimal) integer
0b101010 Base 2 (binary) integer
3.14, 58.1e-10 Floating-point number (real)
"Olá", "Oi" Strings
"""Olá""" String com múltiplas linhas
@"Nodo/Rotulo" class_NodePath or StringName
$NodePath Forma abreviada para get_node("NodePath")

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

Built-in types are stack-allocated. They are passed as values. This means a copy is created on each assignment or when passing them as arguments to functions. The only exceptions are Arrays and Dictionaries, which are passed by reference so they are shared. (Pooled arrays such as PoolByteArray are still passed as values.)

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

Short for “boolean”, it can only contain true or 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 standard C escape sequences. GDScript also supports Formatação de Strings em GDScript.

Tipos básicos de vetor

Vector2

2D vector type containing x and y fields. Can also be accessed as an array.

Rect2

2D Rectangle type containing two vectors fields: position and size. Also contains an end field which is 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

3×2 matrix used for 2D transforms.

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

Axis-aligned bounding box (or 3D box) contains 2 vectors fields: position and size. Also contains an end field which is 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

Generic sequence of arbitrary object types, including other arrays or dictionaries (see below). The array can resize dynamically. Arrays are indexed starting from index 0. Negative indices count from the end.

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

GDScript arrays are allocated linearly in memory for speed. Large arrays (more than tens of thousands of elements) may however cause memory fragmentation. If this is a concern, special types of arrays are available. These only accept a single data type. They avoid memory fragmentation and use less memory, but are atomic and tend to run slower than generic arrays. They are therefore only recommended to use for large data sets:

  • PoolByteArray: Um array de bytes (inteiros com valor de 0 até 255).
  • PoolIntArray: Um array de inteiros.
  • PoolRealArray: Um array de floats.
  • PoolStringArray: Um array de strings.
  • PoolVector2Array: Um array de objetos Vector2.
  • PoolVector3Array: Um array de objetos Vector3.
  • PoolColorArray: Um array de objetos 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"
}

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.

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:

  • Built-in types (Array, Vector2, int, String, etc.).
  • Engine classes (Node, Resource, Reference, etc.).
  • Nomes constantes se eles contiverem um recurso de script (`` MyScript`` se você declarar `` const MyScript = preload (“res: //my_script.gd”) ``).
  • Other classes in the same script, respecting scope (InnerClass.NestedClass if you declared class NestedClass inside the class InnerClass in the same scope).
  • 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

Casting is also useful to have better type-safe variables when interacting with the scene tree:

# 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

Constantes são similares a variáveis, mas podem ser constantes ou expressões constantes e podem ser atribuídas durante a inicialização.

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.

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.

Enumeradores

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

If you pass a name to the enum, it will put all the keys inside a constant dictionary of that name.

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.

Referencing functions

Contrary to Python, functions are not first-class objects in GDScript. This means they cannot be stored in variables, passed as an argument to another function or be returned from other functions. This is for performance reasons.

To reference a function by name at run-time, (e.g. to store it in a variable, or pass it to another function as an argument) one must use the call or funcref helpers:

# 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

A function can be declared static. When a function is static, it has no access to the instance member variables or self. This is mainly useful to make libraries of helper functions:

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

Sometimes, you might want to assign a different initial value based on a boolean expression. In this case, ternary-if expressions come in handy:

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

Para iterar através de uma faixa de valores, como em arrays ou tabelas, um laço for é usado. Quando iterando por um array, o elemento atual é armazenado na variável do laço. Ao iterar por um dicionário, o índice é armazenado na variável do laço.

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

A match statement is used to branch execution of a program. It’s the equivalent of the switch statement found in many other languages, but offers some additional features.

Basic syntax:

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

Crash-course for people who are familiar with switch statements:

  1. Replace switch with match.
  2. Remove case.
  3. Remove any breaks. If you don’t want to break by default, you can use continue for a fallthrough.
  4. Troque default por um único sublinhado.

Controle de fluxo:

The patterns are matched from top to bottom. If a pattern matches, the corresponding block will be executed. After that, the execution continues below the match statement. If you want to have a fallthrough, you can use continue to stop execution in the current block and check the ones below it.

Há 6 tipos de padrões:

  • Constant pattern

    Constant primitives, like numbers and strings:

    match x:
        1:
            print("We are number one!")
        2:
            print("Two are better than one!")
        "test":
            print("Oh snap! It's a string!")
    
  • Variable pattern

    Matches the contents of a variable/enum:

    match typeof(x):
        TYPE_REAL:
            print("float")
        TYPE_STRING:
            print("text")
        TYPE_ARRAY:
            print("array")
    
  • Wildcard pattern

    Este padrão compara/coincide com tudo. É escrito com uma única sublinha _ .

    It can be used as the equivalent of the default in a switch statement in other languages:

    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.")
    
  • Binding pattern

    A binding pattern introduces a new variable. Like the wildcard pattern, it matches everything - and also gives that value a name. It’s especially useful in array and dictionary patterns:

    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)
    
  • Array pattern

    Matches an array. Every single element of the array pattern is a pattern itself, so you can nest them.

    The length of the array is tested first, it has to be the same size as the pattern, otherwise the pattern doesn’t match.

    Open-ended array: An array can be bigger than the pattern by making the last subpattern ...

    Every subpattern has to be comma-separated.

    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")
    
  • Dictionary pattern

    Funciona da mesma forma que o padrão de array. Toda chave precisa ser um padrão constante.

    The size of the dictionary is tested first, it has to be the same size as the pattern, otherwise the pattern doesn’t match.

    Open-ended dictionary: A dictionary can be bigger than the pattern by making the last subpattern ...

    Qualquer subpadrão precisa ser separado por pontos.

    Se você não especificar um valor, só a existência da chave é conferida.

    A value pattern is separated from the key pattern with a :.

    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")
    
  • Multiple patterns

    You can also specify multiple patterns separated by a comma. These patterns aren’t allowed to have any bindings in them.

    match x:
        1, 2, 3:
            print("It's 1 - 3")
        "Sword", "Splash potion", "Fist":
            print("Yep, you've taken damage")
    

Classes

By default, all script files are unnamed classes. In this case, you can only reference them using the file’s path, using either a relative or an absolute path. For example, if you name a script file 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()

Instead, you can give your class a name to register it as a new type in Godot’s editor. For that, you use the class_name keyword. You can add an optional comma followed by a path to an image, to use it as an icon. Your class will then appear with its new icon in the editor:

# Item.gd

extends Node

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

Here’s a class file example:

# 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

A class (stored as a file) can inherit from:

  • A global class.
  • Another class file.
  • Uma classe interna dentro de outro arquivo de classe.

Herança múltipla não é permitida.

Inheritance uses the extends keyword:

# 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

To check if a given instance inherits from a given class, the is keyword can be used:

# Cache the enemy class.
const Enemy = preload("enemy.gd")

# [...]

# Use 'is' to check inheritance.
if (entity is Enemy):
    entity.apply_damage()

To call a function in a parent class (i.e. one extend-ed in your current class), prepend . to the function name:

.base_func(args)

This is especially useful because functions in extending classes replace functions with the same name in their parent classes. If you still want to call them, you can prefix them with . (like the super keyword in other languages):

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

Nota

Default functions like _init, and most notifications such as _enter_tree, _exit_tree, _process, _physics_process, etc. are called in all parent classes automatically. There is no need to call them explicitly when overloading them.

Construtor de Classe

The class constructor, called on class instantiation, is named _init. As mentioned earlier, the constructors of parent classes are called automatically when inheriting a class. So, there is usually no need to call ._init() explicitly.

Unlike the call of a regular function, like in the above example with .some_func, if the constructor from the inherited class takes arguments, they are passed like this:

func _init(args).(parent_args):
   pass

This is better explained through examples. Consider this scenario:

# 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. If the inherited class (State.gd) defines a _init constructor that takes arguments (e in this case), then the inheriting class (Idle.gd) must define _init as well and pass appropriate parameters to _init from State.gd.

  2. Idle.gd can have a different number of arguments than the parent class State.gd.

  3. In the example above, e passed to the State.gd constructor is the same e passed in to Idle.gd.

  4. If Idle.gd’s _init constructor takes 0 arguments, it still needs to pass some value to the State.gd parent class, even if it does nothing. This brings us to the fact that you can pass literals in the base constructor as well, not just variables. eg.:

    # 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 GDScript exports.

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

Whenever the value of variable is modified by an external source (i.e. not from local usage in the class), the setter function (setterfunc above) will be called. This happens before the value is changed. The setter must decide what to do with the new value. Vice versa, when variable is accessed, the getter function (getterfunc above) must return the desired value. Below is an example:

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.

Either of the setter or getter functions can be omitted:

# 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 and getters are useful when exporting variables to the editor in tool scripts or plugins, for validating input.

As said, local access will not trigger the setter and getter. Here is an illustration of this:

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

By default, scripts don’t run inside the editor and only the exported properties can be changed. In some cases, it is desired that they do run inside the editor (as long as they don’t execute game code or manually avoid doing so). For this, the tool keyword exists and must be placed at the top of the file:

tool
extends Button

func _ready():
    print("Hello")

See Running code in the editor for more information.

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

Se uma classe herdar de: ref: class_Reference, as instâncias serão liberadas quando não estiverem mais em uso. Nenhum coletor de lixo existe, apenas a contagem de referência. Por padrão, todas as classes que não definem herança se estendem Reference. Se isto não for desejado, então uma classe deve herdar: ref: class_Object manualmente e deve chamar instance.free (). Para evitar ciclos de referência que não podem ser liberados, uma função weakref é fornecida para criar referências fracas.

Alternativamente, quando não estiver usando referências, o `` is_instance_valid (instance) `` pode ser usado para verificar se um objeto foi liberado.

Sinais

Signals are a tool to emit messages from an object that other objects can react to. To create custom signals for a class, use the signal keyword.

extends Node

# A signal named health_depleted
signal health_depleted

Nota

Signals are a Callback mechanism. They also fill the role of Observers, a common programming pattern. For more information, read the Observer tutorial in the Game Programming Patterns ebook.

You can connect these signals to methods the same way you connect built-in signals of nodes like class_Button or class_RigidBody.

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

These arguments show up in the editor’s node dock, and Godot can use them to generate callback functions for you. However, you can still emit any number of arguments when you emit signals; it’s up to you to emit the correct values.

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

GDScript can bind an array of values to connections between a signal and a method. When the signal is emitted, the callback method receives the bound values. These bound arguments are unique to each connection, and the values will stay the same.

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.

Building on the example above, let’s say we want to display a log of the damage taken by each character on the screen, like Player1 took 22 damage.. The health_changed signal doesn’t give us the name of the character that took damage. So when we connect the signal to the in-game console, we can add the character’s name in the binds array argument:

# 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 offers support for coroutines via the yield built-in function. Calling yield() will immediately return from the current function, with the current frozen state of the same function as the return value. Calling resume() on this resulting object will continue execution and return whatever the function returns. Once resumed, the state object becomes invalid. Here is an example:

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.

Will print:

Hello
my dear
world

It is also possible to pass values between yield() and resume(), for example:

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.

Will print:

Hello
world
cheers!

Corrotinas e sinais

The real strength of using yield is when combined with signals. yield can accept two arguments, an object and a signal. When the signal is received, execution will recommence. Here are some examples:

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

Coroutines themselves use the completed signal when they transition into an invalid state, for example:

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

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

my_func will only continue execution once both buttons have been pressed.

Palavra-chave Onready

When using nodes, it’s common to desire to keep references to parts of the scene in a variable. As scenes are only warranted to be configured when entering the active scene tree, the sub-nodes can only be obtained when a call to Node._ready() is made.

var my_label

func _ready():
    my_label = get_node("MyLabel")

This can get a little cumbersome, especially when nodes and external references pile up. For this, GDScript has the onready keyword, that defers initialization of a member variable until _ready() is called. It can replace the above code with a single line:

onready var my_label = get_node("MyLabel")

Palavra-chave assert

A palavra-chave `` assert`` pode ser usada para testar quando a compilação é para a 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 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 esta compilando em modo deputaçã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.