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.

현재 씬 변경하기

GDScript는 콘텐츠를 만드는 데 사용되는 동적 타입 고급 프로그래밍 언어입니다. Python과 비슷한 문법을 사용합니다(블록이 들여쓰기 기반이고, 많은 키워드가 비슷합니다). 이 언어의 목적은 Godot 엔진에 최적화되고 긴밀하게 통합되어 컨텐츠 생성 및 통합을 위한 뛰어난 유연성을 제공하는 것입니다.

GDScript는 Python과 완전히 독립적이며 이를 기반으로 하지 않습니다.

역사

참고

GDScript의 역사에 대한 문서는 자주 묻는 질문으로 이동되었습니다.

GDScript 예제

어떤 사람들은 구문을 살펴봄으로써 더 잘 배울 수 있습니다. 그래서 여기에 간단한 GDScript 예제가 있습니다.

# Everything after "#" is a comment.
# A file is a class!

# (optional) icon to show in the editor dialogs:
@icon("res://path/to/optional/icon.svg")

# (optional) class definition:
class_name MyClass

# Inheritance:
extends BaseClass


# Member variables.
var a = 5
var s = "Hello"
var arr = [1, 2, 3]
var dict = {"key": "value", 2: 3}
var other_dict = {key = "value", other_key = 2}
var typed_var: int
var inferred_type := "String"

# Constants.
const ANSWER = 42
const THE_NAME = "Charly"

# Enums.
enum {UNIT_NEUTRAL, UNIT_ENEMY, UNIT_ALLY}
enum Named {THING_1, THING_2, ANOTHER_THING = -1}

# Built-in vector types.
var v2 = Vector2(1, 2)
var v3 = Vector3(1, 2, 3)


# Function, with a default value for the last parameter.
func some_function(param1, param2, param3 = 123):
    const local_const = 5

    if param1 < local_const:
        print(param1)
    elif param2 > 5:
        print(param2)
    else:
        print("Fail!")

    for i in range(20):
        print(i)

    while param2 != 0:
        param2 -= 1

    match param3:
        3:
            print("param3 is 3!")
        _:
            print("param3 is not 3!")

    var local_var = param1 + 3
    return local_var


# Functions override functions with the same name on the base/super class.
# If you still want to call them, use "super":
func something(p1, p2):
    super(p1, p2)


# It's also possible to call another function in the super class:
func other_something(p1, p2):
    super.something(p1, p2)


# Inner class
class Something:
    var a = 10


# Constructor
func _init():
    print("Constructed!")
    var lv = Something.new()
    print(lv.a)

이전에 C, C++, C#과 같은 정적 타입 언어에 대한 경험이 있지만 한 번도 동적 타입 언어를 써 본 적이 없다면, 이 튜토리얼을 읽는 것이 좋습니다: GDScript: 동적 언어 소개.

식별자

알파벳 문자로 제한되는 문자열 (a부터 z, A부터 Z), 숫자 (0부터 9), _는 식별자입니다. 추가로 식별자는 숫자로 시작할 수 없습니다. 식별자는 대소문자를 구분합니다 (fooFOO와 다릅니다).

식별자에는 `UAX#31 <https://www.unicode.org/reports/tr31/>`__의 대부분의 유니코드 문자 부분이 포함될 수도 있습니다. 이를 통해 영어 이외의 언어로 작성된 식별자 이름을 사용할 수 있습니다. ASCII 문자 및 이모티콘에 대해 "혼동 가능"하다고 간주되는 유니코드 문자는 식별자에 허용되지 않습니다.

키워드

다음은 언어에서 지원하는 키워드 목록입니다. 키워드는 예약된 단어(토큰)이기 때문에, 식별자로 사용할 수 없습니다. 다음 섹션에 나열된 (in, not, and 혹은 or 와 같은) 연산자와 내장 타입 이름 역시 예약된 단어입니다.

키워드는 GDScript tokenizer에 정의되어 있습니다. 정체가 궁금하다면 확인해보세요.

키워드

설명

if

if/else/elif를 참고하세요.

elif

if/else/elif를 참고하세요.

else

if/else/elif를 참고하세요.

for

for를 참고하세요.

while

while을 참고하세요.

match

match를 참고하세요.

언제

match 문에서 `패턴 가드 <패턴 가드>`_에서 사용됩니다.

break

현재의 for 또는 while 루프 실행을 끝냅니다.

continue

즉시 for 또는 while 루프의 다음 반복으로 건너뜁니다.

pass

명령문이 문법적으로는 필요하지만 실행할 만한 코드가 마땅치 않을 때 사용됩니다. 예: 빈 함수.

return

함수에서 값을 반환합니다.

클래스

다른 클래스 파일의 내부 클래스.

class_name

스크립트를 지정된 이름을 가진 전역적으로 액세스 가능한 클래스로 정의합니다. `Registering named classes`_를 참조하세요.

extends

현재 클래스로 확장할 클래스를 정의합니다.

is

변수가 주어진 클래스를 확장하는지, 혹은 변수가 주어진 내장 유형인지 여부를 테스트합니다.

안으로

값이 문자열, 배열, 범위, 사전 또는 노드 내에 있는지 테스트합니다. ``for``와 함께 사용하면 테스트하는 대신 반복됩니다.

as

가능하다면 주어진 타입으로 값을 캐스트합니다.

self

현재 클래스 인스턴스를 참조합니다.

슈퍼

상위 메서드의 범위를 확인합니다. `Inheritance`_를 참조하세요.

signal

시그널을 정의합니다.

func

함수를 정의합니다.

static

정적 함수를 정의합니다. 정적 멤버 변수를 허용하지 않습니다.

const

상수를 정의합니다.

enum

열거형을 정의합니다. Enums를 참조하세요.

var

변수를 정의합니다.

breakpoint

디버거 중단점을 위한 편집기 도우미입니다. 여백을 클릭하여 생성된 중단점과 달리 ``breakpoint``는 스크립트 자체에 저장됩니다. 이렇게 하면 버전 제어를 사용할 때 여러 컴퓨터에서 지속됩니다.

preload

클래스나 변수를 미리 불러옵니다. 리소스로 취급되는 클래스를 참고하세요.

await

시그널 또는 코루틴이 완료될 때까지 기다립니다. `Awaiting signals or coroutines`_를 참조하세요.

yield

이전에는 코루틴에 사용되었습니다. 전환을 위한 키워드로 유지됩니다.

assert

조건을 가정(Assert)하고 실패 시 오류를 기록합니다. 디버그가 아닌 빌드에서는 무시됩니다. Assert 키워드를 참고하세요.

무효

함수가 어떤 값도 반환하지 않음을 나타내는 데 사용됩니다.

PI

PI 상수.

TAU

TAU 상수.

INF

무한대 상수. 비교할 때 사용됩니다.

NAN

NAN (Not A Number, 숫자 아님) 상수. 비교할 때 사용됩니다.

연산자

다음은 지원되는 연산자 목록과 해당 우선순위입니다. ** 연산자를 포함하여 모든 이진 연산자는 left-associative <https://en.wikipedia.org/wiki/Operator_associativity>`_입니다. 이는 ``2 ** 2 ** 3``가 ``(2 ** 2) ** 3``와 동일함을 의미합니다. 필요한 우선 순위를 명시적으로 지정하려면 괄호를 사용하세요(예: ``2 ** (2 ** 3)`). 삼항 if/else 연산자는 오른쪽 연관 연산자입니다.

연산자

설명

<< >>

묶기 (가장 높은 우선순위)

괄호는 실제로 연산자는 아니지만 연산의 우선 순위를 명시적으로 지정할 수 있도록 해줍니다.

x[index]

설명

x.attribute

특성 참조

foo()

함수 호출

await x

시그널이나 코루틴을 기다리기

그룹 노드
그룹 노드

타입 캐스팅

is_instance_of() 함수도 참조하세요.

x ** y

pow() 함수를 호출하는 것과 유사하게 x 자체를 ``y``번 곱합니다.

~x

비트 단위 NOT

+x
-x

들여쓰기

x * y
x / y
x % y

곱하기 / 나누기 / 나머지

% 연산자는 :ref:`형식 문자열 <doc_gdscript_printf>`에 추가로 사용됩니다.

참고: 이러한 연산자는 C++와 동일한 동작을 가지므로 Python, JavaScript 등을 사용하는 사용자에게는 예상치 못한 일이 될 수 있습니다. 표 뒤의 자세한 참고 사항을 참조하세요.

x + y
x - y

더하기 / 배열의 연결

x << y
x >> y

비트 시프트

x & y

비트 단위 AND

x ^ y

비트 단위 XOR

x | y

비트 단위 OR

x == y
x != y
x < y
x > y
x <= y
x >= y

비교

표 뒤의 자세한 내용을 참조하세요.

x in y
x not in y

결론

``in``는 구문의 일부로 for 키워드와 함께 사용되기도 합니다.

그룹 노드
!x

부울 NOT 및 해당 unrecommended 별칭

x and y
x && y

부울 AND 및 해당 unrecommended 별칭

x or y
x || y

부울 OR 및 해당 unrecommended 별칭

true_expr if cond else false_expr

삼항 if/else

그룹 노드

유형 캐스트하기

x = y
x += y
x -= y
x *= y
x /= y
x **= y
x %= y
x &= y
x |= y
x ^= y
x <<= y
x >>= y

지정 (가장 낮은 우선순위)

표현식 내에서는 할당 연산자를 사용할 수 없습니다.

참고

일부 연산자의 동작은 예상한 것과 다를 수 있습니다.

  1. / 연산자의 두 피연산자가 모두 int 리터럴(x / 2.0)을 사용하거나, 캐스팅(float(x) / y)하거나, 1.0``(``x * 1.0 / y)로 곱합니다.

  2. % 연산자는 int에만 사용할 수 있습니다. float의 경우 fmod() 함수를 사용하세요.

  3. 음수 값의 경우 % 연산자와 ``fmod()``는 음의 무한대로 반올림하는 대신 truncation <https://en.wikipedia.org/wiki/Truncation>`_을 사용합니다. 이는 나머지에 부호가 있음을 의미합니다. 수학적 의미에서 나머지가 필요한 경우 :ref:`posmod() <class_@GlobalScope_method_posmod>fposmod() 함수를 대신 사용하세요.

  4. ==!= 연산자를 사용하면 때때로 서로 다른 유형의 값을 비교할 수 있지만(예: ``1 == 1.0``는 true), 다른 경우에는 런타임 오류가 발생할 수 있습니다. 피연산자의 유형이 확실하지 않은 경우 is_same() 함수를 안전하게 사용할 수 있습니다(그러나 유형 및 참조에 대해서는 더 엄격하다는 점에 유의하세요). 부동소수점을 비교하려면 is_equal_about()is_zero_about() 함수를 대신 사용하세요.

리터럴

예제

설명

null

널 값

false, true

불리언 값

45

기본 10진법 정수

0x8f51

기본 16진법 정수

0b101010

기본 2진법 정수

3.14, 58.1e-10

부동 소수점 숫자 (실수)

"안녕하세요", '안녕'

일반 문자열

"안녕하세요", "안녕"

삼중따옴표로 묶인 일반 문자열

"안녕하세요", "안녕"

원형 문자열

"안녕하세요", "안녕"

세 번 따옴표로 묶인 원형 문자열

&"name"

String

@"Node/Label"

NodePath

리터럴처럼 보이지만 실제로는 그렇지 않은 두 가지 구문도 있습니다.

예제

설명

$NodePath

get_node("NodePath")의 짧은 표현

그룹 노드

get_node("NodePath")의 짧은 표현

정수와 부동 소수점 수는 가독성을 높이기 위해 숫자를 _로 구분할 수 있습니다. 숫자를 쓰는 다음 방법은 모두 올바릅니다:

12_345_678  # Equal to 12345678.
3.141_592_7  # Equal to 3.1415927.
0x8080_0000_ffff  # Equal to 0x80800000ffff.
0b11_00_11_00  # Equal to 0b11001100.

**일반 문자열 리터럴**에는 다음 이스케이프 시퀀스가 포함될 수 있습니다.

이스케이프 시퀀스

설명

\n

줄 바꿈 (라인 피드)

\t

수평 탭 문자

\r

캐리지 리턴

\a

경보 (비프/벨)

\b

백스페이스

\f

폼 피드 페이지 나누기

\v

수직 탭 문자

\"

큰 따옴표

\'

작은 따옴표

\\

백슬래시

\uXXXX

UTF-16 유니코드 코드포인트 XXXX (16진수, 대소문자 구분 없음)

\UXXXXXX

UTF-32 유니코드 코드포인트 XXXXXX (16진수, 대소문자 구분 없음)

0xFFFF 위의 이스케이프된 유니코드 문자를 나타내는 방법은 두 가지가 있습니다:

또한 \ 뒤에 문자열 내부에 줄 바꿈을 사용하면 문자열 자체에 줄 바꿈 문자를 삽입하지 않고도 다음 줄에서 계속할 수 있습니다.

한 유형의 따옴표(예: ")로 묶인 문자열은 이스케이프 없이 다른 유형의 따옴표(예: ')를 포함할 수 있습니다. 삼중 따옴표로 묶인 문자열을 사용하면 동일한 유형의 연속 따옴표를 최대 두 개까지 이스케이프 처리할 수 있습니다(문자열 가장자리에 인접하지 않는 한).

**원시 문자열 리터럴**은 항상 소스 코드에 나타나는 대로 문자열을 인코딩합니다. 이는 정규식에 특히 유용합니다. 원시 문자열 리터럴은 이스케이프 시퀀스를 처리하지 않지만 \\\"``('``)를 인식하고 이를 자체적으로 바꿉니다. 따라서 문자열은 시작 부분과 일치하는 따옴표를 가질 수 있지만 앞에 백슬래시가 있는 경우에만 가능합니다.

print("\tchar=\"\\t\"")  # Prints `    char="\t"`.
print(r"\tchar=\"\\t\"") # Prints `\tchar=\"\\t\"`.

참고

일부 문자열은 원시 문자열 리터럴을 사용하여 표현할 수 없습니다. 문자열 끝에 홀수 개의 백슬래시를 사용할 수 없거나 문자열 내부에 이스케이프되지 않은 여는 따옴표를 사용할 수 없습니다. 그러나 실제로는 다른 인용 유형을 사용하거나 일반 문자열 리터럴과 연결을 사용할 수 있으므로 이는 중요하지 않습니다.

GDScript는 형식 문자열도 지원합니다.

들여쓰기

주석은 전체 스크립트, 선언, 명령문 또는 소스 코드의 위치에 대한 수정자 역할을 하는 GDScript의 특수 토큰입니다. 주석은 스크립트가 Godot 편집기와 GDScript 컴파일러에서 처리되는 방식에 영향을 미칠 수 있습니다.

모든 주석은 @ 문자로 시작하고 이름으로 지정됩니다. 각 주석에 대한 자세한 설명과 예는 :ref:`GDScript 클래스 참조 <class_@GDScript>`에서 확인할 수 있습니다.

예를 들어 이를 사용하여 값을 편집기로 내보낼 수 있습니다.

@export_range(1, 100, 1, "or_greater")
var ranged_var: int = 50

내보내기 속성에 대한 자세한 정보는:ref:GDScript 내보내기 <doc_gdscript_exports> 기사를 읽으세요.

필수 인수 유형과 호환되는 모든 상수 표현식은 주석 인수 값으로 전달될 수 있습니다.

const MAX_SPEED = 120.0

@export_range(0.0, 0.5 * MAX_SPEED)
var initial_speed: float = 0.25 * MAX_SPEED

주석은 한 줄에 하나씩 지정하거나 같은 줄에 모두 지정할 수 있습니다. 주석이 아닌 다음 문에 영향을 미칩니다. 주석에는 괄호 사이에 쉼표로 구분된 인수가 전송될 수 있습니다.

둘 다 동일합니다.

@annotation_a
@annotation_b
var variable

@annotation_a @annotation_b var variable

@onready 주석

노드를 사용할 때, 씬의 일부를 변수로 참조하는 것이 일반적입니다. 씬은 활성 씬 트리에 들어갈 때만 구성되기 때문에 하위 노드는 Node._ready() 호출이 있을 때만 가져올 수 있습니다.

var my_label


func _ready():
    my_label = get_node("MyLabel")

이 작업은 특히 노드와 외부 참조가 쌓이다 보면 번거로워질 수 있습니다. 이를 위해 GDScript에는 _ready()가 호출될 때까지 멤버 변수의 초기화를 지연시키는 onready 키워드가 있습니다. 위의 코드는 한 줄로 대체 가능합니다:

@onready var my_label = get_node("MyLabel")

경고

동일한 변수에 @onready@export 주석을 적용하면 예상한 대로 작동하지 않습니다. @onready 주석은 ``@export``가 적용된 후 기본값이 설정되도록 하고 이를 재정의합니다.

@export var a = "init_value_a"
@onready @export var b = "init_value_b"

func _init():
    prints(a, b) # init_value_a <null>

func _notification(what):
    if what == NOTIFICATION_SCENE_INSTANTIATED:
        prints(a, b) # exported_value_a exported_value_b

func _ready():
    prints(a, b) # exported_value_a init_value_b

따라서 ONREADY_WITH_EXPORT 경고가 생성되며 기본적으로 오류로 처리됩니다. 비활성화하거나 무시하지 않는 것이 좋습니다.

주석

#부터 줄 끝까지는 주석으로 간주되어 무시됩니다.

# This is a comment.

Godot 스크립트 편집기에서는 특정 댓글에 사용자의 주의를 끌기 위해 댓글 내에서 특수 키워드가 강조 표시됩니다.

  • 긴급 (빨간색으로 표시): ALERT, ATTENTION, CAUTION, CRITICAL, DANGER, SECURITY

  • 경고 (노란색으로 표시): BUG, DEPRECATED, FIXME, HACK, TASK, TBD, TODO, WARNING

  • 주의사항 (녹색으로 표시): INFO, NOTE, NOTICE, TEST, TESTING

이러한 키워드는 대소문자를 구분하므로 인식하려면 대문자로 작성해야 합니다.

# In the example below, "TODO" will appear in yellow by default.
# The `:` symbol after the keyword is not required, but it's often used.

# TODO: Add more items for the player to choose from.

강조 표시된 키워드 목록과 해당 색상은 편집기 설정의 텍스트 편집기 > 테마 > 댓글 마커 섹션에서 변경할 수 있습니다.

문서 설명*을 추가하려면 하나(``#``) 대신 두 개의 해시 기호(``##``)를 사용하세요. 이 설명은 스크립트 문서와 내보낸 변수의 검사기 설명에 표시됩니다. 문서 주석은 문서화 가능한 항목(예: 멤버 변수) 바로 *위 또는 파일 상단에 배치되어야 합니다. 전용 서식 옵션도 사용할 수 있습니다. 자세한 내용은 :ref:`doc_gdscript_documentation_comments`를 참조하세요.

## This comment will appear in the script documentation.
var value

## This comment will appear in the inspector tooltip, and in the documentation.
@export var exported_value

Godot 버전 관리

코드 영역은 스크립트 편집기가 *접을 수 있는 영역*으로 이해하는 특별한 유형의 주석입니다. 즉, 코드 영역 주석을 작성한 후 주석 왼쪽에 나타나는 화살표를 클릭하여 영역을 축소하거나 확장할 수 있습니다. 이 화살표는 표준 코드 접기와 구별되도록 보라색 사각형 안에 표시됩니다.

본 텍스트는 다음과 같습니다:

# Important: There must be *no* space between the `#` and `region` or `endregion`.

# Region without a description:
#region
...
#endregion

# Region with a description:
#region Some description that is displayed even when collapsed
...
#endregion

코드 영역을 빠르게 생성하려면 스크립트 편집기에서 여러 줄을 선택하고 선택 항목을 마우스 오른쪽 버튼으로 클릭한 다음 **만들기 코드 영역**을 선택합니다. 편집을 위해 지역 설명이 자동으로 선택됩니다.

다른 코드 영역 내에 코드 영역을 중첩할 수 있습니다.

어떻게 작동하는 지의 예제입니다:

# This comment is outside the code region. It will be visible when collapsed.
#region Terrain generation
# This comment is inside the code region. It won't be visible when collapsed.
func generate_lakes():
    pass

func generate_hills():
    pass
#endregion

#region Terrain population
func place_vegetation():
    pass

func place_roads():
    pass
#endregion

이는 큰 코드 덩어리를 이해하기 쉬운 섹션으로 구성하는 데 유용할 수 있습니다. 그러나 외부 편집기는 일반적으로 이 기능을 지원하지 않으므로 접는 코드 영역에 의존하지 않는 경우에도 코드를 쉽게 따라갈 수 있는지 확인하십시오.

참고

개별 기능과 들여쓰기 섹션(예: iffor)은 스크립트 편집기에서 항상 축소될 수 있습니다. 이는 단일 함수나 들여쓰기된 섹션을 포함하기 위해 코드 영역을 사용하지 말아야 함을 의미합니다. 그렇게 하면 많은 이점을 얻을 수 없기 때문입니다. 코드 영역은 여러 요소를 그룹화하는 데 사용될 때 가장 잘 작동합니다.

줄 계속

GDScript의 코드 줄은 백슬래시(\)를 사용하여 다음 줄에서 계속될 수 있습니다. 줄 끝에 하나를 추가하면 다음 줄의 코드가 백슬래시가 있는 것처럼 작동합니다. 예는 다음과 같습니다.

var a = 1 + \
2

다음과 같이 한 줄이 여러 번 이어질 수 있습니다.

var a = 1 + \
4 + \
10 + \
4

내장 유형

내장 유형은 스택에 할당됩니다. 그들은 값으로 전달됩니다. 즉, 복사본은 각 할당에서 또는 유형이 인수로 함수에 전달할 때 만들어진다는 뜻입니다. 예외는 참조로 전달되어 공유되는 Object, Array, Dictionary, 그리고 (PackedByteArray와 같은) 압축 배열입니다. 모든 배열, Dictionary, 그리고 일부 오브젝트(Node, Resource)에는 복사본을 만들 수 있는 duplicate() 메서드가 있습니다.

기초 내장 유형

GDScript의 변수에는 여러 내장 유형을 할당할 수 있습니다.

null

null은 정보를 가지지 않는 빈 데이터 타입으로 어떤 값도 할당할 수 없습니다.

Object에서 상속된 유형만 null 값을 가질 수 있습니다. 따라서 Object를 "nullable" 유형이라고 합니다. 변형 유형 <doc_variant_class>`은 항상 유효한 값을 가져야 하므로 ``null` 값을 가질 수 없습니다.

bool

"불리언"의 약자로, 오직 true 또는 false만 포함할 수 있습니다.

int

"정수"의 약자로, 전체 숫자(양수와 음수)를 저장합니다. 64비트 값으로 저장되며, C++에서 int64_t와 같습니다.

float

부동 소수점 값을 사용해 소수를 포함하는 실수를 저장합니다. C++의 "double"에 해당하는 64비트 값으로 저장됩니다. 참고: 현재 Vector2, Vector3, PoolRealArray와 같은 데이터 구조는 32비트 단정도 "float" 값을 저장합니다.

String

유니코드 형식의 문자열입니다. 문자열에는 다음과 같은 이스케이프 시퀀스가 포함될 수 있습니다.

String

각 이름의 인스턴스를 하나만 허용하는 변경할 수 없는 문자열입니다. 생성 속도가 느리고 멀티스레딩 시 잠금을 기다리게 될 수 있습니다. 그 대신 비교가 매우 빠르기 때문에 사전 키에 대한 좋은 후보가 됩니다.

NodePath

노드 또는 노드 속성에 대한 사전 구문 분석된 경로입니다. 문자열에 쉽게 할당하거나 문자열에서 할당할 수 있습니다. 노드를 얻기 위해 트리와 상호 작용하거나 :ref:`Tweens <class_Tween>`과 같은 속성에 영향을 미치는 데 유용합니다.

벡터 내장 타입

Vector2

2D 벡터 타입으로 x, y 필드를 가집니다. 배열로 접근할 수도 있습니다.

Vector2

Vector2와 동일하지만 구성 요소는 정수입니다. 2D 그리드에서 항목을 나타내는 데 유용합니다.

Rect2

2D 사각형 타입으로 두 개의 벡터 필드 position, size를 가집니다. 또한 position + size값인 end 필드를 가집니다.

Vector3

3D 벡터 타입으로 x, y, z 필드를 가집니다. 배열로 접근할 수도 있습니다.

Vector3

Vector3과 동일하지만 구성요소가 정수입니다. 3D 그리드에서 항목을 인덱싱하는 데 사용할 수 있습니다.

Transform2D

3x2 행렬(Matrix)로 2D 변형에 사용됩니다.

Plane

표준화된 형태의 3D 평면(Plane) 타입으로 normal 벡터와 d 스칼라 거리 필드를 가집니다.

Quat

사원수(Quaternion)는 3D 회전을 표현하기 위해 사용되는 데이터 타입입니다. 회전 값을 보간하는 용도로 사용됩니다.

AABB

축이 정렬된 경계 사각형(또는 3D 상자)로 두 개의 벡터 필드 position, size를 가집니다. 또한 position + size값인 end 필드를 가집니다.

Basis

3x3 행렬로 3D 회전과 크기 조절에 사용됩니다. 3개의 벡터 필드(x, y, z)를 가집니다. 3D 벡터의 배열로 접근할 수도 있습니다.

Transform2D

3D 변형으로 기본 필드 basis와 Vector3 필드 origin을 포함합니다.

엔진 내장 타입

Color

색상 데이터 유형으로 r, g, b, a 필드를 가집니다. 색조/채도/명도 값을 h, s, v로 접근할 수도 있습니다.

RID

리소스 ID (RID). 서버는 불투명한 데이터를 참조하기 위해 통용 RID를 사용합니다.

Object

내장 타입이 아닌 모든 것의 기본 클래스.

컨테이너 내장 타입

Array

다른 배열이나 딕셔너리를 포함한 임의 오브젝트 타입의 통용 시퀀스입니다 (아래 참조). 배열은 동적으로 크기를 조절할 수 있습니다. 배열은 인덱스 0부터 시작하여 매깁니다. 음수 인덱스는 배열의 끝부터 셉니다.

var arr = []
arr = [1, 2, 3]
var b = arr[1] # This is 2.
var c = arr[arr.size() - 1] # This is 3.
var d = arr[-1] # Same as the previous line, but shorter.
arr[0] = "Hi!" # Replacing value 1 with "Hi!".
arr.append(4) # Array is now ["Hi!", 2, 3, 4].

타입 있는 배열

Godot also features support for typed arrays. 쓰기 작업에서 Godot는 요소 값이 지정된 유형과 일치하는지 확인하므로 배열에 잘못된 값이 포함될 수 없습니다. GDScript 정적 분석기는 형식화된 배열을 고려하지만 front()back()``와 같은 배열 메서드에는 여전히 ``Variant 반환 형식이 있습니다.

형식화된 배열에는 Array[Type] 구문이 있습니다. 여기서 Type``는 모든 ``Variant 유형, 기본 클래스, 사용자 클래스 또는 열거형일 수 있습니다. 중첩된 배열 유형(예: Array[Array[int]])은 지원되지 않습니다.

var a: Array[int]
var b: Array[Node]
var c: Array[MyClass]
var d: Array[MyEnum]
var e: Array[Variant]

``Array``와 ``Array[Variant]``는 같은 것입니다.

참고

배열은 참조로 전달되므로 배열 요소 유형은 런타임 시 변수가 참조하는 메모리 내 구조의 속성이기도 합니다. 변수의 정적 유형은 참조할 수 있는 구조를 제한합니다. 따라서 유형이 필수 유형의 하위 유형인 경우에도 다른 요소 유형으로 배열을 할당할 수 없습니다.

만들어진 람다를 호출하려면 call() 메서드를 사용할 수 있습니다:

var a: Array[Node2D] = [Node2D.new()]

# (OK) You can add the value to the array because `Node2D` extends `Node`.
var b: Array[Node] = [a[0]]

# (Error) You cannot assign an `Array[Node2D]` to an `Array[Node]` variable.
b = a

# (OK) But you can use the `assign()` method instead. Unlike the `=` operator,
# the `assign()` method copies the contents of the array, not the reference.
b.assign(a)

사용자 편의성과 기존 코드와의 호환성을 위해 Array``(``Array[Variant]) 유형에 대한 유일한 예외가 발생했습니다. 그러나 형식화되지 않은 배열에 대한 작업은 안전하지 않은 것으로 간주됩니다.

지역 변수(Local Variables)

PackedArray는 일반적으로 동일한 유형의 형식화된 배열(예: PackedInt64Array 대 Array[int])에 비해 반복 및 수정 속도가 더 빠르며 메모리를 덜 소비합니다. 최악의 경우에는 형식이 지정되지 않은 배열만큼 빠를 것으로 예상됩니다. 반대로, 압축되지 않은 배열(유형 지정 여부와 상관없이)에는 PackedArray에 부족한 :ref:`Array.map <class_Array_method_map>`과 같은 추가 편의 메서드가 있습니다. 사용 가능한 메서드에 대한 자세한 내용은 :ref:`class reference <class_PackedFloat32Array>`를 참조하세요. 유형이 지정된 배열은 일반적으로 유형이 지정되지 않은 배열보다 반복하고 수정하는 속도가 더 빠릅니다.

모든 어레이는 충분히 커지면 메모리 조각화를 일으킬 수 있지만, 메모리 사용량과 성능(반복 및 수정 속도)이 중요하고 저장하는 데이터 유형이 Packed 어레이 유형 중 하나와 호환되는 경우 이를 사용하면 성능이 향상될 수 있습니다. 그러나 그러한 우려가 없다면(예: 배열 크기가 수만 개의 요소에 도달하지 않는 경우) 일반 배열이나 형식화된 배열을 사용하는 것이 더 도움이 될 수 있습니다. 이는 코드를 더 쉽게 작성하고 유지 관리할 수 있는 편리한 방법을 제공하기 때문입니다(데이터에 이러한 작업이 많이 필요한 경우 잠재적으로 더 빠를 수 있음). 저장할 데이터가 알려진 유형(자신이 정의한 클래스 포함)인 경우 유형이 지정된 배열을 사용하는 것이 좋습니다. 유형이 지정되지 않은 배열에 비해 반복 및 수정 시 더 나은 성능을 얻을 수 있기 때문입니다.

  • PoolByteArray: 바이트의 배열 (0부터 255까지의 정수).

  • PoolIntArray: 정수의 배열.

  • PoolIntArray: 정수의 배열.

  • PoolRealArray: 실수의 배열.

  • PoolRealArray: 실수의 배열.

  • PoolStringArray: 문자열의 배열.

  • PoolVector2Array: Vector2 오브젝트의 배열.

  • PoolVector3Array: Vector3 오브젝트의 배열.

  • PoolVector2Array: Vector2 오브젝트의 배열.

  • PoolColorArray: Color 오브젝트의 배열.

Dictionary

고유 키로 참조되는 값들을 가지는 연관 컨테이너입니다.

var d = {4: 5, "A key": "A value", 28: [1, 2, 3]}
d["Hi!"] = 0
d = {
    22: "value",
    "some_key": 2,
    "other_key": [2, 3, 4],
    "more_key": "Hello"
}

Lua 스타일의 테이블 구문도 지원됩니다. Lua 스타일은 : 대신 =을 사용하고 문자열 키를 표시하기 위해 따옴표를 사용하지 않습니다(쓸 문자가 약간 줄어듭니다). 그러나 이 형식으로 작성된 키 이름은 (다른 모든 GDScript 식별자와 마찬가지로) 숫자로 시작할 수 없습니다.

var d = {
    test22 = "value",
    some_key = 2,
    other_key = [2, 3, 4],
    more_key = "Hello"
}

존재하는 딕셔너리에 키를 추가하려면, 기존 키와 같은 방식으로 접근한 뒤 할당해야 합니다:

var d = {} # Create an empty Dictionary.
d.waiting = 14 # Add String "waiting" as a key and assign the value 14 to it.
d[4] = "hello" # Add integer 4 as a key and assign the String "hello" as its value.
d["Godot"] = 3.01 # Add String "Godot" as a key and assign the value 3.01 to it.

var test = 4
# Prints "hello" by indexing the dictionary with a dynamic key.
# This is not the same as `d.test`. The bracket syntax equivalent to
# `d.test` is `d["test"]`.
print(d[test])

참고

대괄호 구문은 딕셔너리 뿐만 아니라 모든 Object의 속성에 접근하는 데 사용할 수 있습니다. 존재하지 않는 속성을 인덱싱하려고 할 때 스크립트 오류가 발생한다는 점에 유의하세요. 이를 방지하려면 Object.get()Object.set() 메서드를 대신 사용하세요.

딕셔너리

Godot 4.4에는 입력된 사전에 대한 지원이 추가되었습니다. 쓰기 작업에서 Godot는 요소 키와 값이 지정된 유형과 일치하는지 확인하므로 사전에는 유효하지 않은 키나 값이 포함될 수 없습니다. GDScript 정적 분석기는 유형이 지정된 사전을 고려합니다. 그러나 값을 반환하는 사전 메서드에는 여전히 Variant 반환 유형이 있습니다.

형식화된 사전에는 Dictionary[KeyType, ValueType] 구문이 있습니다. 여기서 KeyTypeValueType``는 모든 ``Variant 유형, 기본 또는 사용자 클래스 또는 열거형일 수 있습니다. 키와 값 유형을 모두 반드시 지정해야 하지만 Variant``를 사용하여 하나를 유형화하지 않을 있습니다. 중첩된 유형의 컬렉션(예: ``Dictionary[String, Dictionary[String, int]])은 지원되지 않습니다.

var a: Dictionary[String, int]
var b: Dictionary[String, Node]
var c: Dictionary[Vector2i, MyClass]
var d: Dictionary[MyEnum, float]
# String keys, values can be any type.
var e: Dictionary[String, Variant]
# Keys can be any type, boolean values.
var f: Dictionary[Variant, bool]

``Dictionary``와 ``Dictionary[Variant, Variant]``는 같은 것입니다.

int

시그널는 객체가 그것을 듣고 싶어하는 사람들에게 내보낼 수 있는 메시지입니다. 시그널 유형은 이미터를 통과시키는 데 사용할 수 있습니다.

시그널는 실제 객체에서 가져와 사용하는 것이 더 좋습니다. $Button.button_up.

Plane

함수를 값으로 전달하는 데 유용한 개체와 함수가 포함되어 있습니다(예: 시그널에 연결할 때).

멤버로 메서드를 가져오면 콜러블이 반환됩니다. var x = $Sprite2D.rotate``는 ``x``의 값을 개체로 ``$Sprite2D, 메서드로 ``rotate``를 사용하여 호출 가능 항목으로 설정합니다.

call 메서드(x.call(PI))를 사용하여 호출할 수 있습니다.

변수

변수는 클래스 멤버로 존재할 수도 있고 함수에 지역적으로 존재할 수도 있습니다. 이들은 var 키워드로 생성되며 초기화할 때 값을 할당받을 수도 있습니다.

var a # Data type is 'null' by default.
var b = 5
var c = 3.8
var d = b + c # Variables are always initialized in direct order (see below).

변수는 타입을 지정할 수도 있습니다. 타입을 지정하면 항상 같은 타입을 가지도록 강제되며, 호환되지 않는 값을 할당하려고 하면 오류가 발생합니다.

타입은 변수 선언 시 변수 이름 뒤에 :(콜론) 기호를 사용해 지정하고 그 뒤에 타입을 지정합니다.

var my_vector2: Vector2
var my_node: Node = Sprite2D.new()

변수가 선언과 동시에 초기화되면 타입을 유추할 수 있으므로 타입 이름을 생략할 수 있습니다:

var my_vector2 := Vector2() # 'my_vector2' is of type 'Vector2'.
var my_node := Sprite2D.new() # 'my_node' is of type 'Sprite2D'.

타입 유추는 할당된 값에 정의된 타입이 있는 경우에만 가능하며, 그렇지 않으면 오류가 발생합니다.

올바른 타입은 다음과 같습니다:

  • 내장 유형 (Array, Vector2, int, String 등).

  • 엔진 클래스 (Node, Resource, Reference 등).

  • 스크립트 리소스가 포함된 상수 이름(const MyScript = preload("res://my_script.gd")를 선언한 경우에 MyScript가 여기에 속합니다).

  • 같은 스크립트의 스코프 안에 있는 다른 클래스들(같은 스코프에서 class InnerClass 안에 class NestedClass를 선언한 경우 InnerClass.NestedClass가 여기에 속합니다).

  • class_name 키워드로 선언된 스크립트 클래스.

  • 싱글톤로 등록된 자동 로드.

참고

``Variant``는 유효한 유형 사양이지만 실제 유형은 아닙니다. 이는 설정된 유형이 없다는 의미일 뿐이며 정적 유형이 전혀 없는 것과 동일합니다. 따라서 ``Variant``에 대해서는 실수일 가능성이 높으므로 기본적으로 추론이 허용되지 않습니다.

프로젝트 설정에서 이 확인을 변경하여 이 확인을 끄거나 경고만 표시하도록 할 수 있습니다. 자세한 내용은 :ref:`doc_gdscript_warning_system`를 참조하세요.

다음 예제에서:

적 씬은 다음 노드들을 사용할 것입니다:

  1. 변수의 정적 유형에 따라 변수는 null``(유형이 지정되지 않은 변수 개체)이거나 해당 유형의 기본값(``int``의 경우 ``0, bool``의 경우 ``false 등)을 갖습니다.

  2. 지정된 값은 스크립트에 있는 변수의 순서대로 위에서 아래로 할당됩니다.

    • (Node 파생 클래스에만 해당) @onready 주석이 변수에 적용되면 초기화가 5단계로 연기됩니다.

  3. 정의된 경우 _init() 메서드가 호출됩니다.

  4. 장면과 리소스를 인스턴스화할 때 내보낸 값이 할당됩니다.

  5. (Node 파생 클래스에만 해당) @onready 변수가 초기화됩니다.

  6. (Node 파생 클래스에만 해당) 정의되면 _ready() 메서드가 호출됩니다.

경고

함수 호출을 포함하여 복잡한 표현식을 변수 이니셜라이저로 지정할 수 있습니다. 변수가 올바른 순서로 초기화되었는지 확인하세요. 그렇지 않으면 값을 덮어쓸 수 있습니다. 예를 들면:

var a: int = proxy("a", 1)
var b: int = proxy("b", 2)
var _data: Dictionary = {}

func proxy(key: String, value: int):
    _data[key] = value
    print(_data)
    return value

func _init() -> void:
    print(_data)

이렇게 프린트 될 것입니다:

{ "a": 1 }
{ "a": 1, "b": 2 }
{  }

이 문제를 해결하려면 _data 변수 정의를 a 정의 위로 이동하거나 빈 사전 할당(= {})을 제거하세요.

인스턴스 편집하기

클래스 멤버 변수는 정적으로 선언될 수 있습니다.

static var a

정적 변수는 인스턴스가 아닌 클래스에 속합니다. 즉, 정적 변수는 일반 멤버 변수와 달리 여러 인스턴스 간에 값을 공유합니다.

클래스 내부에서는 정적 및 비정적 함수 모두에서 정적 변수에 액세스할 수 있습니다. 클래스 외부에서 클래스나 인스턴스를 사용하여 정적 변수에 액세스할 수 있습니다. 두 번째 인스턴스는 읽기가 어렵기 때문에 권장되지 않습니다.

참고

@export@onready 주석은 정적 변수에 적용할 수 없습니다. 지역 변수는 정적일 수 없습니다.

다음 예에서는 max_id``라는 정적 변수를 사용하여 ``Person 클래스를 정의합니다. _init() 함수에서 max_id``를 증가시킵니다. 이를 통해 게임에서 ``Person 인스턴스 수를 쉽게 추적할 수 있습니다.

# person.gd
class_name Person

static var max_id = 0

var id
var name

func _init(p_name):
    max_id += 1
    id = max_id
    name = p_name

이 코드에서는 Person 클래스의 두 인스턴스를 생성하고 변수가 정적이며 모든 인스턴스에 액세스할 수 있으므로 클래스와 모든 인스턴스가 동일한 max_id 값을 갖는지 확인합니다.

# test.gd
extends Node

func _ready():
    var person1 = Person.new("John Doe")
    var person2 = Person.new("Jane Doe")

    print(person1.id) # 1
    print(person2.id) # 2

    print(Person.max_id)  # 2
    print(person1.max_id) # 2
    print(person2.max_id) # 2

정적 변수에는 유형 힌트, setter 및 getter가 있을 수 있습니다.

static var balance: int = 0

static var debt: int:
    get:
        return -balance
    set(value):
        balance = -value

기본 클래스 정적 변수는 하위 클래스를 통해 액세스할 수도 있습니다.

class A:
    static var x = 1

class B extends A:
    pass

func _ready():
    prints(A.x, B.x) # 1 1
    A.x = 2
    prints(A.x, B.x) # 2 2
    B.x = 3
    prints(A.x, B.x) # 3 3

참고

도구 스크립트에서 정적 변수를 참조할 때 정적 변수를 포함하는 다른 스크립트도 반드시 도구 스크립트여야 합니다. 자세한 내용은 :ref:`편집기에서 코드 실행 <doc_running_code_in_the_editor_important_information>`을 참조하세요.

@static_unload 주석

GDScript 클래스는 리소스이므로 스크립트에 정적 변수가 있으면 해당 클래스의 인스턴스가 더 이상 없고 다른 참조가 남아 있지 않은 경우에도 언로드되지 않습니다. 이는 정적 변수가 대량의 데이터를 저장하거나 장면과 같은 다른 프로젝트 리소스에 대한 참조를 보유하는 경우 중요할 수 있습니다. 이 데이터를 수동으로 정리해야 합니다. 또는 정적 변수가 중요한 데이터를 저장하지 않고 재설정할 수 있는 경우 @static_unload 주석을 사용해야 합니다.

경고

현재 버그로 인해 @static_unload 주석을 사용하더라도 스크립트는 해제되지 않습니다.

@static_unload``는 전체 스크립트(내부 클래스 포함)에 적용되며 스크립트의 위, ``class_nameextends 앞에 배치되어야 합니다.

@static_unload
class_name MyNode
extends Node

Static functions`Static constructor`_도 참조하세요.

캐스트하기

타입이 지정된 변수에는 호환 가능한 타입의 값을 할당해야 합니다. 값을 특정 타입으로 강제 변환해야 하는 경우, 특히 객체 타입의 경우 캐스팅 연산자 as를 사용할 수 있습니다.

오브젝트 유형 간 캐스팅은 값이 캐스팅할 유형과 같거나 캐스팅할 유형의 하위 유형인 경우 캐스팅하면 동일한 오브젝트가 생성됩니다.

var my_node2D: Node2D
my_node2D = $Sprite2D as Node2D # Works since Sprite2D is a subtype of Node2D.

값이 하위 유형이 아닌 경우 캐스팅 연산 결과는 null 값입니다.

var my_node2D: Node2D
my_node2D = $Button as Node2D # Results in 'null' since a Button is not a subtype of Node2D.

내장 타입의 경우 가능하다면 강제로 타입을 변환하지만, 불가능하다면 오류를 발생합니다.

var my_int: int
my_int = "123" as int # The string can be converted to int.
my_int = Vector2() as int # A Vector2 can't be converted to int, this will cause an error.

캐스팅은 씬 트리와 상호작용할 때 더 나은 타입 안전한 변수를 만드는 데 유용합니다:

# Will infer the variable to be of type Sprite2D.
var my_sprite := $Character as Sprite2D

# Will fail if $AnimPlayer is not an AnimationPlayer, even if it has the method 'play()'.
($AnimPlayer as AnimationPlayer).play("walk")

상수

상수는 게임이 실행 중일 때 변경할 수 없는 값입니다. 상수 값은 컴파일 시간에 정해져야 합니다. const 키워드를 사용하면 상수 값에 이름을 지정할 수 있습니다. 선언된 상수에 값을 할당하려고 하면 오류가 발생합니다.

값이 변경되지 않는다면 상수를 사용하는 것이 좋습니다.

const A = 5
const B = Vector2(20, 20)
const C = 10 + 20 # Constant expression.
const D = Vector2(20, 30).x # Constant expression: 20.
const E = [1, 2, 3, 4][0] # Constant expression: 1.
const F = sin(20) # 'sin()' can be used in constant expressions.
const G = x + 20 # Invalid; this is not a constant expression!
const H = A + 20 # Constant expression: 25 (`A` is a constant).

상수의 타입은 할당되는 값에서 유추할 수 있지만 명시적으로 지정할 수도 있습니다:

const A: int = 5
const B: Vector2 = Vector2()

호환되지 않는 타입의 값을 할당하면 오류가 발생합니다.

함수 내부에 상수를 생성할 수도 있는데, 이는 로컬 매직 값의 이름을 지정하는 데 유용합니다.

열거형

열거형은 기초적으로 상수의 축약형으로, 연속적인 정수를 일부 상수에 할당할 때 꽤 유용합니다.

enum {TILE_BRICK, TILE_FLOOR, TILE_SPIKE, TILE_TELEPORT}

# Is the same as:
const TILE_BRICK = 0
const TILE_FLOOR = 1
const TILE_SPIKE = 2
const TILE_TELEPORT = 3

If you pass a name to the enum, it will put all the keys inside a constant Dictionary of that name. This means all constant methods of a dictionary can also be used with a named enum. This only works for GDScript enums, not for enums from built-in classes.

중요

Godot 3.1부터는, 이름있는 열거형의 키는 전역 상수로 등록되지 않습니다. 키에 접근하려면 열거형의 이름이 앞에 있어야합니다(이름.KEY). 아래의 예제를 참고하세요.

enum State {STATE_IDLE, STATE_JUMP = 5, STATE_SHOOT}

# Is the same as:
const State = {STATE_IDLE = 0, STATE_JUMP = 5, STATE_SHOOT = 6}
# Access values with State.STATE_IDLE, etc.

func _ready():
    # Access values with Name.KEY, prints '5'
    print(State.STATE_JUMP)
    # Use dictionary methods:
    # prints '["STATE_IDLE", "STATE_JUMP", "STATE_SHOOT"]'
    print(State.keys())
    # prints '{ "STATE_IDLE": 0, "STATE_JUMP": 5, "STATE_SHOOT": 6 }'
    print(State)
    # prints '[0, 5, 6]'
    print(State.values())

열거형의 키에 값을 할당하지 않으면 이전 값에 1을 더한 값이 할당되고, 열거형의 첫 번째 항목인 경우 ``0``가 할당됩니다. 동일한 값을 가진 여러 키가 허용됩니다.

함수

함수는 항상 class에 속합니다. 변수 조회의 범위 우선순위는: 로컬 → 클래스 멤버 → 전역입니다. self 변수는 항상 사용할 수 있고 클래스 멤버(self 참조)에 접근하기 위한 옵션으로 제공되지만 항상 필수적이지는 않습니다(Python과 달리 함수의 첫 번째 인수로 보내서는 됩니다).

func my_function(a, b):
    print(a)
    print(b)
    return a + b  # Return is optional; without it 'null' is returned.

함수는 언제든지 반환(return)할 수 있습니다. 기본 반환 값은 null입니다.

기본적으로 모든 함수 매개변수가 필수입니다. 기본값을 할당하여 마지막에 하나 이상의 매개변수를 선택적으로 만들 수 있습니다.

# Since the last two parameters are optional, all these calls are valid:
# - my_function(1)
# - my_function(1, 20)
# - my_function(1, 20, 100)
func my_function(a_required, b_optional = 10, c_optional = 42):
    print(a_required)
    print(b_optional)
    print(c_optional)

함수에 코드 한 줄만 포함되어 있으면 한 줄에 작성할 수 있습니다.

func square(a): return a * a

func hello_world(): print("Hello World")

func empty_function(): pass

그리고 함수는 인수와 반환 값의 타입을 지정할 수 있습니다. 인수의 타입은 변수와 비슷한 방식으로 추가할 수 있습니다:

func my_function(a: int, b: String):
    pass

함수 인수가 기본 값을 가진다면 타입을 유추할 수 있습니다:

func my_function(int_arg := 42, String_arg := "string"):
    pass

함수의 반환 타입은 화살표 토큰 (->)을 사용헤 인수 목록 뒤에 지정할 수 있습니다:

func my_int_function() -> int:
    return 0

반환 타입이 있는 함수는 반드시 그에 맞는 값을 반환해야 합니다. 타입을 void로 설정하면 함수는 아무 것도 반환하면 안 됩니다. Void 함수는 return 키워드로 함수에서 일찍 반환할 수 있지만, 값을 반환하면 안 됩니다.

func void_function() -> void:
    return # Can't return a value.

참고

void가 아닌 함수는 항상 값을 반환해야 하므로 코드에 분기 문이 있는 경우(예: if/else 구조) 가능한 모든 경로에서 반환해야 합니다. 예를 들어, if 블록 안에 return이 있지만 그 이후에는 없는 경우 블록이 실행되지 않으면 함수가 반환할 올바른 값을 가지지 않기 때문에 편집기에서 오류가 발생합니다.

함수 참조하기

함수는 Callable 개체 측면에서 일급 값입니다. 함수를 호출하지 않고 이름으로 참조하면 적절한 호출 가능 항목이 자동으로 생성됩니다. 함수를 인수로 전달하는 데 사용할 수 있습니다.

func map(arr: Array, function: Callable) -> Array:
    var result = []
    for item in arr:
        result.push_back(function.call(item))
    return result

func add1(value: int) -> int:
    return value + 1;

func _ready() -> void:
    var my_array = [1, 2, 3]
    var plus_one = map(my_array, add1)
    print(plus_one) # Prints `[2, 3, 4]`.

참고

콜러블은 반드시 call() 메서드를 사용하여 호출되어야 합니다. () 연산자를 직접 사용할 수 없습니다. 이 동작은 직접 함수 호출 시 성능 문제를 방지하기 위해 구현되었습니다.

랜덤 함수

Lambda 함수를 사용하면 클래스에 속하지 않는 함수를 선언할 수 있습니다. 대신 Callable 개체가 생성되어 변수에 직접 할당됩니다. 이는 클래스 범위를 오염시키지 않고 전달할 콜러블을 만드는 데 유용할 수 있습니다.

var lambda = func (x):
    print(x)

만들어진 람다를 호출하려면 call() 메서드를 사용할 수 있습니다:

lambda.call(42) # Prints `42`.

디버깅 목적으로 Lambda 함수의 이름을 지정할 수 있습니다(이름은 디버거에 표시됨).

var lambda = func my_lambda(x):
    print(x)

일반 함수와 동일한 방식으로 람다 함수에 대한 유형 힌트를 지정할 수 있습니다.

var lambda := func (x: int) -> void:
    print(x)

람다 함수에서 값을 반환하려면 명시적인 ``return``가 필요합니다(``return``를 생략할 수 없음).

var lambda = func (x): return x ** 2
print(lambda.call(2)) # Prints `4`.

람다 함수는 로컬 환경을 캡처합니다:

var x = 42
var lambda = func ():
    print(x) # Prints `42`.
lambda.call()

경고

지역 변수는 람다가 생성될 때 한 번 값으로 캡처됩니다. 따라서 외부 함수에서 다시 할당되면 람다에서 업데이트되지 않습니다.

var x = 42
var lambda = func (): print(x)
lambda.call() # Prints `42`.
x = "Hello"
lambda.call() # Prints `42`.

또한 람다는 외부 지역 변수를 재할당할 수 없습니다. 람다를 종료한 후에는 람다 캡처가 암시적으로 변수를 숨기기 때문에 변수는 변경되지 않습니다.

var x = 42
var lambda = func ():
    print(x) # Prints `42`.
    x = "Hello" # Produces the `CONFUSABLE_CAPTURE_REASSIGNMENT` warning.
    print(x) # Prints `Hello`.
lambda.call()
print(x) # Prints `42`.

그러나 참조별 전달 데이터 유형(배열, 사전 및 객체)을 사용하는 경우 변수를 다시 할당할 때까지 콘텐츠 변경 사항이 공유됩니다.

var a = []
var lambda = func ():
    a.append(1)
    print(a) # Prints `[1]`.
    a = [2] # Produces the `CONFUSABLE_CAPTURE_REASSIGNMENT` warning.
    print(a) # Prints `[2]`.
lambda.call()
print(a) # Prints `[1]`.

정적 함수

함수를 정적으로 선언할 수 있습니다. 함수가 정적이면 인스턴스 멤버 변수나 self로 접근할 수 없습니다. 주로 도우미 함수 라이브러리를 만드는 데 유용합니다:

static func sum2(a, b):
    return a + b

Lambda 함수는 정적으로 선언할 수 없습니다.

Static variables`Static constructor`_도 참조하세요.

정적 함수

가변 함수는 가변 개수의 인수를 취할 수 있는 함수입니다. Godot 4.5부터 GDScript는 가변 함수를 지원합니다. 가변 함수를 선언하려면 초과된 모든 인수를 배열로 수집하는 *rest 매개변수*를 사용해야 합니다.

func my_func(a, b = 0, ...args):
    prints(a, b, args)

func _ready():
    my_func(1)             # 1 0 []
    my_func(1, 2)          # 1 2 []
    my_func(1, 2, 3)       # 1 2 [3]
    my_func(1, 2, 3, 4)    # 1 2 [3, 4]
    my_func(1, 2, 3, 4, 5) # 1 2 [3, 4, 5]

함수는 최대 하나의 나머지 매개변수를 가질 수 있으며 이는 매개변수 목록의 마지막 매개변수여야 합니다. 나머지 매개변수는 기본값을 가질 수 없습니다. 정적 및 람다 함수도 가변적일 수 있습니다.

정적 타이핑은 가변 함수에도 작동합니다. 그러나 형식화된 배열은 현재 나머지 매개변수의 정적 형식으로 지원되지 않습니다.

# You cannot specify `...values: Array[int]`.
func sum(...values: Array) -> int:
    var result := 0
    for value in values:
        assert(value is int)
        result += value
    return result

참고

Rest 매개변수를 사용하여 함수를 가변형으로 선언할 수 있지만, 일부 언어(JavaScript, PHP)에 존재하는 *확산 구문*을 사용하여 함수를 호출할 때 매개변수 압축 해제는 현재 GDScript에서 지원되지 않습니다. 그러나 ``callv()``를 사용하여 인수 배열로 함수를 호출할 수 있습니다.

func test_func(...args):
    #log_data(...args) # This won't work.
    log_data.callv(args) # This will work.

func log_data(...values):
    # You should use `callv()` if you want to pass `values` as the argument list,
    # rather than passing the array as the first argument.
    prints.callv(values)
    # You can use array concatenation to prepend/append the argument list.
    write_data.callv(["user://log.txt"] + values)

func write_data(path, ...values):
    # ...

추상 함수

`Abstract classes and methods`_를 참조하세요.

명령문(Statement)과 제어 흐름(Control Flow)

명령문은 표준으로 할당, 함수 호출, 제어 흐름 구조 등이 될 수 있습니다. 명령문 구분 기호인 ;의 사용은 자유입니다.

표현식

표현식은 순서대로 배열된 연산자와 피연산자의 시퀀스입니다. 표현식 자체도 명령문이 될 수 있지만 다른 표현식에는 부작용이 없으므로 호출만 명령문으로 사용하는 것이 합리적입니다.

표현식은 유효한 대상에 할당할 수 있는 값을 반환합니다. 일부 연산자의 피연산자는 다른 표현식이 될 수 있습니다. 할당은 표현식이 아니므로 값을 반환하지 않습니다.

어떻게 작동하는 지의 예제입니다:

2 + 2 # Binary operation.
-5 # Unary operation.
"okay" if x > 4 else "not okay" # Ternary operation.
x # Identifier representing variable or constant.
x.a # Attribute access.
x[4] # Subscript access.
x > 2 or x < 5 # Comparisons and logic operators.
x == y + 2 # Equality test.
do_something() # Function call.
[1, 2, 3] # Array definition.
{A = 1, B = 2} # Dictionary definition.
preload("res://icon.svg") # Preload builtin function.
self # Reference to current instance.

식별자, 속성 및 아래 첨자는 유효한 할당 대상입니다. 과제의 왼쪽에는 다른 표현식을 사용할 수 없습니다.

self

``self``는 현재 인스턴스를 참조하는 데 사용할 수 있으며 현재 스크립트에서 사용 가능한 기호를 직접 참조하는 것과 동일한 경우가 많습니다. 그러나 ``self``를 사용하면 동적으로 정의된 속성, 메서드 및 기타 이름에 액세스할 수도 있습니다(즉, 현재 클래스의 하위 유형에 존재할 것으로 예상되거나 _set() 및/또는 :ref:`_get() <class_Object_private_method__get>`을 사용하여 제공됨).

extends Node

func _ready():
    # Compile time error, as `my_var` is not defined in the current class or its ancestors.
    print(my_var)
    # Checked at runtime, thus may work for dynamic properties or descendant classes.
    print(self.my_var)

    # Compile time error, as `my_func()` is not defined in the current class or its ancestors.
    my_func()
    # Checked at runtime, thus may work for descendant classes.
    self.my_func()

경고

기본 클래스에 있는 하위 클래스의 멤버에 액세스하는 것은 종종 나쁜 습관으로 간주됩니다. 이는 특정 코드 부분의 책임 영역을 모호하게 만들어 게임 부분 간의 전반적인 관계를 추론하기 어렵게 만들기 때문입니다. 게다가, 부모 클래스가 자신의 자손에 대해 어느 정도 기대를 갖고 있다는 사실을 잊어버릴 수도 있습니다.

if/else/elif

간단한 조건은 if/else/elif 구문을 사용해 만들 수 있습니다. 조건문 주변에 괄호를 씌워도 되지만 필수는 아닙니다. 탭 기반 들여쓰기의 특성을 감안하면 else/if 대신 elif를 사용해서 들여쓰기 수준을 유지할 수 있습니다.

if (expression):
    statement(s)
elif (expression):
    statement(s)
else:
    statement(s)

간단한 명령문은 조건처럼 같은 줄에 적을 수 있습니다:

if 1 + 1 == 2: return 2 + 2
else:
    var x = 3 + 3
    return x

때로는 불리언 표현식을 기반으로 초기 값을 다르게 할당해야 하는 경우가 있습니다. 이 경우에는 삼항 표현식을 쓰면 됩니다:

var x = (value) if (expression) else (value)
y += 3 if y < 10 else -1

삼항 if 표현식은 2개 이상의 분기를 처리하기 위해 중첩될 수 있습니다. 삼항 if 표현식을 중첩할 때 가독성을 유지하기 위해 전체 표현식을 여러 줄로 감싸는 것이 좋습니다:

var count = 0

var fruit = (
        "apple" if count == 2
        else "pear" if count == 1
        else "banana" if count == 0
        else "orange"
)
print(fruit)  # banana

# Alternative syntax with backslashes instead of parentheses (for multi-line expressions).
# Less lines required, but harder to refactor.
var fruit_alt = \
        "apple" if count == 2 \
        else "pear" if count == 1 \
        else "banana" if count == 0 \
        else "orange"
print(fruit_alt)  # banana

값이 무언가에 포함되어 있는지 확인하고 싶을 수도 있습니다. 이를 수행하기 위해 in 연산자와 결합된 if 문을 사용할 수 있습니다.

# Check if a letter is in a string.
var text = "abc"
if 'b' in text: print("The string contains b")

# Check if a variable is contained within a node.
if "varName" in get_parent(): print("varName is defined in parent!")

while

간단한 루프는 while 구문으로 만들 수 있습니다. 루프는 break를 사용해서 끊거나 continue를 사용해서 계속할 수 있습니다:

while (expression):
    statement(s)

for

배열이나 테이블과 같은 범위의 반복에는 for 루프가 사용됩니다. 배열을 반복할 때 현재 배열 요소는 루프 변수에 저장됩니다. 딕셔너리를 반복할 때 key는 루프 변수에 저장됩니다.

for x in [5, 7, 11]:
    statement # Loop iterates 3 times with 'x' as 5, then 7 and finally 11.

var names = ["John", "Marta", "Samantha", "Jimmy"]
for name: String in names: # Typed loop variable.
    print(name) # Prints name's content.

var dict = {"a": 0, "b": 1, "c": 2}
for i in dict:
    print(dict[i]) # Prints 0, then 1, then 2.

for i in range(3):
    statement # Similar to [0, 1, 2] but does not allocate an array.

for i in range(1, 3):
    statement # Similar to [1, 2] but does not allocate an array.

for i in range(2, 8, 2):
    statement # Similar to [2, 4, 6] but does not allocate an array.

for i in range(8, 2, -2):
    statement # Similar to [8, 6, 4] but does not allocate an array.

for c in "Hello":
    print(c) # Iterate through all characters in a String, print every letter on new line.

for i in 3:
    statement # Similar to range(3).

for i in 2.2:
    statement # Similar to range(ceil(2.2)).

반복되는 동안 배열에 값을 할당하려면 ``for i in array.size()``를 사용하는 것이 가장 좋습니다.

for i in array.size():
    array[i] = "Hello World"

루프 변수는 for 루프에 대해 로컬이며 변수에 할당해도 배열의 값이 변경되지 않습니다. 참조로 전달된 객체(예: 노드)는 루프 변수에 대한 메서드를 호출하여 계속 조작할 수 있습니다.

for string in string_array:
    string = "Hello World" # This has no effect

for node in node_array:
    node.add_to_group("Cool_Group") # This has an effect

match

match 명령문은 프로그램의 실행을 분기하는 데 사용됩니다. 다른 많은 언어에서 볼 수 있는 switch 명령문과 유사하지만 몇 가지 추가 기능을 제공합니다.

경고

match``는 ``== 연산자보다 유형이 더 엄격합니다. 예를 들어 1``는 ``1.0``와 일치하지 **않습니다**. 유일한 예외는 ``StringStringName 일치입니다. 예를 들어 문자열 ``"hello"``는 StringName ``&"hello"``와 동일한 것으로 간주됩니다.

기초 문법:

match <test value>:
    <pattern(s)>:
        <block>
    <pattern(s)> when <pattern guard>:
        <block>
    <...>

switch 명령문에 익숙한 사람들을 위한 집중 강좌:

  1. switchmatch로 바꾸세요.

  2. case를 제거하세요.

  3. case를 제거하세요.

  4. default를 하나의 밑줄로 변경하세요.

제어 흐름

패턴은 위에서 아래로 매치됩니다. 패턴이 첫 번째로 일치하는 블록이 실행됩니다. 그 후, match 문 아래에서 계속 실행됩니다. continue를 사용해 현재 블록에서 실행을 중지하고 그 아래 패턴에서 추가로 패턴 일치 여부를 확인할 수 있습니다.

참고

3.x에서 지원되는 match``의 특별한 ``continue 동작은 Godot 4.0에서 제거되었습니다.

다음 패턴 유형을 사용할 수 있습니다.

  • 리터럴 패턴

    `literal <Literals>`_과 일치합니다.

    match x:
        1:
            print("We are number one!")
        2:
            print("Two are better than one!")
        "test":
            print("Oh snap! It's a string!")
    
  • 표현식 패턴

    상수 표현식, 식별자 또는 속성 액세스(A.B)와 일치합니다.

    match typeof(x):
        TYPE_FLOAT:
            print("float")
        TYPE_STRING:
            print("text")
        TYPE_ARRAY:
            print("array")
    
  • 와일드카드 패턴

    이 패턴은 모든 것에 매치됩니다. 하나의 밑줄로 쓸 수 있습니다.

    다른 언어의 switch 명령문의 default와 같은 의미로 쓰입니다:

    match x:
        1:
            print("It's one!")
        2:
            print("It's one times two!")
        _:
            print("It's not 1 or 2. I don't care to be honest.")
    
  • 바인딩 패턴

    바인딩 패턴은 새 변수를 도입합니다. 와일드카드 패턴과 마찬가지로 모든 것에 매치됩니다. 그리고 값에 이름을 부여합니다. 이는 특히 배열 패턴과 딕셔너리 패턴에 유용합니다:

    match x:
        1:
            print("It's one!")
        2:
            print("It's one times two!")
        var new_var:
            print("It's not 1 or 2, it's ", new_var)
    
  • 배열 패턴

    배열을 비교합니다. 배열 패턴의 각 단일 요소도 패턴이므로, 패턴을 중첩할 수 있습니다.

    배열의 길이가 패턴과 같은지 테스트하고, 같지 않다면 패턴이 일치하지 않습니다.

    개방형 배열: 배열의 마지막 서브패턴을 ..으로 만들어서 패턴보다 배열이 더 커질 수 있습니다.

    각 서브패턴은 쉼표로 구분해야 합니다.

    match x:
        []:
            print("Empty array")
        [1, 3, "test", null]:
            print("Very specific array")
        [var start, _, "test"]:
            print("First element is ", start, ", and the last is \"test\"")
        [42, ..]:
            print("Open ended array")
    
  • 딕셔너리 패턴

    배열 패턴과 같은 방식으로 작동합니다. 모든 키는 일정한 패턴이어야 합니다.

    딕셔너리의 길이가 패턴과 같은지 테스트하고, 같지 않다면 패턴이 일치하지 않습니다.

    개방형 딕셔너리: 딕셔너리의 마지막 서브패턴을 ..으로 만들어서 패턴보다 딕셔너리가 더 커질 수 있습니다.

    모든 서브패턴은 쉼표로 구분되어야 합니다.

    값을 지정하지 않으면, 키의 존재 여부만 확인됩니다.

    값 패턴과 키 패턴은 :로 분리됩니다.

    match x:
        {}:
            print("Empty dict")
        {"name": "Dennis"}:
            print("The name is Dennis")
        {"name": "Dennis", "age": var age}:
            print("Dennis is ", age, " years old.")
        {"name", "age"}:
            print("Has a name and an age, but it's not Dennis :(")
        {"key": "godotisawesome", ..}:
            print("I only checked for one entry and ignored the rest")
    
  • 다중 패턴

    여러 패턴을 쉼표로 구분해서 지정할 수 있습니다. 이 패턴들 사이에서 바인딩은 허용되지 않습니다.

    match x:
        1, 2, 3:
            print("It's 1 - 3")
        "Sword", "Splash potion", "Fist":
            print("Yep, you've taken damage")
    

패턴 가드

*패턴 가드*는 패턴 목록을 따르는 선택적 조건이며 match 분기를 선택하기 전에 추가 검사를 수행할 수 있도록 해줍니다. 패턴과 달리 패턴 가드는 임의의 표현이 될 수 있습니다.

match``당 하나의 분기만 실행할 있습니다. 브랜치를 선택하면 나머지는 확인되지 않습니다. 여러 분기에 동일한 패턴을 사용하거나 너무 일반적인 패턴이 있는 분기를 선택하지 않으려면 ``when 키워드를 사용하여 패턴 목록 뒤에 패턴 가드를 지정할 수 있습니다.

match point:
    [0, 0]:
        print("Origin")
    [_, 0]:
        print("Point on X-axis")
    [0, _]:
        print("Point on Y-axis")
    [var x, var y] when y == x:
        print("Point on line y = x")
    [var x, var y] when y == -x:
        print("Point on line y = -x")
    [var x, var y]:
        print("Point (%s, %s)" % [x, y])
  • 현재 분기에 일치하는 패턴이 없으면 패턴 가드가 평가되지 않고 **않**되며 다음 분기의 패턴이 확인됩니다.

  • 일치하는 패턴이 발견되면 패턴 가드가 평가됩니다.

    • true이면 분기 본문이 실행되고 ``match``가 종료됩니다.

    • 값을 지정하지 않으면, 키의 존재 여부만 확인됩니다.

클래스

기본적으로 모든 스크립트 파일은 이름 없는 클래스입니다. 이 경우 상대 경로나 절대 경로를 사용한 파일 경로를 통해서만 참조할 수 있습니다. 예를 들어 스크립트 파일의 이름을 characrer.gd로 지은 경우 다음과 같이 참조합니다:

# Inherit from 'character.gd'.

extends "res://path/to/character.gd"

# Load character.gd and create a new node instance from it.

var Character = load("res://path/to/character.gd")
var character_node = Character.new()

스크립트를 클래스로 등록하기

대신, Godot 편집기에서 클래스 이름을 지정해서 새로운 타입으로 등록할 수 있습니다. 이를 위해 class_name 키워드를 사용합니다. 추가로 쉼표 뒤에 이미지 경로를 추가해서 이미지를 클래스 아이콘으로 사용할 수 있습니다. 그러면 클래스가 편집기에 새 아이콘과 함께 나타납니다:

# item.gd

@icon("res://interface/icons/item.png")
class_name Item
extends Node
../../../_images/class_name_editor_register_example.png

사용자 정의 노드 아이콘으로 사용되는 SVG 이미지에는 Editor > Scale With Editor ScaleEditor > Convert Icons With Editor Theme :ref:`import options <doc_importing_images_editor_import_options>`이 활성화되어 있어야 합니다. 이는 아이콘이 Godot의 자체 아이콘과 동일한 색상 팔레트로 디자인된 경우 아이콘이 편집기의 규모 및 테마 설정을 따를 수 있도록 합니다.

클래스 파일 예제입니다:

# Saved as a file named 'character.gd'.

class_name Character


var health = 5


func print_health():
    print(health)


func print_this_script_three_times():
    print(get_script())
    print(ResourceLoader.load("res://character.gd"))
    print(Character)

``extends``도 사용하려면 두 가지를 모두 같은 줄에 유지하면 됩니다.

class_name MyNode extends Node

명명된 클래스는 전역적으로 등록됩니다. 즉, load 또는 ``preload``가 필요 없이 다른 스크립트에서 사용할 수 있게 됩니다.

var player

func _ready():
    player = Character.new()

참고

Godot의 클래스 구문은 간결합니다. 멤버 변수나 함수만 포함할 수 있습니다. 정적 함수를 사용할 수 있지만 정적 멤버 변수는 사용할 수 없습니다. 같은 방식으로, 엔진은 인스턴스를 생성할 때마다 변수를 초기화하며 여기에는 배열과 딕셔너리가 포함됩니다. 사용자가 알지 못하는 사이에 별도의 스레드에서 스크립트를 초기화할 수 있기 때문에 스레드 안전 정신이 적용되었습니다.

경고

Godot 편집기는 '만들기 New 노드' 또는 '만들기 New 씬' 대화 상자 창에서 접두사 "Editor"로 시작하는 이름으로 이러한 사용자 정의 클래스를 숨깁니다. 클래스는 클래스 이름을 통해 런타임에 인스턴스화할 수 있지만 Godot 편집기에서 사용하는 내장 편집기 노드와 함께 편집기 창에 의해 자동으로 숨겨집니다.

클래스와 노드

Godot 4.5부터 @abstract 주석을 사용하여 추상 클래스와 메소드를 정의할 수 있습니다.

추상 클래스는 직접 인스턴스화할 수 없는 클래스입니다. 대신, 다른 클래스에서 상속되도록 되어 있습니다. 추상 클래스를 인스턴스화하려고 하면 오류가 발생합니다.

추상 메서드는 구현이 없는 메서드입니다. 따라서 함수 헤더 뒤에는 줄 바꿈이나 세미콜론이 필요합니다. 이는 재정의 시 메서드 서명이 호환되어야 하므로 상속 클래스가 준수해야 하는 계약을 정의합니다.

상속 클래스는 모든 추상 메서드에 대한 구현을 제공하거나 상속 클래스를 추상으로 표시해야 합니다. 클래스에 하나 이상의 추상 메서드(자체 메서드 또는 구현되지 않은 상속 메서드)가 있는 경우 해당 클래스도 abstract로 표시되어야 합니다. 그러나 그 반대는 성립하지 않습니다. 추상 클래스에는 추상 메서드가 없어도 됩니다.

메소드를 선택사항으로 선언하여 재정의하려면 추상이 아닌 메소드를 사용하고 기본 구현을 제공해야 합니다.

예를 들어 draw()``라는 추상 메서드를 정의하는 ``Shape``라는 추상 클래스가 있을 있습니다. 그런 다음 ``draw() 메서드를 자체 방식으로 구현하는 Circle``Square``와 같은 하위 클래스를 만들 수 있습니다. 이를 통해 추상 클래스 자체에서 모든 세부 사항을 구현하지 않고도 모든 모양에 대한 공통 *인터페이스*를 정의할 수 있습니다.

@abstract class Shape:
    @abstract func draw()

# This is a concrete (non-abstract) subclass of Shape.
# You **must** implement all abstract methods in concrete classes.
class Circle extends Shape:
    func draw():
        print("Drawing a circle.")

class Square extends Shape:
    func draw():
        print("Drawing a square.")

내부 클래스와 ``class_name``를 사용하여 생성된 클래스는 모두 추상 클래스일 수 있습니다. 이 예제에서는 두 개의 추상 클래스를 만듭니다. 그 중 하나는 다른 추상 클래스의 하위 클래스입니다.

@abstract
class_name AbstractClass
extends Node

@abstract class AbstractInnerClass:
    func _ready():
        pass

# This is an example of a concrete subclass of `AbstractInnerClass`.
# This class can be instantiated using `AbstractClass.ConcreteInnerClass.new()`
# in other scripts, even though it's part of an abstract `class_name` script.
class ConcreteInnerClass extends AbstractInnerClass:
    func _ready():
        print("Concrete class ready.")

경고

추상 클래스는 인스턴스화할 수 없으므로 노드에 추상 클래스를 연결할 수 없습니다. 그렇게 하려고 하면 씬을 실행할 때 엔진이 오류를 인쇄합니다.

Cannot set object script. Script '<path to script>' should not be abstract.

이름이 지정되지 않은 클래스는 추상으로 정의할 수도 있습니다. @abstract 주석은 extends 앞에 와야 합니다.

@abstract
extends Node

상속

(파일로 저장한) 클래스는 여기서 상속될 수 있습니다:

  • 전역 클래스.

  • 다른 클래스 파일.

  • 다른 클래스 파일의 내부 클래스.

다중 상속은 허용되지 않습니다.

extends 키워드를 사용해 상속합니다:

# Inherit/extend a globally available class.
extends SomeClass

# Inherit/extend a named class file.
extends "somefile.gd"

# Inherit/extend an inner class in another file.
extends "somefile.gd".SomeInnerClass

참고

상속이 명시적으로 정의되지 않은 경우 클래스는 기본적으로 :ref:`class_RefCounted`를 상속합니다.

주어진 인스턴스가 주어진 클래스로부터 상속받았는지 확인하려면, is 키워드를 사용할 수 있습니다:

# Cache the enemy class.
const Enemy = preload("enemy.gd")

# [...]

# Use 'is' to check inheritance.
if entity is Enemy:
    entity.apply_damage()

부모 클래스(즉, 현재 클래스에서 extend한 클래스)에서 함수를 호출하려면 함수 이름 앞에 .을 추가하세요:

super(args)

이는 확장하는 클래스의 함수가 부모 클래스에서 같은 이름을 가진 함수를 대체하기 때문에 특히 유용합니다. 여전히 부모 클래스의 함수를 호출하고 싶다면 앞에 .를 붙일 수 있습니다(다른 언어의 super 키워드같이요):

func some_func(x):
    super(x) # Calls the same function on the super class.

슈퍼 클래스에서 다른 함수를 호출해야 하는 경우 속성 연산자를 사용하여 함수 이름을 지정할 수 있습니다.

func overriding():
    return 0 # This overrides the method in the base class.

func dont_override():
    return super.overriding() # This calls the method as defined in the base class.

경고

일반적인 오해 중 하나는 get_class(), queue_free() 등과 같은 비가상 엔진 방법을 재정의하려고 한다는 것입니다. 이는 기술적인 이유로 지원되지 않습니다.

Godot 3에서는 GDScript에서 엔진 메소드를 섀도우*할 수 있으며 GDScript에서 이 메소드를 호출하면 작동합니다. 그러나 일부 이벤트에서 엔진 내부에서 메소드가 호출되면 엔진은 코드를 실행하지 **않습니다*.

Godot 4에서는 GDScript가 기본 메소드 호출을 최적화하므로 섀도잉도 항상 작동하지 않을 수 있습니다. 따라서 기본적으로 오류로 처리되는 NATIVE_METHOD_OVERRIDE 경고를 추가했습니다. 경고를 비활성화하거나 무시하지 않는 것이 좋습니다.

이는 _ready(), _process() 및 기타(문서에서 virtual 한정자로 표시되고 이름이 밑줄로 시작됨)와 같은 가상 메서드에는 적용되지 않습니다. 이러한 메소드는 특히 엔진 동작을 사용자 정의하기 위한 것이며 GDScript에서 재정의될 수 있습니다. 시그널 및 알림도 이러한 목적에 유용할 수 있습니다.

클래스 생성자

클래스 인스턴스화 시 호출되는 클래스 생성자의 이름은 _init``입니다. 기본 클래스 생성자를 호출하려면 ``super 구문을 사용할 수도 있습니다. 모든 클래스에는 항상 호출되는 암시적 생성자가 있습니다(클래스 변수의 기본값을 정의함). ``super``는 명시적 생성자를 호출하는 데 사용됩니다.

func _init(arg):
   super("some_default", arg) # Call the custom base constructor.

예제를 통해서 더 쉽게 설명해 보겠습니다. 다음 시나리오를 생각해보세요:

# state.gd (inherited class).
var entity = null
var message = null


func _init(e = null):
    entity = e


func enter(m):
    message = m


# idle.gd (inheriting class).
extends "state.gd"


func _init(e = null, m = null):
    super(e)
    # Do something with 'e'.
    message = m

유의해야 할 몇 가지 사항이 있습니다:

  1. 상속하는 클래스(State.gd)가 인수(이 경우 e)를 가지는 _init 생성자를 정의하는 경우 상속받는 클래스(Idle.gd)는 반드시 _init을 정의해야 하고, State.gd에서 _init로 적절한 매개변수를 전달해야 합니다.

  2. idle.gd는 부모 클래스 State.gd와 다른 개수의 인수를 가질 수 있습니다.

  3. 위의 예제에서 State.gd 생성자로 전달된 eIdle.gd로 전달된 e와 같습니다.

  4. Idle.gd_init 생성자가 0개의 인수를 가지고 아무것도 하지 않더라도 부모 클래스 State.gd에 값을 전달해야 합니다. 이는 변수뿐만 아니라 기본 생성자에서도 리터럴을 전달할 수 있다는 사실을 알려줍니다. 예시:

# idle.gd

func _init():
    super(5)

정적 생성자

정적 생성자는 정적 변수가 초기화된 후 클래스가 로드될 때 자동으로 호출되는 정적 함수 ``_static_init``입니다.

static var my_static_var = 1

static func _static_init():
    my_static_var = 2

정적 생성자는 인수를 사용할 수 없으며 값을 반환해서는 안 됩니다.

내부 클래스

클래스 파일은 내부 클래스를 가질 수 있습니다. 내부 클래스는 class 키워드로 정의합니다. 내부 클래스는 ClassName.new() 함수로 인스턴스화 될 수 있습니다.

# Inside a class file.

# An inner class in this class file.
class SomeInnerClass:
    var a = 5


    func print_value_of_a():
        print(a)


# This is the constructor of the class file's main class.
func _init():
    var c = SomeInnerClass.new()
    c.print_value_of_a()

리소스로 취급되는 클래스

파일로 저장된 클래스는 리소스로 취급됩니다. 다른 클래스에서 접근하려면 반드시 디스크에서 불러와야 합니다. 불러오려면 loadpreload 함수를 사용할 수 있습니다 (아래 참조). 불러온 클래스 리소스를 인스턴스화 하려면 클래스 오브젝트에 new 함수를 호출해야 합니다:

# Load the class resource when calling load().
var MyClass = load("myclass.gd")

# Preload the class only once at compile time.
const MyClass = preload("myclass.gd")


func _init():
    var a = MyClass.new()
    a.some_function()

내보내기

참고

내보내기에 관한 서술은 GDScript 내보낸 속성로 옮겨졌습니다.

속성(세터 및 게터)

어떤 이유에서든 클래스 멤버 변수가 언제 변경되는지 아는 것은 자주 유용합니다. 어떤 방식으로든 접근을 캡슐화하는 것이 바람직할 수도 있습니다.

이를 위해 GDScript는 변수 선언 후에 setget 키워드를 사용하여 속성을 정의하는 특수 구문을 제공합니다. 그런 다음 변수에 액세스하거나 할당할 때 실행될 코드 블록을 정의할 수 있습니다.

예시:

var milliseconds: int = 0
var seconds: int:
    get:
        return milliseconds / 1000
    set(value):
        milliseconds = value * 1000

참고

이전 Godot 버전의 setget``와 달리, ``setget 메소드는 동일한 클래스 내에서 액세스할 때에도 (self. 접두사가 있거나 없이) 항상 호출됩니다(아래 설명 제외). 이렇게 하면 동작이 일관되게 됩니다. 값에 직접 액세스해야 하는 경우 직접 액세스를 위해 다른 변수를 사용하고 속성 코드에서 해당 이름을 사용하도록 합니다.

외부 파일

또한 변수 선언에서 코드를 분할하거나 여러 속성에서 코드를 재사용해야 하는 경우 기존 클래스 함수를 사용하는 또 다른 표기법이 있습니다(그러나 setter/getter가 호출되는 속성을 구분할 수는 없습니다).

var my_prop:
    get = get_my_prop, set = set_my_prop

적 씬은 다음 노드들을 사용할 것입니다:

var my_prop: get = get_my_prop, set = set_my_prop

setter와 getter는 동일한 표기법을 사용해야 하며, 동일한 변수에 대해 스타일을 혼합하는 것은 허용되지 않습니다.

참고

인라인 setter 및 getter에 대한 유형 힌트를 지정할 수 없습니다. 이는 상용구를 줄이기 위해 의도적으로 수행됩니다. 변수가 입력되면 setter의 인수는 자동으로 동일한 유형이 되며 getter의 반환 값은 이와 일치해야 합니다. 분리된 setter/getter 함수는 유형 힌트를 가질 수 있으며 유형은 변수 유형과 일치하거나 더 넓은 유형이어야 합니다.

setter/getter가 호출되지 않는 경우

변수가 초기화되면 초기화 값이 변수에 직접 기록됩니다. @onready 주석이 변수에 적용되는지 여부를 포함합니다.

변수 이름을 사용하여 자체 setter 내에서 설정하거나 자체 getter 내에서 가져오면 기본 멤버에 직접 액세스하므로 무한 재귀가 생성되지 않으며 다른 변수를 명시적으로 선언할 필요가 없습니다.

signal changed(new_value)
var warns_when_changed = "some value":
    get:
        return warns_when_changed
    set(value):
        changed.emit(value)
        warns_when_changed = value

최종 결과물입니다:

var my_prop: set = set_my_prop

func set_my_prop(value):
    my_prop = value # No infinite recursion.

경고

예외는 setter/getter에서 호출되는 다른 함수로 전파되지 않습니다. 예를 들어 다음 코드는 **무한 재귀**를 발생시킵니다.

var my_prop:
    set(value):
        set_my_prop(value)

func set_my_prop(value):
    my_prop = value # Infinite recursion, since `set_my_prop()` is not the setter.

툴 모드

기본적으로 스크립트는 편집기 내에서 실행되지 않으며, 오직 내보낸 속성만 편집기에서 변경할 수 있습니다. 어떤 경우에는 (편집기가 게임 코드를 실행하지 않거나 수동으로 실행하지 않는 한) 편집기 내에서 실행하는 것이 바람직합니다. 이를 위해 @tool 키워드가 존재하며, 파일 맨 위에 위치해야 합니다:

@tool
extends Button

func _ready():
    print("Hello")

자세한 정보는 편집기에서 코드 실행하기를 참조하세요.

경고

Tool 스크립트에서 queue_free() 또는 free()로 노드를 해제할 때 (특히 해제할 노드가 스크립트 소유자 자체일 때) 주의하세요. Tool 스크립트는 편집기에서 코드를 실행하기 때문에 잘못 사용하면 편집기가 충돌할 수 있습니다.

메모리 관리

Godot는 가비지 수집기 대신에 더 이상 사용되지 않거나 순전히 수동 관리가 필요한 특정 인스턴스를 해제하기 위해 참조 계산을 구현합니다. RefCounted 클래스의 모든 인스턴스(또는 class_Resource`와 같이 이를 상속하는 모든 클래스)는 더 이상 사용되지 않으면 자동으로 해제됩니다. :ref:`class_RefCounted`가 아닌 클래스(예: :ref:`class_Node 또는 기본 Object 유형)의 인스턴스의 경우 free()``(또는 노드의 경우 ``queue_free())로 삭제될 때까지 메모리에 남아 있습니다.

참고

class_Node`가 ``free()` 또는 ``queue_free()``를 통해 삭제되면 해당 자식 노드도 모두 재귀적으로 삭제됩니다.

해제할 수 없는 참조 순환을 방지하기 위해 약한 참조 생성을 위한 WeakRef 함수가 제공됩니다. 이를 통해 RefCounted 해제를 방지하지 않고 객체에 액세스할 수 있습니다. 예는 다음과 같습니다.

extends Node

var my_file_ref

func _ready():
    var f = FileAccess.open("user://example_file.json", FileAccess.READ)
    my_file_ref = weakref(f)
    # the FileAccess class inherits RefCounted, so it will be freed when not in use

    # the WeakRef will not prevent f from being freed when other_node is finished
    other_node.use_file(f)

func _this_is_called_later():
    var my_file = my_file_ref.get_ref()
    if my_file:
        my_file.close()

또는, 참조를 사용하지 않을 때 is_instance_valid(instance)를 사용해서 오브젝트가 해제되었는지 확인할 수 있습니다.

시그널

시그널은 한 오브젝트에서 반응할 수 있는 다른 오브젝트로 메시지를 방출하는 도구입니다. 클래스에 대한 커스텀 시그널을 생성하려면 signal 키워드를 사용하세요.

extends Node


# A signal named health_depleted.
signal health_depleted

참고

시그널은 콜백 메커니즘입니다. 그리고 일반적인 프로그래밍 패턴인 옵저버(Observer)의 역할도 합니다. 자세한 정보는 Game Programming Patterns의 전자책, Observer tutorial을 읽으세요.

커스텀 시그널도 Button, class_RigidBody 같은 노드에 내장된 시그널을 연결하는 방법과 같은 방식으로 메서드에 연결할 수 있습니다.

아래 예제에서 Character 노드의 health_depleted 시그널을 Game 노드로 연결합니다. Character 노드가 시그널을 방출하면 Game 노드의 _on_Character_health_depleted가 호출됩니다:

# game.gd

func _ready():
    var character_node = get_node('Character')
    character_node.health_depleted.connect(_on_character_health_depleted)


func _on_character_health_depleted():
    get_tree().reload_current_scene()

하나의 시그널에 원하는 만큼 많은 인수를 함께 방출할 수 있습니다.

위가 유용한 예입니다. 화면의 체력 바가 애니메이션이 적용되며 체력 변화에 반응하기를 원하지만 유저 인터페이스를 씬 트리의 플레이어와 분리하려고 한다고 가정해 보겠습니다.

Character.gd 스크립트에서 health_changed 시그널을 정의하고 Object.emit_signal()로 방출합니다. 그런 다음 씬 트리의 맨 위에 있는 Game 노드에서 Object.connect() 메서드를 사용해 시그널을 Lifebar에 연결합니다:

# character.gd

...
signal health_changed


func take_damage(amount):
    var old_health = health
    health -= amount

    # We emit the health_changed signal every time the
    # character takes damage.
    health_changed.emit(old_health, health)
...
# lifebar.gd

# Here, we define a function to use as a callback when the
# character's health_changed signal is emitted.

...
func _on_Character_health_changed(old_value, new_value):
    if old_value > new_value:
        progress_bar.modulate = Color.RED
    else:
        progress_bar.modulate = Color.GREEN

    # Imagine that `animate` is a user-defined function that animates the
    # bar filling up or emptying itself.
    progress_bar.animate(old_value, new_value)
...

Game 노드에서는 CharacterLifebar 노드를 가져와서 시그널을 방출하는 캐릭터를 수신기인 Lifebar 노드에 연결합니다.

# game.gd

func _ready():
    var character_node = get_node('Character')
    var lifebar_node = get_node('UserInterface/Lifebar')

    character_node.health_changed.connect(lifebar_node._on_Character_health_changed)

이를 통해 LifebarCharacter 노드에 연결하지 않고도 체력 변화에 반응할 수 있습니다.

시그널을 정의한 뒤에 개별적으로 괄호 안에 인수 이름을 적을 수 있습니다:

# Defining a signal that forwards two arguments.
signal health_changed(old_value, new_value)

These arguments show up in the editor's Signals dock, and Godot can use them to generate callback functions for you. However, you can still emit any number of arguments when you emit signals; it's up to you to emit the correct values.

../../../_images/gdscript_basics_signals_node_tab_1.png

방출된 시그널이 여러분이 필요한 데이터에 대한 접근을 제공하지 않는다면 이 배열의 값들로 연결에 여분의 상수 정보를 추가할 수 있습니다.

시그널가 내보내지면 콜백 메서드는 시그널에서 제공하는 값 외에 바인딩된 값을 받습니다.

위의 예를 바탕으로 Player1이 데미지를 22 입었습니다.와 같이 각 캐릭터가 입은 데미지 로그를 화면에 표시하고 싶다고 가정해 보겠습니다. health_changed 시그널은 피해를 입은 캐릭터의 이름을 알려주지 않습니다. 따라서 게임 내 콘솔에 시그널을 연결할 때 바인딩 배열 인수에 캐릭터 이름을 추가할 수 있습니다:

# game.gd

func _ready():
    var character_node = get_node('Character')
    var battle_log_node = get_node('UserInterface/BattleLog')

    character_node.health_changed.connect(battle_log_node._on_Character_health_changed.bind(character_node.name))

BattleLog 노드는 바인딩 배열의 각 요소를 추가 인수로 받습니다:

# battle_log.gd

func _on_Character_health_changed(old_value, new_value, character_name):
    if not new_value <= old_value:
        return

    var damage = old_value - new_value
    label.text += character_name + " took " + str(damage) + " damage."

시그널이나 코루틴을 기다리기

await 키워드를 사용하면 실행을 계속하기 전에 시그널가 방출될 때까지 기다리는 coroutines <https://en.wikipedia.org/wiki/Coroutine>`_을 생성할 수 있습니다. 시그널와 함께 ``await` 키워드를 사용하거나 코루틴이기도 한 함수에 대한 호출은 즉시 호출자에게 제어권을 반환합니다. 시그널가 방출되면(또는 호출된 코루틴이 완료되면) 중지된 지점부터 실행을 재개합니다.

예를 들어, 사용자가 버튼을 누를 때까지 실행을 중지하려면 다음과 같이 하면 됩니다.

func wait_confirmation():
    print("Prompting user")
    await $Button.button_up # Waits for the button_up signal from Button node.
    print("User confirmed")
    return true

이 경우 ``wait_confirmation``는 코루틴이 되며, 이는 호출자도 이를 기다려야 함을 의미합니다.

func request_confirmation():
    print("Will ask the user")
    var confirmed = await wait_confirmation()
    if confirmed:
        print("User confirmed")
    else:
        print("User cancelled")

await 없이 코루틴의 반환 값을 요청하면 오류가 발생합니다.

func wrong():
    var confirmed = wait_confirmation() # Will give an error.

그러나 결과에 의존하지 않는 경우 비동기식으로 호출하면 실행이 중단되지 않고 현재 함수가 코루틴으로 만들어지지 않습니다.

func okay():
    wait_confirmation()
    print("This will be printed immediately, before the user press the button.")

시그널나 코루틴이 아닌 표현식과 함께 wait를 사용하면 값이 즉시 반환되고 함수는 호출자에게 제어권을 돌려주지 않습니다.

func no_wait():
    var x = await get_five()
    print("This doesn't make this function a coroutine.")

func get_five():
    return 5

이는 또한 코루틴이 아닌 함수에서 시그널를 반환하면 호출자가 시그널를 기다리게 된다는 것을 의미합니다.

func get_signal():
    return $Button.button_up

func wait_button():
    await get_signal()
    print("Button was pressed")

참고

이전 Godot 버전의 ``yield``와 달리 함수 상태 객체를 얻을 수 없습니다. 이는 유형 안전성을 보장하기 위해 수행됩니다. 이러한 유형 안전성이 적용되면 함수는 실제로 런타임 중에 함수 상태 개체를 반환하지만 ``int``를 반환한다고 말할 수 없습니다.

You can store the arguments passed to the signal's parameters. If there is only one parameter, the awaited value will have the same type as the argument:

func toggled():
    var signal_args = await $Button.toggled
    assert(typeof(signal_args) == TYPE_BOOL)

If there is more than one parameter, the awaited value will be of type Array:

func request_completed():
    var signal_args = await $HTTPRequest.request_completed
    assert(typeof(signal_args) == TYPE_ARRAY)

Otherwise, the awaited value will be null:

func button_up():
    var signal_args = await $Button.button_up
    assert(signal_args == null)

Assert 키워드

assert 키워드는 디버그 빌드에서 조건을 확인하는 데 사용할 수 있습니다. assert는 디버그 빌드가 아니면 무시됩니다. 즉, 인수로 전달된 표현식은 릴리스 모드로 내보낸 프로젝트에서 평가되지 않습니다. 이 때문에 assert에는 부작용이 있는 표현식이 포함되어서는 안 됩니다. 그렇지 않으면 스크립트는 프로젝트가 디버그 빌드인지 여부에 따라 매우 다르게 동작할 것입니다.

# Check that 'i' is 0. If 'i' is not 0, an assertion error will occur.
assert(i == 0)

편집기에서 프로젝트를 실행할 때 assert 오류가 발생하면 프로젝트가 일시 정지됩니다.

어설션이 실패할 경우 표시할 사용자 지정 오류 메시지를 선택적으로 전달할 수 있습니다.

assert(enemy_power < 256, "Enemy is too powerful!")