Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Godot 인터페이스

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

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

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

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

오브젝트 참조 얻기

모든 :ref:`Object <class_Object>에 있어, 오브젝트를 참조하는 가장 기본이 되는 방식은 획득한 다른 인스턴스로부터 존재하는 오브젝트로 참조를 가져오는 것이다.

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

The same principle applies for RefCounted objects. While users often access Node and Resource this way, alternative measures are available.

속성(property)이나 메서드 액세스 대신 로드 액세스로 리소스에 접근할 수 있습니다.

# 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. 리소스를 로딩할 때 내부적으로 엔진이 관리하는 캐싱된 리소스 인스턴스를 가져온다는 사실을 기억해두십시오. 새 오브젝트를 생성하려면 이미 존재하면 레퍼런스를 duplicate <class_Resource_method_duplicate>`하거나 ``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 <class_CanvasItem>`는 ``visible` 속성(property)를 갖고 있습니다. 스크립팅 API에게 노출된 모든 속성(property)들은 이름으로 바인딩 된 setter와 getter 쌍과 같습니다. :ref:`CanvasItem.visible <class_CanvasItem_property_visible>`에 액세스가 발생하면 Godot은 다음과 같은 동작을 수행합니다:

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

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

  • 만약 찾지 못한다면 유저가"script" 또는 "meta" 속성(property)에 액세스하는 것을 원하는지 명시적으로 묻습니다.

  • If not, it checks for a _set/_get implementation (depending on type of access) in the CanvasItem and its inherited types. These methods can execute logic that gives the impression that the Object has a property. This is also the case with the _get_property_list method.

    • Note that this happens even for non-legal symbol names, such as names starting with a digit or containing a slash.

As a result, this duck-typed system can locate a property either in the script, the object's class, or any class that object inherits, but only for things which extend Object.

Godot provides a variety of options for performing runtime checks on these accesses:

  • A duck-typed property access. These will be property checks (as described above). If the operation isn't supported by the object, execution will halt.

    # 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.
    
  • A method check. In the case of CanvasItem.visible, one can access the methods, set_visible and is_visible like any other method.

    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.
    
  • Outsource the access to a Callable. These may be useful in cases where one needs the max level of freedom from dependencies. In this case, one relies on an external context to setup the method.

# 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)

These strategies contribute to Godot's flexible design. Between them, users have a breadth of tools to meet their specific needs.