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...
Průvodce stylem GDScript
Tento průvodce stylem uvádí konvence pro psaní elegantního GDScriptu. Cílem je podpořit psaní čistého, čitelného kódu a podporovat konzistenci napříč projekty, diskusemi a kurzy. Doufejme, že to také podpoří vývoj nástrojů automatického formátování.
Protože GDScript je blízký jazyku Python, je tato příručka inspirována příručkou PEP 8 programovacího stylu jazyka Python.
Průvodci stylem nejsou zamýšleny jako striktní pravidla. Občas se může stát, že některé z níže uvedených pokynů nebudete moci použít. V takovém případě se řiďte vlastním úsudkem a požádejte kolegy vývojáře o radu.
Obecně platí, že udržování konzistentního kódu v projektech a v týmu je důležitější než dodržování tohoto návodu do puntíku.
Poznámka
Vestavěný editor skriptů Godot používá mnoho těchto konvencí ve výchozím nastavení. Nechte si s jím pomoci.
Zde je kompletní příklad třídy založený na těchto pokynech:
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!")
Formátování
Kódování a speciální znaky
Pro zalomení řádků používejte znaky pro posuv řádku (LF), nikoli CRLF nebo CR. (výchozí nastavení editoru)
Na konci každého souboru použijte jeden znak posuvu řádku. (výchozí nastavení editoru)
Použijte kódování UTF-8 bez značky pořadí bajtů <https://en.wikipedia.org/wiki/Byte_order_mark>`_. (výchozí nastavení editoru)
Pro odsazení použijte místo mezer Tabulátory. (výchozí nastavení editoru)
Odsazení
Každá úroveň odsazení by měla být o jednu větší než blok, který ji obsahuje.
Dobré:
for i in range(10):
print("hello")
Špatné:
for i in range(10):
print("hello")
for i in range(10):
print("hello")
K odlišení pokračovaní řádků od běžných bloků kódu použijte 2 úrovně odsazení.
Dobré:
effect.interpolate_property(sprite, "transform/scale",
sprite.get_scale(), Vector2(2.0, 2.0), 0.3,
Tween.TRANS_QUAD, Tween.EASE_OUT)
Špatné:
effect.interpolate_property(sprite, "transform/scale",
sprite.get_scale(), Vector2(2.0, 2.0), 0.3,
Tween.TRANS_QUAD, Tween.EASE_OUT)
Výjimkou tvoří pole, slovníky a výčty. Pro odlišení pokračovacích řádků použijte jednu úroveň odsazení:
Dobré:
var party = [
"Godot",
"Godette",
"Steve",
]
var character_dict = {
"Name": "Bob",
"Age": 27,
"Job": "Mechanic",
}
enum Tile {
BRICK,
FLOOR,
SPIKE,
TELEPORT,
}
Špatné:
var party = [
"Godot",
"Godette",
"Steve",
]
var character_dict = {
"Name": "Bob",
"Age": 27,
"Job": "Mechanic",
}
enum Tile {
BRICK,
FLOOR,
SPIKE,
TELEPORT,
}
Koncová čárka
V polích, slovnících a výčtech používejte na posledním řádku čárku. To vede ke snazšímu refaktoringu a lepšímu porovnávání ve správě verzí, protože při přidávání nových prvků není třeba upravovat poslední řádek.
Dobré:
var array = [
1,
2,
3,
]
Špatné:
var array = [
1,
2,
3
]
Koncové čárky jsou v jednořádkových seznamech zbytečné, proto je v tomto případě nepřidávejte.
Dobré:
var array = [1, 2, 3]
Špatné:
var array = [1, 2, 3,]
Prázdné řádky
Definice funkcí a tříd obklopte dvěma prázdnými řádky:
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)
Uvnitř funkcí použijte jeden prázdný řádek pro oddělení logických sekcí.
Poznámka
We use a single line between classes and function definitions in the class reference and in short code snippets in this documentation.
Délka řádku
Udržujte jednotlivé řádky kódu pod 100 znaků.
Pokud můžete, snažte se, aby řádky neměly více než 80 znaků. To usnadňuje čtení kódu na malých displejích a při otevření dvou skriptů vedle sebe v externím textovém editoru. Například při prohlížení rozdílové revize.
Jeden příkaz na řádek
Avoid combining multiple statements on a single line, including conditional statements, to adhere to the GDScript style guidelines for readability.
Dobré:
if position.x > width:
position.x = 0
if flag:
print("flagged")
Špatné:
if position.x > width: position.x = 0
if flag: print("flagged")
Jedinou výjimkou z tohoto pravidla je ternární operátor:
next_state = "idle" if is_on_floor() else "fall"
Format multiline statements for readability
When you have particularly long if statements or nested ternary expressions,
wrapping them over multiple lines improves readability. Since continuation lines
are still part of the same expression, 2 indent levels should be used instead of one.
GDScript allows wrapping statements using multiple lines using parentheses or backslashes. Parentheses are favored in this style guide since they make for easier refactoring. With backslashes, you have to ensure that the last line never contains a backslash at the end. With parentheses, you don't have to worry about the last line having a backslash at the end.
When wrapping a conditional expression over multiple lines, the and/or
keywords should be placed at the beginning of the line continuation, not at the
end of the previous line.
Dobré:
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
Špatné:
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
Vyhněte se zbytečným závorkám
Vyhněte se závorkám ve výrazech a podmíněných příkazech. Pokud to není nutné pro pořadí operací nebo obalení přes více řádků, pouze snižují čitelnost.
Dobré:
if is_colliding():
queue_free()
Špatné:
if (is_colliding()):
queue_free()
Logické operátory
Dávejte přednost jednoduchým anglickým verzím logických operátorů, protože jsou nejpřístupnější:
Místo
&&použijteand.Místo
||`použijteor.Use
notinstead of!.
Můžete také použít závorky kolem logických operátorů, abyste odstranili případné nejasnosti. To může usnadnit čtení dlouhých výrazů.
Dobré:
if (foo and bar) or not baz:
print("condition is true")
Špatné:
if foo && bar || !baz:
print("condition is true")
Mezery
Always use one space around operators and after commas. Also, avoid extra spaces
in dictionary references and function calls. One exception to this is for
single-line dictionary declarations, where a space should be added after the
opening brace and before the closing brace. This makes the dictionary easier to
visually distinguish from an array, as the [] characters look close to
{} with most fonts.
Dobré:
position.x = 5
position.y = target_position.y + 10
dict["key"] = 5
my_array = [4, 5, 6]
my_dictionary = { key = "value" }
print("foo")
Špatné:
position.x=5
position.y = mpos.y+10
dict ["key"] = 5
myarray = [4,5,6]
my_dictionary = {key = "value"}
print ("foo")
Nepoužívejte mezery k zarovnání výrazů na výšku:
x = 100
y = 100
velocity = 500
Uvozovky
Použijte dvojité uvozovky, pokud jednoduché uvozovky neumožňují v daném řetězci vynechání escapovaných znaků. Viz příklady níže:
# 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\"")
Čísla
U čísel s pohyblivou řádovou čárkou nevynechávejte počáteční ani koncovou nulu. V opačném případě se stanou hůře čitelnými a na první pohled se hůře odlišují od celých čísel.
Dobré:
var float_number = 0.234
var other_float_number = 13.0
Špatné:
var float_number = .234
var other_float_number = 13.
V hexadecimálních číslech používejte malá písmena, protože jejich menší výška usnadňuje čtení čísla.
Dobré:
var hex_number = 0xfb8c0b
Špatné:
var hex_number = 0xFB8C0B
Využijte podtržítka v literálech jazyka GDScript, aby byla velká čísla čitelnější.
Dobré:
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
Špatné:
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
Konvence pojmenování
These naming conventions follow the Godot Engine style. Breaking these will make your code clash with the built-in naming conventions, leading to inconsistent code. As a summary table:
Typ |
Convention |
Příklad |
|---|---|---|
Názvy souborů |
snake_case |
|
Class names |
PascalCase |
|
Node names |
PascalCase |
|
Funkce |
snake_case |
|
Proměnné |
snake_case |
|
Signály |
snake_case |
|
Konstanty |
CONSTANT_CASE |
|
Enum names |
PascalCase |
|
Enum members |
CONSTANT_CASE |
|
Názvy souborů
Use snake_case for file names. For named classes, convert the PascalCase class name to 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
To je v souladu s tím, jak jsou pojmenovány soubory C++ ve zdrojovém kódu Godotu. Tím se také vyhnete problémům velkých a malých písmen, které mohou nastat při exportu projektu ze systému Windows na jiné platformy.
Třídy a uzly
Pro názvy tříd a uzlů použijte PascalCase:
extends CharacterBody3D
Při načítání třídy do konstanty nebo proměnné použijte také PascalCase:
const Weapon = preload("res://weapon.gd")
Funkce a proměnné
Pro pojmenování funkcí a proměnných použijte snake_case:
var particle_effect
func load_level():
K virtuálním metodám, které musí uživatel implementovat, soukromým funkcím a soukromým proměnným přidejte jedno podtržítko (_):
var _counter = 0
func _recalculate_path():
Signály
Pro pojmenování signálů použijte minulý čas:
signal door_opened
signal score_changed
Konstanty a výčtové typy
Zapisujte konstanty pomocí CONSTANT_CASE, tj. všemi velkými písmeny s podtržítkem (_) pro oddělení slov:
const MAX_SPEED = 200
Use PascalCase for enum names and keep them singular, as they represent a type. Use CONSTANT_CASE for their members, as they are constants:
enum Element {
EARTH,
WATER,
AIR,
FIRE,
}
Write enums with each item on its own line. This allows adding documentation comments above each item more easily, and also makes for cleaner diffs in version control when items are added or removed.
Dobré:
enum Element {
EARTH,
WATER,
AIR,
FIRE,
}
Špatné:
enum Element { EARTH, WATER, AIR, FIRE }
Pořadí kódu
This section focuses on code order. For formatting, see Formátování. For naming conventions, see Konvence pojmenování.
Doporučujeme uspořádat kód GDScript tímto způsobem:
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
And put the class methods and variables in the following order depending on their access modifiers:
1. public
2. private
Pořadí jsme optimalizovali tak, aby bylo snadné číst kód shora dolů, aby vývojáři, kteří čtou kód poprvé, pochopili, jak funguje, a aby se předešlo chybám souvisejícím s pořadím deklarace proměnných.
Toto pořadí kódů se řídí čtyřmi základními pravidly:
Nejdříve jsou na řadě vlastnosti a signály a poté metody.
Veřejné přijde před soukromé.
Virtuální zpětná volání jsou před rozhraním třídy.
Funkce pro konstrukci a inicializaci objektu,
_inita_ready, předcházejí funkce, které modifikují objekt za běhu.
Deklarace třídy
If the code is meant to run in the editor, place the @tool annotation on the
first line of the script.
Follow with the optional @icon then the class_name if necessary. You can turn a
GDScript file into a global type in your project using class_name. For more
information, see Registrace pojmenovaných tříd. If the class is meant
to be an abstract class,
add @abstract before the class_name keyword.
Then, add the extends keyword if the class extends a built-in type.
Following that, you should have the class's optional documentation comments. You can use that to explain the role of your class to your teammates, how it works, and how other developers should use it, for example.
@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.
For inner classes, use single-line declarations:
## 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
Signály a vlastnosti
Deklarace signálů, za kterými následují vlastnosti, tedy členské proměnné, zapisujte až za docstring.
Enumy by měly být uvedeny až za signály, protože je můžete použít jako nápovědu pro export ostatních vlastností.
Poté napište konstanty, exportované proměnné, veřejné, soukromé proměnné a proměnné onready, a to v tomto pořadí.
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")
Poznámka
GDScript evaluates @onready variables right before the _ready
callback. You can use that to cache node dependencies, that is to say, to get
child nodes in the scene that your class relies on. This is what the example
above shows.
Členské proměnné
Nedeklarujte členské proměnné, pokud se používají pouze lokálně v metodě, protože to znesnadňuje orientaci v kódu. Místo toho je deklarujte jako lokální proměnné v těle metody.
Lokální proměnné
Lokální proměnné deklarujte co nejblíže jejich prvnímu použití. To usnadňuje sledování kódu, aniž byste museli příliš rolovat, abyste našli místo, kde byla proměnná deklarována.
Metody a statické funkce
Po vlastnostech třídy následují metody.
Začněte zpětnou metodou _init(), kterou engine zavolá při vytvoření objektu v paměti. Následuje zpětné volání _ready(), které Godot zavolá při přidání uzlu do stromu scény.
Tyto funkce by měly být na prvním místě, protože ukazují, jak se objekt inicializuje.
Další vestavěná virtuální zpětná volání, jako _unhandled_input() a _physics_process, by měly následovat. Ty řídí hlavní smyčku objektu a interakci s herním enginem.
Zbytek rozhraní třídy, veřejné a soukromé metody, následují v tomto pořadí.
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()
Statické typování
GDScript supports optional static typing.
Deklarované typy
Chcete-li deklarovat typ proměnné, použijte <proměnná>: <typ>:
var health: int = 0
Chcete-li deklarovat návratový typ funkce, použijte -> <type>:
func heal(amount: int) -> void:
Odvozené typy
In most cases, you can let the compiler infer the type using :=.
Prefer := when the type is written on the same line as the assignment,
otherwise prefer writing the type explicitly.
Dobré:
# 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)
Include the type hint when the type is ambiguous, and omit the type hint when it's redundant.
Špatné:
# 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()
In some cases, the type must be stated explicitly, otherwise the behavior
will not be as expected because the compiler will only be able to use
the function's return type. For example, get_node() cannot infer a type
unless the scene or file of the node is loaded in memory. In this case, you
should set the type explicitly.
Dobré:
@onready var health_bar: ProgressBar = get_node("UI/LifeBar")
Špatné:
# The compiler can't infer the exact type and will use Node
# instead of ProgressBar.
@onready var health_bar := get_node("UI/LifeBar")
Alternatively, you can use the as keyword to cast the return type, and
that type will be used to infer the type of the var.
@onready var health_bar := get_node("UI/LifeBar") as ProgressBar
# health_bar will be typed as ProgressBar
Poznámka
This option is considered more type-safe than type hints,
but also less null-safe as it silently casts the variable to null in case of a type mismatch at runtime,
without an error/warning.
Mezery mezi komentáři
Regular comments (
#) and documentation comments (##) should start with a space, but not code that you comment out. Additionally, code region comments (#region/#endregion) must follow that precise syntax, so they should not start with a space.Using a space for regular and documentation comments helps differentiate text comments from disabled code.
Dobré:
Špatné:
Poznámka
In the script editor, to toggle commenting of the selected code, press Ctrl + K. This feature adds/removes a single
#sign before any code on the selected lines.Prefer writing comments on their own line as opposed to inline comments (comments written on the same line as code). Inline comments are best used for short comments, typically a few words at most:
Dobré:
Špatné: