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...
GDScript 스타일 가이드
이 스타일 가이드는 우아한 GDScript를 작성하기 위한 규칙을 나열합니다. 목표는 깨끗하고 읽기 쉬운 코드 작성을 장려하고 프로젝트, 토론 및 튜토리얼 전반에 걸쳐 일관성을 촉진하는 것입니다. 바라건대 이 가이드는 자동 서식 툴의 개발도 지원할 것입니다.
GDScript는 Python에 가깝기 때문에 이 가이드는 Python의 PEP 8 프로그래밍 스타일 가이드에서 영감을 받았습니다.
스타일 가이드는 빡빡한 법전이 아닙니다. 아직은 아래의 가이드라인을 적용하지 못할 수도 있습니다. 그런 일이 발생하면 최선의 판단을 내리고 동료 개발자에게 통찰력을 요청하세요.
일반적으로 프로젝트와 팀 내에서 코드를 일관되게 유지하는 것이 이 가이드를 따라가는 것보다 더 중요합니다.
참고
Godot의 내장 스크립트 에디터는 기본적으로 이러한 규칙을 많이 사용합니다. 에디터가 여러분을 도울 수 있도록 하세요.
이 가이드라인을 기반으로 한 전체 클래스 예제입니다:
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!")
서식(Formatting)
인코딩과 특수 문자
줄 바꿈을 위해 라인 피드 (LF) 문자를 사용합니다. CRLF나 CR은 사용하지 않습니다 (편집기 기본 설정)
각 파일의 끝에 하나의 라인 피드 문자를 사용합니다. (편집기 기본 설정)
바이트 순서 표식 없이 UTF-8 인코딩을 사용합니다. (편집기 기본 설정)
들여쓰기로 스페이스바 대신 Tab(탭) 키를 사용합니다. (편집기 기본 설정)
들여쓰기
들여쓰기 너비는 블록 바깥보다 한 칸 더 커야 됩니다.
좋음:
for i in range(10):
print("hello")
나쁨:
for i in range(10):
print("hello")
for i in range(10):
print("hello")
정규 코드 블록과 이어지는 줄을 구분하기 위해 2 칸 들여쓰기를 사용하세요.
좋음:
effect.interpolate_property(sprite, "transform/scale",
sprite.get_scale(), Vector2(2.0, 2.0), 0.3,
Tween.TRANS_QUAD, Tween.EASE_OUT)
나쁨:
effect.interpolate_property(sprite, "transform/scale",
sprite.get_scale(), Vector2(2.0, 2.0), 0.3,
Tween.TRANS_QUAD, Tween.EASE_OUT)
이 규칙의 예외는 배열, 딕셔너리, 열거형입니다. 연속되는 줄을 구분하려면 한 칸 들여쓰기를 사용하세요:
좋음:
var party = [
"Godot",
"Godette",
"Steve",
]
var character_dict = {
"Name": "Bob",
"Age": 27,
"Job": "Mechanic",
}
enum Tiles {
TILE_BRICK,
TILE_FLOOR,
TILE_SPIKE,
TILE_TELEPORT,
}
나쁨:
var party = [
"Godot",
"Godette",
"Steve",
]
var character_dict = {
"Name": "Bob",
"Age": 27,
"Job": "Mechanic",
}
enum Tiles {
TILE_BRICK,
TILE_FLOOR,
TILE_SPIKE,
TILE_TELEPORT,
}
쉼표 매달기(Trailing comma)
배열, 딕셔너리, 열거형의 마지막 줄에 쉼표 매달기를 사용하세요. 이렇게 하면 새 요소를 추가해도 이전의 마지막 줄을 수정하지 않아도 되기 때문에 리팩토링하기 쉽고 버전 컨트롤에서 비교가 더 잘 됩니다.
좋음:
var array = [
1,
2,
3,
]
나쁨:
var array = [
1,
2,
3
]
쉼표 매달기는 한 줄 목록에는 불필요합니다. 따라서 이 경우는 사용하지 마세요.
좋음:
var array = [1, 2, 3]
나쁨:
var array = [1, 2, 3,]
공백 줄(Blank lines)
함수와 클래스 정의를 두 개의 공백 줄로 묶습니다:
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)
로직 섹션을 분리하기 위해 함수 안에 하나의 공백 줄을 사용합니다.
참고
We use a single line between classes and function definitions in the class reference and in short code snippets in this documentation.
줄 길이
코드 한 줄은 100 문자 이내로 유지합니다.
가능하다면 80 문자 이내로 유지해보세요. 이렇게 하면 작은 화면에서도 코드를 읽기 쉽고, 외부 텍스트 에디터에서 양쪽에 두 스크립트가 열려있는 화면에서도 읽기 쉽습니다. 예를 들면 서로 다른 코드 개정판을 볼 때요.
한 줄에 하나의 명령문
Avoid combining multiple statements on a single line, including conditional statements, to adhere to the GDScript style guidelines for readability.
좋음:
if position.x > width:
position.x = 0
if flag:
print("flagged")
나쁨:
if position.x > width: position.x = 0
if flag: print("flagged")
유일한 예외라면 삼항(Ternary) 연산자일 것입니다:
next_state = "idle" if is_on_floor() else "fall"
가독성을 위해서 여러 줄로 명령문 형식 지정
특히 긴 if
문이나 중첩된 삼항 표현식이 있는 경우 여러 줄로 감싸면 가독성이 향상됩니다. 연속되는 줄은 여전히 동일한 표현식의 일부이므로 하나 대신 2개의 들여쓰기 수준을 사용해야 합니다.
GDScript에서는 괄호나 백슬래시를 사용해 여러 줄을 사용하여 명령문을 줄 바꿈할 수 있습니다. 괄호는 더 쉽게 리팩토링할 수 있도록 하기 때문에 이 스타일 가이드에서 선호됩니다. 백슬래시를 사용하면 마지막 줄 끝에 백슬래시가 포함되지 않도록 해야 합니다. 괄호를 사용하면 마지막 줄 끝에 백슬래시가 있는 것에 대해 걱정할 필요가 없습니다.
조건식을 여러 줄로 묶을 때 and
/or
키워드는 이전 줄의 끝이 아니라 줄 연속의 시작 부분에 배치해야 합니다.
좋음:
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
나쁨:
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
불필요한 괄호 피하기
표현식과 조건문에서 괄호를 사용하지 마세요. 작업 순서나 여러 줄을 묶는 데에 필요한 경우가 아니면 가독성만 떨어뜨립니다.
좋음:
if is_colliding():
queue_free()
나쁨:
if (is_colliding()):
queue_free()
불리언(Boolean) 연산자
가장 접근하기 쉬운 불리언 연산자의 영어 텍스트 버전을 선호합니다:
&&
대신and
를 사용하세요.||
대신or
를 사용하세요.Use
not
instead of!
.
모호한 표현을 막고자 불리언 연산자 주변에 괄호를 사용하세요. 이렇게 하면 긴 표현식도 읽기 쉬워집니다.
좋음:
if (foo and bar) or not baz:
print("condition is true")
나쁨:
if foo && bar || !baz:
print("condition is true")
공백
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.
좋음:
position.x = 5
position.y = target_position.y + 10
dict["key"] = 5
my_array = [4, 5, 6]
my_dictionary = { key = "value" }
print("foo")
나쁨:
position.x=5
position.y = mpos.y+10
dict ["key"] = 5
myarray = [4,5,6]
my_dictionary = {key = "value"}
print ("foo")
표현식을 세로로 정렬하기 위해 공백을 사용하지 마세요:
x = 100
y = 100
velocity = 500
따옴표
작은 따옴표로 주어진 문자열을 더 작은 문자 수로 이스케이프하게 만드는 것이 아니라면 큰 따옴표를 사용하세요. 아래의 예제를 참고하세요:
# 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\"")
숫자
부동 소수점 숫자에서 앞뒤에 붙는 0을 생략하지 마세요. 그렇지 않으면 가독성이 떨어지고 정수와 한눈에 구별하기 어려워집니다.
좋음:
var float_number = 0.234
var other_float_number = 13.0
나쁨:
var float_number = .234
var other_float_number = 13.
16진수의 문자에는 소문자를 사용하세요. 알파벳 높이가 낮을수록 숫자를 더 읽기 쉽게 하기 때문입니다.
좋음:
var hex_number = 0xfb8c0b
나쁨:
var hex_number = 0xFB8C0B
리터럴에서 GDScript의 밑줄을 활용해 큰 숫자를 더 읽기 쉽게 만드세요.
좋음:
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
나쁨:
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
명명 규칙
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:
타입 |
Convention |
예제 |
---|---|---|
파일 이름 |
snake_case |
|
Class names |
PascalCase |
|
Node names |
PascalCase |
|
함수(Function) |
snake_case |
|
변수(Variable) |
snake_case |
|
시그널 |
snake_case |
|
상수 |
CONSTANT_CASE |
|
Enum names |
PascalCase |
|
Enum members |
CONSTANT_CASE |
|
파일 이름
파일 이름으로 스네이크_표기법(snake_case)을 사용하세요. 명명된 클래스의 경우 파스칼 표기(PascalCase)된 클래스 이름을 스네이크_표기(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
이는 Godot의 소스 코드에서 C++ 파일의 이름이 어떻게 지정되는지와 일치합니다. 이는 또한 Windows에서 다른 플랫폼으로 프로젝트를 내보낼 때 발생할 수 있는 대소문자 구분 문제를 방지합니다.
클래스와 노드
클래스와 노드 이름에는 파스칼 표기법(PascalCase)을 사용하세요:
extends CharacterBody3D
그리고 상수 또는 변수로 클래스를 불러올 때도 파스칼 표기법(PascalCase)을 사용하세요:
const Weapon = preload("res://weapon.gd")
함수와 변수
함수와 변수 이름에는 스네이크_표기법(snake_case)을 사용하세요:
var particle_effect
func load_level():
사용자가 재정의해야 하는 가상 메서드 함수, private 함수, private 변수 앞에 밑줄(_) 하나를 추가하세요:
var _counter = 0
func _recalculate_path():
시그널
시그널의 이름에는 과거형을 사용하세요:
signal door_opened
signal score_changed
상수(Constant)와 열거형(enum)
상수_표기법(CONSTANT_CASE)으로 상수를 작성하세요. 다시 말해, 모든 단어는 대문자로 하고 띄어쓰기 대신 밑줄 (_)을 사용하세요:
const MAX_SPEED = 200
열거형 이름에는 파스칼 표기법(PascalCase)을 사용하고, 열거형의 멤버에는 상수와 마찬가지로 상수_표기법(CONSTANT_CASE)을 사용하세요:
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.
좋음:
enum Element {
EARTH,
WATER,
AIR,
FIRE,
}
나쁨:
enum Element { EARTH, WATER, AIR, FIRE }
코드 순서
This section focuses on code order. For formatting, see 서식(Formatting). For naming conventions, see 명명 규칙.
제안하는 GDScript 코드 구조는 다음과 같습니다:
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. subclasses
And put the class methods and variables in the following order depending on their access modifiers:
1. public
2. private
코드를 위에서 아래로 쉽게 읽을 수 있도록 순서를 최적화했으며, 코드를 처음 읽는 개발자가 어떻게 작동하는지 이해하고 변수 선언 순서와 관련된 오류를 방지할 수 있습니다.
이 코드 순서는 네 가지 규칙을 따릅니다:
속성과 시그널이 첫 번째로 옵니다. 그 뒤는 메서드가 나옵니다.
공개(Public) 코드가 개인(Private) 코드보다 먼저 옵니다.
가상 콜백(Virtual Callback)이 클래스의 인터페이스(Class's Interface)보다 먼저 옵니다.
오브젝트의 생성 및 초기화 함수인
_init
과_ready
는 런타임에서 오브젝트를 수정하는 함수보다 먼저 옵니다.
클래스 선언(Declaration)
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 GDScript reference.
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.
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.
시그널(Signal)과 속성(Property)
Docstring이 끝나면 시그널 선언을 작성한 뒤에 속성, 즉 멤버 변수를 작성합니다.
열거형(Enum)은 시그널 뒤에 나와야 합니다. 다른 속성의 내보내기 힌트로 사용할 수 있기 때문이죠.
그런 다음, 상수(Constant), 내보낸 변수, 공개(Public), 개인(Private), onready 변수를 순서대로 작성하세요.
signal player_spawned(position)
enum Jobs {
KNIGHT,
WIZARD,
ROGUE,
HEALER,
SHAMAN,
}
const MAX_LIVES = 3
@export var job: Jobs = Jobs.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")
참고
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.
멤버 변수
메서드에서 지역적으로만 사용되는 경우 멤버 변수를 선언하지 마세요. 코드를 따라가기 더 어렵게 만들기 때문입니다. 대신 메서드 본문에서 지역 변수로 선언하세요.
지역 변수(Local Variables)
지역 변수를 처음 사용할 때와 최대한 가깝게 선언하세요. 이렇게 하면 변수가 선언된 위치를 찾기 위해 너무 많이 스크롤하지 않고도 코드를 더 쉽게 따라갈 수 있습니다.
메서드(Method)와 정적(Static) 함수
클래스 속성 뒤에는 메서드가 옵니다.
엔진이 메모리에 오브젝트를 생성할 때 호출하는 _init()
콜백 메서드로 시작하세요. 그 뒤로 Godot가 씬 트리에 노드를 추가할 때 호출하는 _ready()
콜백이 옵니다.
이러 함수들은 오브젝트가 초기화되는 방법을 보여주기 때문에 먼저 와야 합니다.
_unhandled_input()
, _physics_process
와 같은 다른 내장된 가상 콜백은 다음에 와야 합니다. 이 메서드들은 오브젝트의 메인 루프와 게임 엔진과의 상호작용을 제어합니다.
이 다음은 순서에 따라 클래스 인터페이스의 나머지인 공개 메서드와 개인 메서드가 옵니다.
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()
정적 타이핑(Static Typing)
GDScript supports optional static typing.
선언된 타입
변수의 타입을 선언하려면 <variable>: <type>
을 사용하세요:
var health: int = 0
함수의 반환 타입을 선언하려면 -> <type>
을 사용하세요:
func heal(amount: int) -> void:
추론된 타입
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.
좋음:
var health: int = 0 # The type can be int or float, and thus should be stated explicitly.
var direction := Vector3(1, 2, 3) # The type is clearly inferred as Vector3.
Include the type hint when the type is ambiguous, and omit the type hint when it's redundant.
나쁨:
var health := 0 # Typed as int, but it could be that float was intended.
var direction: Vector3 = Vector3(1, 2, 3) # The type hint has redundant information.
# 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.
좋음:
@onready var health_bar: ProgressBar = get_node("UI/LifeBar")
또는 as
키워드를 사용해 반환 타입을 캐스팅할 수 있으며, 해당 타입은 var의 타입을 추론하는 데 사용됩니다.
@onready var health_bar := get_node("UI/LifeBar") as ProgressBar
# health_bar will be typed as ProgressBar
이 방법은 첫 번째 방법보다 더 타입에 안전한것으로 간주됩니다.
나쁨:
# The compiler can't infer the exact type and will use Node
# instead of ProgressBar.
@onready var health_bar := get_node("UI/LifeBar")
주석(Comment) 간격
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.
좋음:
나쁨:
참고
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.