.. _doc_gdscript_styleguide: GDScript style guide ==================== Description ----------- This styleguide lists conventions to write elegant GDScript. The goal is to encourage writing clean, readable code and promote consistency across projects, discussions, and tutorials. Hopefully, this will also encourage development of auto-formatting tools. Since GDScript is close to Python, this guide is inspired by Python's `PEP 8 `__ programming styleguide. .. note:: Godot's built-in script editor uses a lot of these conventions by default. Let it help you. Formatting ---------- Encoding and special characters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Use line feed (**LF**) characters to break lines, not CRLF or CR. *(editor default)* * Use one line feed character at the end of each file. *(editor default)* * Use **UTF-8** encoding without a `byte order mark `_. *(editor default)* * Use **Tabs** instead of spaces for indentation. *(editor default)* Indentation ~~~~~~~~~~~ Each indent level should be one greater than the block containing it. **Good**: :: for i in range(10): print("hello") **Bad**: :: for i in range(10): print("hello") for i in range(10): print("hello") Use 2 indent levels to distinguish continuation lines from regular code blocks. **Good**: :: effect.interpolate_property(sprite, "transform/scale", sprite.get_scale(), Vector2(2.0, 2.0), 0.3, Tween.TRANS_QUAD, Tween.EASE_OUT) **Bad**: :: effect.interpolate_property(sprite, "transform/scale", sprite.get_scale(), Vector2(2.0, 2.0), 0.3, Tween.TRANS_QUAD, Tween.EASE_OUT) Blank lines ~~~~~~~~~~~ Surround functions and class definitions with two blank lines: :: func heal(amount): health += amount health = min(health, max_health) emit_signal("health_changed", health) func take_damage(amount, effect=null): health -= amount health = max(0, health) emit_signal("health_changed", health) Use one blank line inside functions to separate logical sections. Line length ~~~~~~~~~~~ Keep individual lines of code under 100 characters. If you can, try to keep lines under 80 characters. This helps to read the code on small displays and with two scripts opened side-by-side in an external text editor. For example, when looking at a differential revision. One statement per line ~~~~~~~~~~~~~~~~~~~~~~ Never combine multiple statements on a single line. No, C programmers, not even with a single line conditional statement. **Good**: :: if position.x > width: position.x = 0 if flag: print("flagged") **Bad**: :: if position.x > width: position.x = 0 if flag: print("flagged") The only exception to that rule is the ternary operator: :: next_state = "fall" if not is_on_floor() else "idle" Avoid unnecessary parentheses ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Avoid parentheses in expressions and conditional statements. Unless necessary for order of operations, they only reduce readability. **Good**: :: if is_colliding(): queue_free() **Bad**: :: if (is_colliding()): queue_free() Boolean operators ~~~~~~~~~~~~~~~~~ Prefer the plain English versions of boolean operators, as they are the most accessible: - Use ``and`` instead of ``&&``. - Use ``or`` instead of ``||``. You may also use parentheses around boolean operators to clear any ambiguity. This can make long expressions easier to read. **Good**: :: if (foo and bar) or baz: print("condition is true") **Bad**: :: if foo && bar || baz: print("condition is true") Comment spacing ~~~~~~~~~~~~~~~ Regular comments should start with a space, but not code that you comment out. This helps differentiate text comments from disabled code. **Good**: :: # This is a comment. #print("This is disabled code") **Bad**: :: #This is a comment. # print("This is disabled code") .. note:: In the script editor, to toggle the selected code commented, press Ctrl K. This feature adds a single # sign at the start of the selected lines. Whitespace ~~~~~~~~~~ Always use one space around operators and after commas. Also, avoid extra spaces in dictionary references and function calls. **Good**: :: position.x = 5 position.y = target_position.y + 10 dict["key"] = 5 my_array = [4, 5, 6] print("foo") **Bad**: :: position.x=5 position.y = mpos.y+10 dict ["key"] = 5 myarray = [4,5,6] print ("foo") Don't use spaces to align expressions vertically: :: x = 100 y = 100 velocity = 500 Quotes ~~~~~~ Use double quotes unless single quotes make it possible to escape fewer characters in a given string. See the examples below: :: # 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\"") Naming conventions ------------------ These naming conventions follow the Godot Engine style. Breaking these will make your code clash with the built-in naming conventions, which is ugly. Classes and nodes ~~~~~~~~~~~~~~~~~ Use PascalCase for class and node names: :: extends KinematicBody Also use PascalCase when loading a class into a constant or a variable: :: const Weapon = preload("res://weapon.gd") Functions and variables ~~~~~~~~~~~~~~~~~~~~~~~ Use snake\_case to name functions and variables: :: 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(): Signals ~~~~~~~ Use the past tense to name signals: :: signal door_opened signal score_changed Constants and enums ~~~~~~~~~~~~~~~~~~~ Write constants with CONSTANT\_CASE, that is to say in all caps with an underscore (\_) to separate words: :: const MAX_SPEED = 200 Use PascalCase for enum *names* and CONSTANT\_CASE for their members, as they are constants: :: enum Element { EARTH, WATER, AIR, FIRE, } Static typing ------------- Since Godot 3.1, GDScript supports :ref:`optional static typing`. Type hints ~~~~~~~~~~ Place the colon right after the variable's name, without a space, and let the GDScript compiler infer the variable's type when possible. **Good**: :: onready var health_bar: ProgressBar = get_node("UI/LifeBar") var health := 0 # The compiler will use the int type **Bad**: :: # The compiler can't infer the exact type and will use Node # instead of ProgressBar onready var health_bar := get_node("UI/LifeBar") When you let the compiler infer the type hint, write the colon and equal signs together: ``:=``. :: var health := 0 # The compiler will use the int type Add a space on either sides of the return type arrow when defining functions. :: func heal(amount: int) -> void: