GDScript 치트시트
마지막 업데이트
기본과 출력
스크립트는 노드 타입을 상속하고, 그 함수들은 Godot가 대신 호출해 줍니다.
| 작업 | 문법 |
|---|---|
| 스크립트를 노드 타입에 연결 | extends Node |
| 노드가 시작될 때 실행할 코드 | func _ready() -> void:
print("Hello, World!") |
| 구분자 없이 값 출력 | print("HP: ", hp) |
| 공백으로 구분해 값 출력 | prints("a", "b", 3) |
| 주석 | # This is a comment |
| 문서화 주석 | ## Shown in the editor's help |
| 여러 줄 문자열 | var text := """Line one
Line two""" |
| 오류 보고 | push_error("Health is negative") |
| 경고 보고 | push_warning("Old save file") |
변수, 상수, 타입
타입은 선택 사항입니다. 붙이면 에디터 검사와 자동 완성을 쓸 수 있고 코드도 빨라집니다.
| 작업 | 문법 |
|---|---|
| 변수 (동적 타입) | var score = 0 |
| 정적 타입 변수 | var speed: float = 200.0 |
| 정적 타입 추론 | var lives := 3 |
| 상수 | const MAX_HP = 100 |
| 열거형 (enum) | enum State { IDLE, RUN, JUMP } |
| enum 값 사용 | var state: State = State.IDLE |
| 벡터와 색상 값 | var pos := Vector2(10, 20)
var tint := Color(1, 0, 0) |
| 빈 객체 참조 | var target: Node = null |
| 문자열, int, float로 변환 | str(42), int("42"), float("3.5") |
| float를 int로 (소수점 이하 버림) | int(3.9) # 3 |
| 타입 확인 | value is int, node is Sprite2D |
| 타입 캐스트 | var sprite := node as Sprite2D |
연산자
익숙한 산술 연산에, 논리 연산에는 영어 단어를 씁니다.
| 작업 | 문법 |
|---|---|
| 더하기, 빼기, 곱하기, 나누기 | a + b, a - b, a * b, a / b |
| 정수 나눗셈 (int / int) | 7 / 2 # 3 |
| 나머지 | 7 % 3, fmod(7.5, 2.0) |
| 거듭제곱 | 2 ** 10 # 1024 |
| 복합 대입 | x += 1, x -= 1, x *= 2, x /= 2 |
| 비교 | ==, !=, <, >, <=, >= |
| 논리 연산 | a and b, a or b, not a |
| 논리 연산 (기호 형태) | a && b, a || b, !a |
| 인라인 if | var label := "win" if score > 10 else "lose" |
| 컬렉션에 포함되는지 | "sword" in inventory |
| 비트 연산 | a & b, a | b, a ^ b, ~a, a << 1, a >> 1 |
제어 흐름
Python처럼 블록은 들여쓰기로 정해집니다. Godot는 기본적으로 탭으로 들여씁니다.
| 작업 | 문법 |
|---|---|
| if, elif, else | if hp <= 0:
die()
elif hp < 20:
print("Low HP")
else:
print("OK") |
| 한 줄 if | if hp <= 0: die() |
| 범위 반복 | for i in range(5):
print(i) # 0 to 4 |
| 시작, 끝, 간격을 지정한 범위 | for i in range(10, 0, -2):
print(i) # 10, 8, 6, 4, 2 |
| n번 반복 | for i in 3:
print(i) # 0, 1, 2 |
| 배열 반복 | for item in items:
print(item) |
| 타입이 지정된 반복 변수 (Godot 4.2+) | for n: String in names:
print(n.to_upper()) |
| while 반복문 | while hp > 0:
hp -= 10 |
| 반복 종료 또는 한 번 건너뛰기 | break, continue |
| 빈 블록 자리 표시자 | pass |
패턴 매칭 (match)
match는 패턴이 맞는 첫 번째 분기를 실행합니다. 폴스루는 없습니다.
| 작업 | 문법 |
|---|---|
| 값 매칭 | match state:
State.IDLE:
print("idle")
State.RUN:
print("run") |
| 한 분기에 여러 값 | match key:
"w", "up":
move_up() |
| 기본 분기 (와일드카드) | match n:
0:
print("zero")
_:
print("other") |
| 값을 이름에 바인딩 | match cmd:
"quit":
get_tree().quit()
var other:
print("Unknown: ", other) |
| 배열 패턴 | match pos:
[0, 0]:
print("origin")
[var x, 0]:
print("on the x axis at ", x) |
| 뒤에 아무 요소나 오는 배열 | match args:
["move", ..]:
print("move command") |
| 딕셔너리 패턴 | match item:
{"type": "coin", "value": var v}:
gold += v |
| when 가드 (Godot 4.4+) | match score:
var s when s >= 90:
print("A")
var s when s >= 75:
print("B")
_:
print("C") |
함수와 람다
함수도 값입니다. 저장하고, 전달하고, 인자를 바인딩할 수 있습니다.
| 작업 | 문법 |
|---|---|
| 타입이 지정된 매개변수와 반환값 | func add(a: int, b: int) -> int:
return a + b |
| 반환값 없음 | func reset() -> void:
score = 0 |
| 기본 인자 | func greet(who := "player") -> void:
print("Hi, ", who) |
| 정적 함수 | static func double(x: int) -> int:
return x * 2 |
| 한 줄 람다 | var square := func(x): return x * x |
| Callable 호출 | square.call(4) # 16 |
| 값으로서의 함수 | var on_done := reset
on_done.call() |
| 인자 바인딩 | var add_ten := add.bind(10)
print(add_ten.call(5)) # 15 |
| 여러 줄 람다 | var greet_all := func(names: Array) -> void:
for n in names:
print("Hi, ", n) |
| 타이머 기다리기 | await get_tree().create_timer(1.0).timeout |
| 코루틴 기다리기 | var data = await fetch_data() |
문자열
문자열 메서드는 새 문자열을 반환하며 원본은 바꾸지 않습니다.
| 작업 | 문법 |
|---|---|
| %로 포맷 | "%s has %d HP" % [name, hp] |
| 소수점 둘째 자리까지 | "%.2f" % 3.14159 # "3.14" |
| 이름 있는 자리 표시자로 포맷 | "{a} vs {b}".format({"a": 1, "b": 2}) |
| +로 이어 붙이기 | "Score: " + str(score) |
| 길이 | text.length() |
| 대문자 또는 소문자 | text.to_upper(), text.to_lower() |
| 여러 부분으로 나누기 | "a,b,c".split(",") # ["a", "b", "c"] |
| 부분 합치기 | ", ".join(["a", "b", "c"]) |
| 앞뒤 공백 제거 | " hi ".strip_edges() # "hi" |
| 텍스트 바꾸기 | text.replace("cat", "dog") |
| 위치 찾기 | text.find("lo") # -1 if missing |
| 시작 또는 끝 문자열 확인 | text.begins_with("Hi"), text.ends_with("!") |
| 부분 문자열 | text.substr(0, 5) |
| 포함 여부 | "ell" in "Hello" # true |
배열
배열은 늘어나고 줄어듭니다. 타입 배열은 지정한 요소 타입만 받습니다.
| 작업 | 문법 |
|---|---|
| 배열 리터럴 (타입 혼합) | var items = [1, "two", 3.0] |
| 타입 배열 | var scores: Array[int] = [10, 20, 30] |
| 인덱스로 읽기 (음수는 끝에서부터) | scores[0], scores[-1] |
| 끝에 추가 | scores.append(40), scores.push_back(40) |
| 인덱스 위치에 삽입 | scores.insert(0, 5) |
| 마지막 요소를 꺼내고 제거 | var last = scores.pop_back() |
| 값 또는 인덱스로 제거 | scores.erase(20), scores.remove_at(0) |
| 포함 여부, 인덱스 찾기 | scores.has(30), scores.find(30) |
| 길이, 비어 있는지 확인 | scores.size(), scores.is_empty() |
| 정렬 | scores.sort() |
| 직접 정한 규칙으로 정렬 | enemies.sort_custom(func(a, b): return a.hp < b.hp) |
| map | scores.map(func(x): return x * 2) |
| filter | scores.filter(func(x): return x > 15) |
| reduce | scores.reduce(func(acc, x): return acc + x, 0) |
| 슬라이스 (끝은 제외) | scores.slice(1, 3) |
딕셔너리
키와 값의 쌍입니다. 키는 어떤 타입이든 되지만 보통 문자열을 씁니다.
| 작업 | 문법 |
|---|---|
| 딕셔너리 리터럴 | var stats = {"hp": 100, "mp": 30} |
| 타입 딕셔너리 (Godot 4.4+) | var prices: Dictionary[String, int] = {"sword": 50} |
| 키 읽기 또는 쓰기 | stats["hp"], stats["xp"] = 50 |
| 기본값과 함께 읽기 | stats.get("luck", 0) |
| 키가 있는지 | stats.has("hp"), "hp" in stats |
| 키 제거 | stats.erase("mp") |
| 키와 값 목록 | stats.keys(), stats.values() |
| 항목 수 | stats.size() |
| 다른 딕셔너리 병합 (true면 덮어쓰기) | stats.merge({"luck": 5}), stats.merge(bonus, true) |
| 키 반복 | for key in stats:
print(key, " = ", stats[key]) |
클래스와 어노테이션
모든 스크립트는 클래스입니다. 어노테이션은 @로 시작합니다.
| 작업 | 문법 |
|---|---|
| 클래스에 전역 이름 붙이기 | class_name Player
extends CharacterBody2D |
| 생성자 | func _init(start_hp := 100) -> void:
hp = start_hp |
| 인스턴스 생성 | var p := Player.new() |
| 내부 클래스 | class Item:
var name := ""
var price := 0 |
| 이 메서드의 부모 버전 호출 | func _ready() -> void:
super()
print("child ready") |
| 다른 부모 메서드 호출 | super.take_damage(10) |
| 정적 변수 (Godot 4.1+) | static var count := 0 |
| 인스펙터에 표시 | @export var speed := 300.0 |
| 슬라이더 범위와 함께 표시 | @export_range(0, 100) var volume := 50 |
| 준비되면 자식 노드 가져오기 | @onready var sprite: Sprite2D = $Sprite2D |
| 세터와 게터 | var hp := 100:
set(value):
hp = clampi(value, 0, 100)
get:
return hp |
| 에디터에서 스크립트 실행 | @tool |
시그널
시그널은 일급 객체입니다. 선언한 뒤 바로 emit, connect, await할 수 있습니다.
| 작업 | 문법 |
|---|---|
| 시그널 선언 | signal died |
| 타입이 지정된 인자를 가진 시그널 | signal health_changed(old_hp: int, new_hp: int) |
| 발신 (emit) | died.emit() |
| 인자와 함께 발신 | health_changed.emit(100, 80) |
| 메서드에 연결 | player.died.connect(_on_player_died) |
| 람다 연결 | button.pressed.connect(func(): print("Clicked")) |
| 추가 인자 전달 | button.pressed.connect(_on_pressed.bind("start")) |
| 한 번만 실행 | timer.timeout.connect(_on_timeout, CONNECT_ONE_SHOT) |
| 연결 해제 | player.died.disconnect(_on_player_died) |
| 연결 확인 | player.died.is_connected(_on_player_died) |
| 시그널 기다리기 | await player.died |
노드와 생명주기
Godot가 노드에서 호출하는 콜백과, 씬 트리에 직접 하는 호출입니다.
| 작업 | 문법 |
|---|---|
| 객체 생성 (트리에 들어가기 전) | func _init() -> void:
print("created") |
| 노드와 자식 노드 준비 완료 | func _ready() -> void:
print("ready") |
| 매 프레임 | func _process(delta: float) -> void:
position.x += 100.0 * delta |
| 물리 틱마다 | func _physics_process(delta: float) -> void:
velocity.y += 980.0 * delta
move_and_slide() |
| UI가 쓰지 않은 입력 | func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("jump"):
jump() |
| 경로로 노드 가져오기 | get_node("Sprite2D"), $Sprite2D |
| 공백이 있는 경로, 고유 이름 | $"UI/Health Bar", %HealthBar |
| 입력 액션 확인 | Input.is_action_pressed("move_right") |
| 씬 인스턴스 생성 | var enemy := preload("res://enemy.tscn").instantiate()
add_child(enemy) |
| 노드를 안전하게 삭제 | queue_free() |
| 부모와 자식 | get_parent(), get_children() |
| 씬 전환 | get_tree().change_scene_to_file("res://main.tscn") |
Godot로 게임을 만들 때 자주 찾게 되는 GDScript 문법을 한 페이지에 담았습니다. 이 GDScript 치트시트는 Godot 4를 위한 빠른 참조 자료입니다. 변수와 정적 타입, 연산자, 제어 흐름과 match, 함수와 람다, 문자열, 배열과 딕셔너리, 클래스, 시그널, 그리고 Godot가 매 프레임 호출하는 노드 콜백을 다룹니다.
여기 나오는 모든 내용은 Godot 4 문법이므로 Godot 3 방식 대신 @export, @onready, died.emit(), await를 보게 됩니다. 필요한 부분을 스크립트에 복사하거나, GDScript 플레이그라운드에서 언어 예제를 바로 실행해 보세요. _ready() 안에 넣으면 Godot를 설치하지 않고도 브라우저에서 실행됩니다.
GDScript 치트시트 자주 묻는 질문
이 GDScript 치트시트는 무료인가요?
이 치트시트는 Godot 4용인가요, Godot 3용인가요?
export와 onready 키워드 대신 @export와 @onready 어노테이션을, emit_signal("died")와 문자열 기반 connect 대신 died.emit()와 died.connect(callable)를, yield 대신 await를, .method() 대신 super()를 사용합니다. 4.1+, 4.2+, 4.4+로 표시된 행은 최소 해당 버전의 Godot가 필요합니다.GDScript에서 =와 :=의 차이는 무엇인가요?
var x = 5는 나중에 어떤 타입이든 담을 수 있는 동적 변수를 만듭니다. var x := 5는 값에서 타입(여기서는 int)을 추론해 고정하므로, 나중에 문자열을 대입하면 오류가 납니다. var x: int = 5는 타입을 명시적으로 지정합니다. 정적 타입을 쓰면 에디터에서 오류를 바로 볼 수 있고, 자동 완성이 좋아지며, 코드도 빨라집니다.GDScript에서 시그널은 어떻게 동작하나요?
signal died로 시그널을 선언하고, died.emit()로 보내고, 다른 노드에서 player.died.connect(_on_player_died)로 반응합니다. 메서드 대신 람다를 연결하거나, .bind()로 추가 인자를 바인딩하거나, await player.died로 시그널이 발생할 때까지 함수를 멈출 수도 있습니다.GDScript는 Python과 비슷한가요?
for ... in, if/elif/else, 그리고 and, or, not 같은 영어 단어를 씁니다. 하지만 GDScript는 Godot를 위해 만들어진 별도의 언어입니다. 선택적인 정적 타입, 시그널, @export 같은 어노테이션이 있고, $로 노드에 바로 접근할 수 있습니다.GDScript를 온라인에서 연습할 수 있나요?
_ready() 안의 코드가 한 번 실행됩니다. 체계적으로 배우고 싶다면 Coddy의 무료 인터랙티브 GDScript 강좌에서 변수와 함수부터 클래스와 시그널까지 단계별로 배울 수 있습니다.