123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- .. _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 <https://www.python.org/dev/peps/pep-0008/>`__ 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 <https://en.wikipedia.org/wiki/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
- <kbd>Ctrl</kbd> <kbd>K</kbd>. 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<doc_gdscript_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:
|