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 편집기가 하는 일이고, 오브젝트의 C++ 생성자에서 이루어집니다.

하지만 어떤 것을 사용해야 하는지 결정하는 것은 딜레마가 됩니다. 스크립트 인스턴스를 만드는 것은 인 게임 클래스를 만드는 것과 동일하지만 씬을 다루려면 API를 변경해야 합니다:

const MyNode = preload("my_node.gd")
const MyScene = preload("my_scene.tscn")
var node = Node.new()
var my_node = MyNode.new() # Same method call.
var my_scene = MyScene.instantiate() # Different method call.
var my_inherited_scene = MyScene.instantiate(PackedScene.GEN_EDIT_STATE_MAIN) # Create scene inheriting from MyScene.

또한 엔진과 스크립트 코드 간의 속도 차 때문에 스크립트가 씬에 비해 조금 더 느리게 작동합니다. 노드가 크고 복잡할수록, 씬으로 작업하는 것이 더 좋습니다.

명명된 유형

편집기 자체에서 스크립트를 새로운 타입으로 등록할 수 있습니다. 노드 생성 또는 리소스 생성 대화 상자에서 새로운 타입으로 추가적인 아이콘과 함께 표시됩니다. 이런 경우, 사용자가 스크립트를 사용하는 것이 훨씬 더 간소화됩니다. 아래와 같이 하지 않아도 됩니다...

  1. 사용하고 싶은 스크립트의 기본 타입을 알기.

  2. 기본 타입의 인스턴스를 생성하기.

  3. 노드에 스크립트를 추가하기.

등록된 스크립트에 대해서 다른 시스템 내 노드와 리소스와 같이 스크립트로 만들어진 타입의 생성 옵션이 나타납니다. 생성 대화 상자에는 타입을 이름으로 찾아볼 수 있는 검색 상자도 있습니다.

타입을 등록하는 데는 두 가지 시스템이 있습니다:

  • 커스텀 타입

    • 편집기 전용. 런타임에는 타입이름에 접근할 수 없습니다.

    • 상속된 커스텀 타입을 지원하지 않습니다.

    • 초기화 툴입니다. 스크립트를 사용해 노드를 만듭니다. 다른 기능은 없습니다.

    • 편집기는 스크립트에 대한 타입 인식, 다른 엔진 타입이나 스크립트와의 관계를 인식할 수 없습니다.

    • 사용자가 아이콘을 정의할 수 있습니다.

    • 스크립트 리소스를 추상화하기 때문에 모든 스크립트 언어에서 작동합니다.

    • EditorPlugin.add_custom_type 을 사용해 설정합니다.

  • 스크립트 클래스

    • 편집기와 런타임에서 접근할 수 있습니다.

    • 상속 관계 전체를 표시합니다.

    • 스크립트가 부착되어 있는 노드를 만들지만, 편집기에서 타입을 바꾸거나 확장할 수도 있습니다.

    • 편집기는 스크립트, 스크립트 클래스, 엔진 C++ 클래스 간의 상속 관계를 인식합니다.

    • 사용자가 아이콘을 정의할 수 있습니다.

    • 엔진 개발자는 수동으로 언어 지원을 추가해야 합니다 (이름 표시와 런타임 접근 가능성 모두).

    • 편집기는 프로젝트 폴더를 탐색하여 모든 스크립팅 언어의 노출된 이름을 등록합니다. 각 스크립팅 언어에 대해 이러한 정보의 노출에 대한 지원을 각각 구현해야 합니다.

두 방법론 모두 생성 대화 상자에 이름을 추가할 수 있습니다. 하지만 스크립트 클래스는 사용자가 스크립트 리소스를 불러오지 않고도 타입이름에 접근할 수 있습니다. 인스턴스를 만들고 상수나 정적 메서드에 접근하는 것은 어디서나 가능합니다.

이러한 기능을 사용하는 경우 씬 없이도 스크립트로 만든 타입을 통해 사용 편의성을 제공할 수 있습니다. 플러그인을 개발하거나 디자이너를 위한 사내 툴을 만드는 사람들에게 이러한 방식의 구현이 더 편리할 것입니다.

단점은 명령형 프로그래밍을 주로 사용해야 한다는 것입니다.

스크립트와 PackedScene의 성능

마지막으로 씬과 스크립트를 선택할 때 고려할 사항은 실행 속도입니다.

오브젝트의 규모가 커질수록, 오브젝트를 만들고 초기화 하는 데 필요한 스크립트의 크기는 더욱 더 커집니다. 노드 계층 구조를 만드는 것이 그러한 경우입니다. 각 노드의 로직은 수 백줄의 코드가 될 수 있습니다.

아래의 코드 예제는 새로운 Node 를 생성하고, 이름을 변경하고, 스크립트를 할당하고, 부모가 될 노드를 소유자로 지정하여 디스크에 같이 저장되도록 한 뒤 Main 노드의 자식으로 등록하는 코드입니다:

# main.gd
extends Node

func _init():
    var child = Node.new()
    child.name = "Child"
    child.script = preload("child.gd")
    add_child(child)
    child.owner = self

이와 같은 스크립트 코드는 엔진쪽의 C++ 코드보다 훨씬 느립니다. 매 명령은 스크립트 API를 호출하기 때문에 실행할 로직을 찾기 위해 백엔드에서 많은 "lookup"이 일어나게 됩니다.

씬은 이런 문제를 피할 수 있도록 해줍니다. 씬이 상속하는 기본 타입인 :ref:`PackedScene <class_PackedScene>`은 오브젝트를 생성에 필요한, 직렬화된 데이터를 사용하는 리소스를 정의합니다. 엔진은 백엔드에서 씬을 배치(batch)로 처리할 수 있게 되고 스크립트보다 훨씬 나은 성능을 보입니다.

결론

결론적으로, 최선의 접근법은 아래 사항들을 고려하는 것입니다:

  • 여러 다른 프로젝트에서 재사용될 예정이며, ("프로그래머"라는 이름표가 없는 사람들을 포함한) 모든 실력 수준의 사람들이 사용할 수 있는 기초 툴을 만들고 싶다면, 아마 커스텀한 이름과 아이콘을 가지고 있는 스크립트로 만들어야 할 것입니다.

  • 게임에 필요한 어떤 개념이라면, 거의 대부분의 경우 씬으로 만들어야 합니다. 씬이 스크립트보다 더 쉽게 추적/편집이 가능하고 보안성이 높습니다.

  • 씬에 이름을 부여하고 싶다면, 스크립트 클래스를 선언하고 상수로 씬을 지정하여 원하는 바를 달성할 수 있습니다. 스크립트는 사실상 네임스페이스가 됩니다:

    # game.gd
    class_name Game # extends RefCounted, so it won't show up in the node creation dialog.
    extends RefCounted
    
    const MyScene = preload("my_scene.tscn")
    
    # main.gd
    extends Node
    func _ready():
        add_child(Game.MyScene.instantiate())