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...
Guia de Estilo GDScript
Este guia de estilo lista as convenções utilizadas para escrever código GDScript elegante. O objetivo é encorajar a escrita de código limpo e legível, além de promover a consistência entre projetos, discussões e tutoriais. Esperamos que isto também encoraje a criação de ferramentas de auto-formatação.
Já que o GDScript é próximo da linguagem Python, este guia é inspirado no guia de estilos PEP 8 do Python.
Guias de estilo não são regras. Às vezes, você talvez não poderá aplicar algumas das diretrizes abaixo. Quando isso acontecer, use seu melhor julgamento, e peça opiniões de outros desenvolvedores.
Em geral, manter seu código consistente em seus projetos e em seu time é mais importante que seguir este guia à risca.
Nota
O editor de scripts padrão do Godot usa várias dessas convenções por padrão. Deixe que isso te ajude.
Aqui está um exemplo completo baseado nessas regras:
class_name StateMachine
extends Node
## Hierarchical State machine for the player.
##
## Initializes states and delegates engine callbacks ([method Node._physics_process],
## [method Node._unhandled_input]) to the state.
signal state_changed(previous, new)
@export var initial_state: Node
var is_active = true:
set = set_is_active
@onready var _state = initial_state:
set = set_state
@onready var _state_name = _state.name
func _init():
add_to_group("state_machine")
func _enter_tree():
print("this happens before the ready method!")
func _ready():
state_changed.connect(_on_state_changed)
_state.enter()
func _unhandled_input(event):
_state.unhandled_input(event)
func _physics_process(delta):
_state.physics_process(delta)
func transition_to(target_state_path, msg={}):
if not has_node(target_state_path):
return
var target_state = get_node(target_state_path)
assert(target_state.is_composite == false)
_state.exit()
self._state = target_state
_state.enter(msg)
Events.player_state_changed.emit(_state.name)
func set_is_active(value):
is_active = value
set_physics_process(value)
set_process_unhandled_input(value)
set_block_signals(not value)
func set_state(value):
_state = value
_state_name = _state.name
func _on_state_changed(previous, new):
print("state changed")
state_changed.emit()
class State:
var foo = 0
func _init():
print("Hello!")
Formatação
Codificação e caracteres especiais
Use caracteres line feed (LF) para quebrar linhas, não CRLF ou CR. (padrão do editor)
Use um caractere line feed no final de cada arquivo. (padrão do editor)
Use a codificação UTF-8 sem uma marca de ordem de byte. (padrão do editor)
Use Tabs ao invés de espaços para indentação. (padrão do editor)
Recuo
Cada nível de indentação deve ser uma unidade maior que a do bloco que o contém.
Bom:
for i in range(10):
print("hello")
Ruim:
for i in range(10):
print("hello")
for i in range(10):
print("hello")
Use 2 níveis de indentação para distinguir linhas contínuas de blocos de código regulares.
Bom:
effect.interpolate_property(sprite, "transform/scale",
sprite.get_scale(), Vector2(2.0, 2.0), 0.3,
Tween.TRANS_QUAD, Tween.EASE_OUT)
Ruim:
effect.interpolate_property(sprite, "transform/scale",
sprite.get_scale(), Vector2(2.0, 2.0), 0.3,
Tween.TRANS_QUAD, Tween.EASE_OUT)
Exceções a essa regra são matrizes, dicionários e enums. Use apenas um nível de indentação para distinguir linhas contínuas:
Bom:
var party = [
"Godot",
"Godette",
"Steve",
]
var character_dict = {
"Name": "Bob",
"Age": 27,
"Job": "Mechanic",
}
enum Tile {
BRICK,
FLOOR,
SPIKE,
TELEPORT,
}
Ruim:
var party = [
"Godot",
"Godette",
"Steve",
]
var character_dict = {
"Name": "Bob",
"Age": 27,
"Job": "Mechanic",
}
enum Tile {
BRICK,
FLOOR,
SPIKE,
TELEPORT,
}
Vírgula extra
Use uma vírgula extra na última linha em matrizes, dicionários, e enums. Isso resulta em refatoração mais fácil e melhores amostras de diferenças em controle de versão, já que a última linha não precisa ser modificada ao adicionar novos elementos.
Bom:
var array = [
1,
2,
3,
]
Ruim:
var array = [
1,
2,
3
]
Vírgulas extras não desnecessárias em listas de uma linha só, então não adicione nesse caso.
Bom:
var array = [1, 2, 3]
Ruim:
var array = [1, 2, 3,]
Linhas em branco
Cerque funções e definições de classes com duas linhas em branco(uma em cima e uma embaixo):
func heal(amount):
health += amount
health = min(health, max_health)
health_changed.emit(health)
func take_damage(amount, effect=null):
health -= amount
health = max(0, health)
health_changed.emit(health)
Use uma linha em branco dentro de funções para separar seções lógicas.
Nota
Usamos uma única linha em branco entre definições de classes e funções na referência de classe e em pequenos trechos de código nesta documentação.
Tamanho de linha
Mantenha linhas individuais de código abaixo de 100 caracteres.
Se puder, tente manter linhas com menos de 80 caracteres. Isso ajuda a ler o código em telas pequenas e com dois scripts abertos lado-a-lado em um editor de texto externo. Por exemplo, quando estiver olhando uma revisão diferente.
Uma declaração por linha
Evite combinar várias instruções em uma única linha, incluindo instruções condicionais, para aderir às diretrizes de estilo do GDScript visando a legibilidade.
Bom:
if position.x > width:
position.x = 0
if flag:
print("flagged")
Ruim:
if position.x > width: position.x = 0
if flag: print("flagged")
A única exceção a essa regra é o operador ternário:
next_state = "idle" if is_on_floor() else "fall"
Formatar instruções de várias linhas para facilitar a leitura
Quando você tem instruções if particularmente longas ou expressões ternárias aninhadas, envolvê-las em várias linhas melhora a legibilidade. Visto que as linhas de continuação ainda fazem parte da mesma expressão, 2 níveis de indentação devem ser usados em vez de um.
GDScript permite agrupar instruções usando várias linhas usando parênteses ou barras invertidas. Os parênteses são preferidos neste guia de estilo, uma vez que facilitam a refatoração. Com barras invertidas, você deve garantir que a última linha nunca contenha uma barra invertida no final. Com parênteses, você não precisa se preocupar com a barra invertida no final da última linha.
Ao envolver uma expressão condicional em várias linhas, as palavras-chave and / or devem ser colocadas no início da continuação da linha, não no final da linha anterior.
Bom:
var angle_degrees = 135
var quadrant = (
"northeast" if angle_degrees <= 90
else "southeast" if angle_degrees <= 180
else "southwest" if angle_degrees <= 270
else "northwest"
)
var position = Vector2(250, 350)
if (
position.x > 200 and position.x < 400
and position.y > 300 and position.y < 400
):
pass
Ruim:
var angle_degrees = 135
var quadrant = "northeast" if angle_degrees <= 90 else "southeast" if angle_degrees <= 180 else "southwest" if angle_degrees <= 270 else "northwest"
var position = Vector2(250, 350)
if position.x > 200 and position.x < 400 and position.y > 300 and position.y < 400:
pass
Evite parênteses desnecessários
Evite parênteses em expressões e instruções condicionais. A menos que seja necessário para a ordem das operações ou quebra de várias linhas, eles apenas reduzem a legibilidade.
Bom:
if is_colliding():
queue_free()
Ruim:
if (is_colliding()):
queue_free()
Operadores booleanos
Prefira a versão por extenso dos operadores booleanos, já que elas são mais acessíveis:
Use
andao invés de&&.Use
orao invés de||.Use
notem vez de!.
Você pode usar parênteses ao redor de operadores booleanos para tirar ambiguidade. Isso pode facilitar e leitura de expressões longas.
Bom:
if (foo and bar) or not baz:
print("condition is true")
Ruim:
if foo && bar || !baz:
print("condition is true")
Espaço em branco
Sempre use um espaço ao redor de operadores e após vírgulas. Além disso, evite espaços extras em referências de dicionários e chamadas de função. Uma exceção a isso são as declarações de dicionário em uma única linha, onde um espaço deve ser adicionado após a chave de abertura e antes da chave de fechamento. Isso torna o dicionário mais fácil de distinguir visualmente de um array, já que os caracteres [] se parecem com {} na maioria das fontes.
Bom:
position.x = 5
position.y = target_position.y + 10
dict["key"] = 5
my_array = [4, 5, 6]
my_dictionary = { key = "value" }
print("foo")
Ruim:
position.x=5
position.y = mpos.y+10
dict ["key"] = 5
myarray = [4,5,6]
my_dictionary = {key = "value"}
print ("foo")
Não use espaços para alinhas expressões verticalmente:
x = 100
y = 100
velocity = 500
Aspas
Use duas aspas a não ser que uma aspa só te deixe escapar menos caracteres em uma string. Veja os exemplos abaixo:
# Normal string.
print("hello world")
# Use double quotes as usual to avoid escapes.
print("hello 'world'")
# Use single quotes as an exception to the rule to avoid escapes.
print('hello "world"')
# Both quote styles would require 2 escapes; prefer double quotes if it's a tie.
print("'hello' \"world\"")
Números
Não omita o zero à esquerda ou à direita em números de ponto flutuante. Caso contrário, isto os torna menos legíveis e mais difíceis de distinguir de inteiros à primeira vista.
Bom:
var float_number = 0.234
var other_float_number = 13.0
Ruim:
var float_number = .234
var other_float_number = 13.
Use letras minúsculas em números hexadecimais, pois sua altura mais baixa torna o número mais fácil de ler.
Bom:
var hex_number = 0xfb8c0b
Ruim:
var hex_number = 0xFB8C0B
Aproveite os sublinhados do GDScript em literais para tornar números grandes mais legíveis.
Bom:
var large_number = 1_234_567_890
var large_hex_number = 0xffff_f8f8_0000
var large_bin_number = 0b1101_0010_1010
# Numbers lower than 1000000 generally don't need separators.
var small_number = 12345
Ruim:
var large_number = 1234567890
var large_hex_number = 0xfffff8f80000
var large_bin_number = 0b110100101010
# Numbers lower than 1000000 generally don't need separators.
var small_number = 12_345
Convenções de nomes
Estas convenções de nomeação seguem o estilo da Godot Engine. Quebrá-las fará com que o seu código fique em conflito com as convenções de nomeação embutidas, levando à um código inconsistente. Como uma tabela resumo:
Tipo |
Convenção |
Exemplo |
|---|---|---|
Nomes de arquivo |
snake_case |
|
Nomes de classes |
PascalCase |
|
Nomes de nós (Nodes) |
PascalCase |
|
Funções |
snake_case |
|
Variáveis |
snake_case |
|
Sinais |
snake_case |
|
Constantes |
CONSTANT_CASE |
|
Nomes de enums |
PascalCase |
|
Membros de enum |
CONSTANT_CASE |
|
Nomes de arquivo
Use snake_case para nomes de arquivos. Para classes nomeadas, converta o nome da classe em PascalCase para snake_case:
# This file should be saved as `weapon.gd`.
class_name Weapon
extends Node
# This file should be saved as `yaml_parser.gd`.
class_name YAMLParser
extends Object
Isto é consistente com a forma como os arquivos C++ são nomeados no código-fonte do Godot. Isto também evita problemas de sensibilidade de caixa que podem surgir ao exportar um projeto do Windows para outras plataformas.
Classes e nós
Use PascalCase para nomes de classes e nós:
extends CharacterBody3D
Use PascalCase também quando estiver carregando uma classe em uma constante ou variável:
const Weapon = preload("res://weapon.gd")
Funções e variáveis
Use snake_case para nomear funções e variáveis:
var particle_effect
func load_level():
Prepend a single underscore (_) to virtual methods/functions the user must override, private functions, and private variables:
var _counter = 0
func _recalculate_path():
Sinais
Utilize o tempo pretérito para nomear sinais:
signal door_opened
signal score_changed
Constantes e enums
Utilize CONSTANT_CASE, com todas as letras maiúsculas e um sublinhado para separas as palavras:
const MAX_SPEED = 200
Use PascalCase para nomes de enums e os mantenha no singular, pois eles representam um tipo. Use CONSTANT_CASE para seus membros, já que são constantes:
enum Element {
EARTH,
WATER,
AIR,
FIRE,
}
Escreva enums com cada item em sua própria linha. Isso permite adicionar comentários de documentação acima de cada item com mais facilidade e também gera diffs mais limpos no controle de versão quando itens são adicionados ou removidos.
Bom:
enum Element {
EARTH,
WATER,
AIR,
FIRE,
}
Ruim:
enum Element { EARTH, WATER, AIR, FIRE }
Ordem do código
Esta seção se concentra na ordem do código. Para formatação, veja Formatação. Para convenções de nomenclatura, veja Convenções de nomes.
Sugerimos que você organize seu código GDScript assim:
01. @tool, @icon, @static_unload
02. class_name
03. extends
04. ## doc comment
05. signals
06. enums
07. constants
08. static variables
09. @export variables
10. remaining regular variables
11. @onready variables
12. _static_init()
13. remaining static methods
14. overridden built-in virtual methods:
1. _init()
2. _enter_tree()
3. _ready()
4. _process()
5. _physics_process()
6. remaining virtual methods
15. overridden custom methods
16. remaining methods
17. inner classes
E coloque os métodos e variáveis da classe na seguinte ordem, dependendo de seus modificadores de acesso:
1. public
2. private
Otimizamos essa ordem pra deixar o código mais fácil de ler de cima pra baixo, para ajudar desenvolvedores lendo o código pela primeira vez a entender como ele funciona, e para evitar erros referentes à ordem da declaração de variáveis.
Essa ordem de código segue quatro regras gerais:
Propriedades e sinais vêm primeiro, seguidos por métodos.
Público vem antes de privado.
Callbacks virtuais vêm antes da interface da classe.
As funções de construção e inicialização do objeto,
_inite_ready, vêm antes de funções que o modificam durante a execução.
Declaração de classe
Se o código for feito para rodar no editor, coloque a anotação @tool na primeira linha do script.
Siga com o opcional @icon e depois o class_name se necessário. Você pode transformar um arquivo GDScript em um tipo global no seu projeto usando class_name. Para mais informações, veja Registrando classes nomeadas. Se a classe for feita para ser uma classe abstrata, adicione @abstract antes da palavra-chave class_name.
Depois, adicione a palavra-chave extends se a classe estender um tipo integrado.
Em seguida, você deve colocar os comentários de documentação opcionais da classe. Você pode usar isso para explicar o papel da sua classe para os seus colegas de equipe, como ela funciona e como outros desenvolvedores devem usá-la, por exemplo.
@abstract
class_name MyNode
extends Node
## A brief description of the class's role and functionality.
##
## The description of the script, what it can do,
## and any further detail.
Para classes internas, use declarações em uma única linha:
## A brief description of the class's role and functionality.
##
## The description of the script, what it can do,
## and any further detail.
@abstract class MyNode extends Node:
pass
Sinais e propriedades
Escreva declarações de sinal, seguida de propriedades, ou seja, variáveis do membro, depois da docstring.
Enums vêm depois de sinais, já que você pode usá-los como inferências de exportação para outras propriedades.
Então, escreva constantes, variáveis exportados, públicos, privados, e onready, nessa ordem.
signal player_spawned(position)
enum Job {
KNIGHT,
WIZARD,
ROGUE,
HEALER,
SHAMAN,
}
const MAX_LIVES = 3
@export var job: Job = Job.KNIGHT
@export var max_health = 50
@export var attack = 5
var health = max_health:
set(new_health):
health = new_health
var _speed = 300.0
@onready var sword = get_node("Sword")
@onready var gun = get_node("Gun")
Nota
O GDScript avalia variáveis @onready imediatamente antes do callback _ready. Você pode usar isso para armazenar em cache dependências de nós, ou seja, para obter nós filhos na cena dos quais sua classe depende. É isso que o exemplo acima mostra.
Variáveis de membro
Não declare variáveis de membro se elas forem usadas apenas localmente em um método, pois torna o código mais difícil de seguir. Em vez disso, declare-as como variáveis locais no corpo do método.
Variáveis locais
Declare variáveis locais o mais pŕoximo possível de seu primeiro uso. Isto torna mais fácil seguir o código, sem ter que rolar muito para encontrar onde a variável foi declarada.
Métodos e funções estáticas
Depois das propriedades da classe vêm os métodos.
Comece com o método _init(), que a engine chamará assim que o objeto for criado na memória. Siga com o método _ready(), que o Godot chama quando ela adiciona um nó à árvore da cena.
Estas funções devem vir primeiro pois elas mostram como o objeto é inicializado.
Outros callbacks virtuais, como _unhandled_input() e _physics_process, devem vir depois. Estes controlam os loops principais do objeto e suas interações com a engine.
O resto da interface da classe, métodos públicos e privados, vêm depois, nessa ordem.
func _init():
add_to_group("state_machine")
func _ready():
state_changed.connect(_on_state_changed)
_state.enter()
func _unhandled_input(event):
_state.unhandled_input(event)
func transition_to(target_state_path, msg={}):
if not has_node(target_state_path):
return
var target_state = get_node(target_state_path)
assert(target_state.is_composite == false)
_state.exit()
self._state = target_state
_state.enter(msg)
Events.player_state_changed.emit(_state.name)
func _on_state_changed(previous, new):
print("state changed")
state_changed.emit()
Tipagem estática
O GDScript suporta tipagem estática opcional.
Tipos declarados
Para declarar o tipo de uma variável, use <variável>: <tipo>:
var health: int = 0
Para declarar o tipo de retorno de uma função, use -> <type>:
func heal(amount: int) -> void:
Tipos inferidos
Na maioria dos casos, você pode deixar o compilador inferir o tipo usando :=. Prefira := quando o tipo estiver escrito na mesma linha que a atribuição; caso contrário, prefira escrever o tipo explicitamente.
Bom:
# The type can be int or float, and thus should be stated explicitly.
var health: int = 0
# The type is clearly inferred as Vector3.
var direction := Vector3(1, 2, 3)
Inclua a dica de tipo (type hint) quando o tipo for ambíguo e omita a dica de tipo quando ela for redundante.
Ruim:
# Typed as int, but it could be that float was intended.
var health := 0
# The type hint has redundant information.
var direction: Vector3 = Vector3(1, 2, 3)
# What type is this? It's not immediately clear to the reader, so it's bad.
var value := complex_function()
Em alguns casos, o tipo deve ser declarado explicitamente, caso contrário o comportamento não será o esperado porque o compilador só poderá usar o tipo de retorno da função. Por exemplo, get_node() não pode inferir um tipo a menos que a cena ou o arquivo do nó esteja carregado na memória. Nesse caso, você deve definir o tipo explicitamente.
Bom:
@onready var health_bar: ProgressBar = get_node("UI/LifeBar")
Ruim:
# The compiler can't infer the exact type and will use Node
# instead of ProgressBar.
@onready var health_bar := get_node("UI/LifeBar")
Alternativamente, você pode usar a palavra-chave as para inferir o tipo de retorno, e esse tipo será usado para inferir o tipo da variável.
@onready var health_bar := get_node("UI/LifeBar") as ProgressBar
# health_bar will be typed as ProgressBar
Nota
Esta opção é considerada mais segura em relação a tipos (type-safe) do que as dicas de tipo, mas também menos segura em relação a nulos (null-safe), pois ela converte silenciosamente a variável para null em caso de incompatibilidade de tipos em tempo de execução, sem gerar um erro ou aviso.
Espaçamento de comentários
Comentários comuns (
#) e comentários de documentação (##) devem começar com um espaço, mas não o código que você comentar para desativar. Além disso, comentários de região de código (#region/#endregion) devem seguir essa sintaxe precisa, portanto não devem começar com um espaço.Usar um espaço para comentários comuns e de documentação ajuda a diferenciar comentários de texto de códigos desativados.
Bom:
Ruim:
Nota
In the script editor, to toggle commenting of the selected code, press Ctrl + K. This shortcut adds/removes a single
#sign before any code on the selected lines.Prefira escrever comentários em suas próprias linhas em vez de comentários inline (comentários escritos na mesma linha que o código). Comentários inline são melhor usados para observações curtas, geralmente com poucas palavras no máximo:
Bom:
Ruim: