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.

Godot 인터페이스

기능을 위해 다른 오브젝트에 의존하는 스크립트가 필요한 경우가 종종 있습니다. 이 과정에는 2부분이 있습니다:

  1. 아마도 기능을 갖는 오브젝트에 대한 참조를 얻기.

  2. 오브젝트에서 데이터 또는 논리에 접근하기.

이 튜토리얼의 나머지 부분에서는 이 모든 작업을 하는 다양한 방법을 간략하게 설명합니다.

오브젝트 참조 얻기

모든 Object에 있어, 오브젝트를 참조하는 가장 기초적인 방법은 획득한 다른 인스턴스로부터 존재하는 오브젝트로 참조를 가져오는 것입니다.

var obj = node.object # Property access.
var obj = node.get_object() # Method access.

RefCounted 오브젝트에 대해서도 같은 원리가 적용됩니다. 사용자들은 종종 NodeResource를 이런 방식으로 접근하지만, 대체 조치도 사용 가능합니다.

속성이나 메서드 접근 대신 로드 접근으로 리소스에 접근할 수 있습니다.

# If you need an "export const var" (which doesn't exist), use a conditional
# setter for a tool script that checks if it's executing in the editor.
# The `@tool` annotation must be placed at the top of the script.
@tool

# Load resource during scene load.
var preres = preload(path)
# Load resource when program reaches statement.
var res = load(path)

# Note that users load scenes and scripts, by convention, with PascalCase
# names (like typenames), often into constants.
const MyScene = preload("my_scene.tscn") # Static load
const MyScript = preload("my_script.gd")

# This type's value varies, i.e. it is a variable, so it uses snake_case.
@export var script_type: Script

# Must configure from the editor, defaults to null.
@export var const_script: Script:
    set(value):
        if Engine.is_editor_hint():
            const_script = value

# Warn users if the value hasn't been set.
func _get_configuration_warnings():
    if not const_script:
        return ["Must initialize property 'const_script'."]

    return []

다음을 참고하세요:

  1. 언어가 리소스를 불러올 수 있는 방법은 여러 가지가 있습니다.

  2. 오브젝트가 데이터에 접근하는 방법을 설계할 때, 리소스를 참조로 전달할 수도 있다는 점을 잊지 마세요.

  3. 리소스를 불러올 때 내부적으로 엔진이 관리하는 캐싱된 리소스 인스턴스를 가져온다는 점을 명심하세요. 새 오브젝트를 생성하려면 이미 존재하면 참조를 복제하거나 new()를 사용해 처음부터 인스턴스화해야 합니다.

노드에도 마찬가지로 대체 접근 방법이 있습니다: 씬트리입니다.

extends Node

# Slow.
func dynamic_lookup_with_dynamic_nodepath():
    print(get_node("Child"))

# Faster. GDScript only.
func dynamic_lookup_with_cached_nodepath():
    print($Child)

# Fastest. Doesn't break if node moves later.
# Note that `@onready` annotation is GDScript-only.
# Other languages must do...
#     var child
#     func _ready():
#         child = get_node("Child")
@onready var child = $Child
func lookup_and_cache_for_future_access():
    print(child)

# Fastest. Doesn't break if node is moved in the Scene tree dock.
# Node must be selected in the inspector as it's an exported property.
@export var child: Node
func lookup_and_cache_for_future_access():
    print(child)

# Delegate reference assignment to an external source.
# Con: need to perform a validation check.
# Pro: node makes no requirements of its external structure.
#      'prop' can come from anywhere.
var prop
func call_me_after_prop_is_initialized_by_parent():
    # Validate prop in one of three ways.

    # Fail with no notification.
    if not prop:
        return

    # Fail with an error message.
    if not prop:
        printerr("'prop' wasn't initialized")
        return

    # Fail and terminate.
    # NOTE: Scripts run from a release export template don't run `assert`s.
    assert(prop, "'prop' wasn't initialized")

# Use an autoload.
# Dangerous for typical nodes, but useful for true singleton nodes
# that manage their own data and don't interfere with other objects.
func reference_a_global_autoloaded_variable():
    print(globals)
    print(globals.prop)
    print(globals.my_getter())

오브젝트에서 데이터나 로직에 접근하기

Godot의 스크립팅 API는 덕 타이핑되어 있습니다. 따라서 스크립트가 동작을 수행할 때 Godot는 동작의 지원을 타입을 통해 확인하는 것이 아닌 오브젝트가 개별 메서드를 구현하는지를 확인합니다.

예를 들어, CanvasItem 클래스는 visible 속성을 갖습니다. 스크립팅 API에게 노출된 모든 속성은 이름으로 바인딩된 setter와 getter 쌍과 같습니다. CanvasItem.visible에 접근을 시도하면 Godot는 다음과 같은 검사를 순서대로 수행합니다:

  • 오브젝트에 스크립트가 붙어있다면 스크립트를 통해 속성의 값을 지정하려 시도합니다. 따라서 스크립트가 속성의 setter 메서드를 오버라이드해서 부모 오브젝트의 속성을 오버라이드할 수 있도록 합니다.

  • 만약 스크립트에게 그 속성이 없다면 스크립트는 ClassDB에 HashMap lookup을 수행해 CanvasItem 클래스와 이를 상속하는 모든 우형에서 "visible" 속성을 찾고 만약 발견한다면 연결된 setter나 getter를 호출합니다. HashMap에 관한 자세한 정보는 data preferences 문서를 참조하세요.

  • 찾을 수 없다면 사용자가 "script" 또는 "meta" 속성에 접근하는 것을 원하는지를 명시적으로 확인합니다.

  • 그렇지 않은 경우 CanvasItem 및 상속된 유형에서 _set/_get 구현(액세스 유형에 따라)을 확인합니다. 이러한 메서드는 개체에 속성이 있다는 인상을 주는 논리를 실행할 수 있습니다. 이는 _get_property_list 방법의 경우에도 마찬가지입니다.

    • 이는 숫자로 시작하거나 슬래시를 포함하는 이름과 같이 합법적이지 않은 기호 이름의 경우에도 발생합니다.

결과적으로, 이 덕 타이핑 시스템은 스크립트, 오브젝트의 클래스 또는 오브젝트가 상속하는 모든 클래스에서 속성을 찾을 수 있지만, Object를 확장하는 것에 대해서만 가능합니다.

Godot는 이러한 접근에 대한 런타임 검사를 수행하기 위한 다양한 옵션을 제공합니다.

  • 오리형 부동산 접근입니다. 이는 위에서 설명한 대로 속성 검사입니다. 작업이 개체에서 지원되지 않으면 실행이 중단됩니다.

    # All Objects have duck-typed get, set, and call wrapper methods.
    get_parent().set("visible", false)
    
    # Using a symbol accessor, rather than a string in the method call,
    # will implicitly call the `set` method which, in turn, calls the
    # setter method bound to the property through the property lookup
    # sequence.
    get_parent().visible = false
    
    # Note that if one defines a _set and _get that describe a property's
    # existence, but the property isn't recognized in any _get_property_list
    # method, then the set() and get() methods will work, but the symbol
    # access will claim it can't find the property.
    
  • 방법 점검. CanvasItem.visible <class_CanvasItem_property_visible>`의 경우 다른 메소드와 마찬가지로 ``set_visible`is_visible 메소드에 액세스할 수 있습니다.

    var child = get_child(0)
    
    # Dynamic lookup.
    child.call("set_visible", false)
    
    # Symbol-based dynamic lookup.
    # GDScript aliases this into a 'call' method behind the scenes.
    child.set_visible(false)
    
    # Dynamic lookup, checks for method existence first.
    if child.has_method("set_visible"):
        child.set_visible(false)
    
    # Cast check, followed by dynamic lookup.
    # Useful when you make multiple "safe" calls knowing that the class
    # implements them all. No need for repeated checks.
    # Tricky if one executes a cast check for a user-defined type as it
    # forces more dependencies.
    if child is CanvasItem:
        child.set_visible(false)
        child.show_on_top = true
    
    # If one does not wish to fail these checks without notifying users,
    # one can use an assert instead. These will trigger runtime errors
    # immediately if not true.
    assert(child.has_method("set_visible"))
    assert(child.is_in_group("offer"))
    assert(child is CanvasItem)
    
    # Can also use object labels to imply an interface, i.e. assume it
    # implements certain methods.
    # There are two types, both of which only exist for Nodes: Names and
    # Groups.
    
    # Assuming...
    # A "Quest" object exists and 1) that it can "complete" or "fail" and
    # that it will have text available before and after each state...
    
    # 1. Use a name.
    var quest = $Quest
    print(quest.text)
    quest.complete() # or quest.fail()
    print(quest.text) # implied new text content
    
    # 2. Use a group.
    for a_child in get_children():
        if a_child.is_in_group("quest"):
            print(quest.text)
            quest.complete() # or quest.fail()
            print(quest.text) # implied new text content
    
    # Note that these interfaces are project-specific conventions the team
    # defines (which means documentation! But maybe worth it?).
    # Any script that conforms to the documented "interface" of the name or
    # group can fill in for it.
    
  • :ref:`Callable <class_Callable>`에 대한 액세스를 아웃소싱합니다. 이는 종속성으로부터 최대한의 자유도가 필요한 경우에 유용할 수 있습니다. 이 경우 메소드를 설정하기 위해 외부 컨텍스트에 의존합니다.

# child.gd
extends Node
var fn = null

func my_method():
    if fn:
        fn.call()

# parent.gd
extends Node

@onready var child = $Child

func _ready():
    child.fn = print_me
    child.my_method()

func print_me():
    print(name)

이러한 전략은 Godot의 유연한 디자인에 기여합니다. 그 사이에 사용자는 특정 요구 사항을 충족할 수 있는 다양한 도구를 갖게 됩니다.