TECHARTNOMAD | MAZELINE.TECH

TECH.ART.FLOW.IO

[번역] UF2025(Orlando) — Unity의 그림자, UEFN Scene Graph와 Verse 심층 분석

jplee 2026. 6. 24. 02:38

역자의 말: 제목의 Unity의 그림자 이거 Shadow 그거 아닙니다. ㅋ UEFN 에서의 Verse 와 UE6 에서의 Verse 는 좀 분리 해 놓고 봐야하겠지만 어차피 VerseVM 런타임에서 돌아가는건 같지 않나 싶습니다.


저자: wlxklyh

이번 글도 꽤 재미있다. 보자마자 든 생각은, 이거 Unity의 Entity + Component 아닌가? 왜 메인라인 UE에는 없고 UEFN 안에 이런 설계가 들어가 있는 걸까? UE가 Unity를 베끼고, Unity가 UE를 베끼고, 하하하하하.

원본 영상: Powering Up Your Projects With Scene Graph and Verse | Unreal Fest Orlando 2025
발표자: Evan Brown, Epic Games Programmer Writer
영상 링크: https://www.youtube.com/watch?v=IW8HjoO-Uj0
영상 길이: 31분 13초. 자막은 영상 자체 영어 자동 자막 기준.
이 글은 해당 발표를 바탕으로 정리한 한국어 심층 기술 글이다.

들어가며

Scene Graph는 또 하나의 장면 정리 패널이 아니다. UEFN의 오브젝트 세계를 통일된 Entity-Component 모델로 전환하는 것이다.
여기서 Verse가 맡는 역할도 단순한 스크립트 언어가 아니다. 강타입, 하위 호환성, 전역 네임스페이스, 트랜잭션 롤백(transactional rollback) 이 함께 Scene Graph에 필요한 안정성과 이식성을 받쳐준다.
기존 UEFN 사용자에게 가장 큰 사고방식 전환은 이것이다. 하나의 중앙 Verse device가 모든 오브젝트를 제어하게 하지 말고, 오브젝트 자신이 컴포넌트를 통해 데이터와 행동을 갖게 하라.

이 글을 읽을 때는 UEFN 에디터, Verse device, Creative prop, Prefab, Actor / Component 같은 기본 개념은 어느 정도 알고 있다고 가정한다. Scene Graph에 대한 사전 지식은 필요 없다. 글에서 정의부터 시작할 것이다.

여기서 AI로 Creative Prop과 Verse Device를 잠깐 설명해보자.

UEFN 개발 방식은 Prop + Device의 역할 분담이다. UEFN(Unreal Editor for Fortnite)은 포트나이트의 공식 에디터이고, 여기서 만든 콘텐츠는 Fortnite Creative 샌드박스 안에서 돌아가야 한다. 이 제한 때문에 일반 UE 프로젝트와 가장 큰 차이가 생긴다. 임의의 Actor에 Blueprint나 C++ 스크립트를 붙일 수 없다. 모든 커스텀 로직은 특수한 것 하나, 즉 Verse device 안에만 쓸 수 있다.

두 종류의 세계 시민이 있다.

Creative Prop(크리에이티브 소품)

  • 장면 안에 배치되는 “말 없는 물체”다. 나무 한 그루, 상자 하나, 벽 하나, 코인 모델 하나 같은 것.
  • 자체 로직은 없다. 본질적으로는 메시 + 충돌 + 간단한 상호작용(공격당함, 닿음)을 가진 인스턴스다.
  • 비유하자면 UE에서 아무 Blueprint도 붙이지 않은 StaticMeshActor에 가깝다.

Verse Device(Verse 장치)

  • Verse 언어로 작성한 스크립트 오브젝트다. 이것도 하나의 엔티티처럼 월드에 배치된다. 보일 수도 있고 안 보일 수도 있다.
  • 생명주기 훅이 있다. OnBegin()은 게임 시작 시 호출되고, OnEnd()는 종료 시 호출된다.
  • 비유하자면 UE에서 렌더링은 하지 않고 로직만 담당하는 GameMode / Manager Actor에 가깝다.

전형적인 흐름은 이렇다.

  1. 에디터에서 N개의 prop을 장면에 끌어다 놓는다. 즉, 장면을 만든다.
  2. Verse device 하나를 장면에 끌어다 놓는다.
  3. device 스크립트 안에서 @editable 변수를 선언해 그 prop들을 “지정”한다. Inspector에서 레퍼런스를 드래그하는 것과 비슷하다.
  4. 게임이 시작되면 device의 OnBegin()이 실행되고, prop 레퍼런스를 가져온 뒤, 이후 device가 prop에 명령을 보낸다. 이동, 숨김, prop의 “상호작용됨” 이벤트 구독 같은 것들이다.

왜 이렇게 설계했을까

“배치되는 것”과 “제어 로직”을 강하게 두 층으로 나눈 것은 Epic의 의도적인 제약이다.

  • prop은 Fortnite 기존 시스템에 의해 직렬화, 복제, 롤백될 수 있어야 한다. 그래서 사용자가 그 안에 임의의 스크립트를 집어넣게 둘 수 없다.
  • 로직은 device에 집중된다. 심사, 샌드박스, 성능 경계를 관리하기 쉽다.
  • 부작용으로 자연스럽게 ECS 스타일이 형성된다. 데이터(prop)는 월드 안에 있고, 행동(device)은 스크립트에 있으며, 둘은 @editable 레퍼런스로 묶인다.

그래서 “prop 배치, device 시작 로직, device가 계속 prop을 구동”하는 구조는 UEFN에서 거의 모든 게임플레이가 따르는 표준 패턴이다. 특정 글만의 특수한 작성 방식이 아니다.

발표 아젠다: Scene Graph와 Verse의 동기에서 시작해 플랫폼 레벨 실전, 그리고 미래 로드맵까지.

발표자는 시작하자마자 큰 줄기를 설명한다. 먼저 Scene Graph와 Verse의 what / why를 이야기하고, 이어 플랫폼 레벨 예시를 통해 전통적인 device-driven 방식Scene Graph component-driven 방식을 비교한다. 마지막으로 현재 단계의 시스템 제한과 향후 방향을 설명한다. 이 네 줄기가 이 글 전체의 구조다.

1. 왜 UEFN은 Scene Graph를 도입하려 하는가

1.1 전통적인 방식에서 “오브젝트에 소속이 없다”는 문제

현재 주류 UEFN 워크플로에서 전형적인 개발 방식은 이렇다. Creative prop은 월드에 배치되고, Verse device는 게임 시작 시 로직을 시작하며, 이후 해당 device가 그 prop들을 계속 제어한다. 이 방식은 동작한다. 하지만 오브젝트 수, 행동 조합, 런타임 생성 요구가 늘어날수록 몇 가지 구조적 문제가 드러난다.

  • 오브젝트 자체에 행동의 소속이 없다: Creative prop은 조작 가능한 기하 오브젝트에 더 가깝고, 실제 상태와 로직은 종종 외부 device 클래스 안으로 흘러간다.
  • 오브젝트 간 협력이 중앙 스케줄링에 의존한다: prop끼리는 직접 대화할 수 없다. 모든 정보가 device를 거쳐 돌아가야 한다.
  • 재사용 단위가 거칠다: 새로운 행동 하나는 종종 새 device 클래스를 만들거나 기존 베이스 클래스의 editables를 계속 부풀리는 일을 뜻한다.
  • 동적 생성 비용이 높다: 런타임에 갑자기 “움직이고, 공격하고, 몬스터를 생성하는” 플랫폼을 만들고 싶다면 prop spawn, 목표 지점, key frame, 관리 클래스, setup 호출을 모두 함께 처리해야 한다.

발표자는 후반부에서 구체적인 플랫폼 레벨 예시를 통해 “복잡도가 왜 폭발하는가”를 매우 구체적으로 보여준다(5절 참고). 여기서는 먼저 이것을 설계 문제로 기억해두자. 행동을 누가 들고 있는가, 데이터를 누가 들고 있는가, 시뮬레이션을 누가 구동하는가. device-driven 방식에서는 이 세 질문의 답이 모두 “중앙 device”로 떨어진다.

1.2 Scene Graph의 기본 정의

영상에서 제시한 공식적인 기본 정의는 이렇다. Scene Graph는 월드 안의 모든 오브젝트를 연결하는 통일된 구조다. 장면 오브젝트를 최상위 simulation entity 아래에 조직하고, 오브젝트 계층, 컴포넌트, 리소스, Verse 행동을 모두 하나의 모델 안에 넣는다.

Scene Graph는 장면 오브젝트를 통일된 엔티티 트리 안에 조직한다.

그림의 집 예시는 매우 단순하다. 지붕, 벽, 바닥 같은 하위 부분은 Outliner 안에 임의로 중첩된 오브젝트가 아니라 simulation entity 아래에 있는 엔티티 트리로 나타난다. 각 노드는 컴포넌트를 통해 자신의 위치, 외형, 행동을 결정한다.

발표자가 반복해서 강조한 말이 있다. Scene Graph의 의미 중 하나는 Unreal Engine의 Actor 체계에서 Entity + Component 체계로 이동하는 것이다. 이 이동은 UEFN 쪽에서 일어나는 것이지, UE 메인라인 프로젝트에 Actor를 버리라고 말하는 것은 아니다. 하지만 Epic이 “메타버스급” 콘텐츠 조직 방식을 조합 우선(composition-first)의 엔지니어링 패러다임으로 끌고 가려 한다는 점은 분명히 보여준다.

2. Entity: 의도적으로 “아무것도 없는” 컨테이너

2.1 Entity는 처음에는 비어 있다

영상은 꽤 많은 시간을 들여 한 가지 사실을 강조한다. Entity는 처음에 아무것도 없다. “아무것도 아니다”라는 구호 같은 말이 아니라, 말 그대로 비어 있다.

위치도 없고, 메시도 없고, 빛도 없고, 상호작용성도 없다. 심지어 3D 공간 안에 존재한다는 감각조차 없다. 어떤 능력이든 갖게 하려면 반드시 명시적으로 컴포넌트를 추가해야 한다.

  • 어떤 좌표에 존재하게 하고 싶다면 transform component를 붙인다.
  • 보이게 하고 싶다면 mesh component를 붙인다.
  • 빛나게 하고 싶다면 light component를 붙인다.
  • 로직을 실행하게 하고 싶다면 커스텀 Verse component를 붙인다.

이런 “최소 초기 상태”는 의도적인 설계 선택이다. Actor가 처음부터 여러 기본 컴포넌트와 기본 행동을 상속받는 것과 대비된다. Entity는 컨테이너로서 최소 출발점만 노출하고, 개발자는 조합을 통해 필요한 오브젝트를 점진적으로 “자라게” 만든다.

Entity는 컴포넌트를 통해 데이터와 행동을 얻는다.

이 그림은 영상에서 반복해서 나온 문장과 대응된다. Entity는 컴포넌트를 사용해 데이터(data)와 행동(behavior)을 싣는다. 평범한 entity를 램프, 자동차, 장치로 진화시키는 것은 전부 어떤 컴포넌트를 얹느냐에 달려 있다.

2.2 Prefab: Entity + Component 묶음을 재사용 가능한 asset으로 봉인하기

영상에서 제시한 또 다른 핵심 구조는 Prefab이다. Prefab이 저장하는 것은 “몇 개의 Creative prop 그룹”이 아니라, 엔티티와 컴포넌트의 완전한 구조다. 그것이 하나의 asset으로 존재한다.

Prefab은 엔티티와 컴포넌트 구조를 재사용 가능한 asset으로 고정한다.

영상에서는 lamp prefab의 전체 구조를 설명한다.

  • lampost 엔티티: transform + mesh + gameplay 요소 하나. 이것은 Verse 코드일 수도 있고 interactable component일 수도 있다.
  • 그 아래에 lamp 자식 엔티티: transform + mesh + light component.
  • 이 둘을 함께 저장해 lamp prefab으로 만든다.

이 prefab을 레벨에 끌어다 놓으면 바로 사용할 수 있는 “가로등 기둥 + 램프” 단위가 된다. 더 중요한 것은 Prefab이 두 가지 수정 방식을 동시에 지원한다는 점이다.

  • Prefab 에디터에서 수정: lampost의 메시를 교체하면 레벨 안의 모든 가로등 인스턴스가 즉시 갱신된다.
  • 단일 인스턴스에서 수정: 이 램프 하나의 light 색상만 바꾸고, 다른 인스턴스는 그대로 둔다.

이것이 발표자가 정리한 말, “원하는 방식으로 콘텐츠를 구조화하라(structure content the way you like)”의 의미다. 대량 재사용과 로컬 커스터마이즈는 둘 중 하나를 포기해야 하는 선택지가 아니다.

3. Component: 엔진 기능이면서, 사용자의 Verse 행동이기도 하다

Scene Graph에서 컴포넌트는 두 종류의 책임을 맡는다. 영상에서는 이를 꽤 완전하게 설명한다.

  1. 내장 컴포넌트(Built-in Components): API가 직접 제공한다. 예를 들어 transform, mesh, light, 그리고 뒤에서 등장하는 key frame movement가 있다. 엔지니어링 관점에서는 “다시 직접 작성하지 않아도 되는 기본 능력”이다.
  2. 사용자 정의 Verse 컴포넌트: 과거 Verse device 안에 쓰던 행동을 컴포넌트로 작성해 엔티티에 붙인다.

컴포넌트는 내장 능력일 수도 있고, 사용자 Verse 코드나 가져온 asset일 수도 있다.

발표자는 세 번째 차원도 덧붙였다. 컴포넌트는 asset reference로도 표현될 수 있다. 가져온 mesh, VFX, 나아가 Prefab 자체도 assets 파일을 통해 Verse에 노출될 수 있고, 런타임에서 컴포넌트 방식으로 인스턴스화, 교체, 생성할 수 있다.

3.1 사용자 정의 Verse 컴포넌트: device 사고방식에서 벗어나기

영상에서는 아주 간단한 예시 컴포넌트를 보여준다. 대략 다음과 같다. 아래 코드는 영상에 나온 코드 조각을 바탕으로 Verse 스타일 의사 코드로 다시 그린 것이다. [AI 추정] 부분은 코드가 자족적으로 보이도록 타입 선언을 보완한 것이지, 영상의 완전한 코드 복사는 아니다.

# [AI 추정] 영상 예시를 바탕으로 정리한 최소 의사 코드.
# 컴포넌트 생명주기를 설명하기 위한 용도다.
my_cool_new_component := class(component):
    OnBeginSimulation():void =
        Print("hello world")

핵심 변화는 “이 코드는 언제 실행되는가?”라는 질문에 있다.

  • 과거 Verse device 방식: 코드는 레벨에 끌어다 놓은 그 device 오브젝트가 시작될 때 실행된다.
  • 컴포넌트 방식: 코드는 컴포넌트가 붙어 있는 엔티티가 시뮬레이션을 시작할 때(OnBeginSimulation) 실행된다. 더 이상 중앙 device를 진입점으로 필요로 하지 않는다.

Prefab은 전체 구조로 저장되며 asset처럼 인스턴스화할 수 있다.

발표자는 극단적인 예를 든다. 같은 컴포넌트를 집 Prefab 안의 모든 자식 엔티티에 붙이면 벽돌 하나하나가 모두 Hello World를 실행하게 만들 수 있다. 그는 이것이 **“아마 좋은 설계는 아닐 것”**이라고도 말한다. 하지만 이 예시는 능력의 경계를 보여준다. 행동은 임의의 입자도 높은 엔티티 단위까지 내려갈 수 있다.

3.2 컴포넌트화의 설계 이점

“컴포넌트를 붙일 것인가”를 조절 스위치처럼 다룰 수 있게 되면, 컴포넌트화는 몇 가지 체감 가능한 엔지니어링 이점을 준다.

  • 상속이 아니라 능력 조합: 새 행동을 추가하기 위해 어떤 베이스 클래스를 확장할 필요가 없다. 새 컴포넌트를 쓰면 된다.
  • 행동과 시각 표현의 분리: mesh와 gameplay 행동은 모두 컴포넌트이므로 독립적으로 교체할 수 있다.
  • 더 자연스러운 쿼리 의미론: 뒤에서 “장면 안의 light component를 가진 모든 엔티티 찾기” 같은 쿼리가 나온다.

4. Verse: Scene Graph가 안정적으로 돌아가는 진짜 이유

영상의 핵심 관점 중 하나는 이것이다. Verse를 평범한 스크립트 언어로 보지 말라. Epic은 Verse를 “장기간 실행, 월드 간 이동, 사용자 공유 콘텐츠”를 감당할 수 있는 언어로 설계했다. 이런 엔지니어링 제약이 Verse를 다른 스크립트 언어와 다른 모습으로 만들었다.

4.1 왜 “메타버스”는 언어에 추가 제약을 요구하는가

발표자는 먼저 메타버스 경험이 해결해야 하는 세 가지 엔지니어링 전제를 설명한다.

  • Always on: 섬과 경험은 계속 실행되어야 하며, 어떤 사용자 코드 하나 때문에 쉽게 죽어서는 안 된다.
  • Transferable: 콘텐츠는 서로 다른 월드 사이를 이동할 수 있어야 한다. 이사할 때 고립된 라이브러리와 리소스를 잔뜩 끌고 다녀야 해서는 안 된다.
  • Strong and stable: 사용자가 공개한 콘텐츠가 다른 사람의 경험을 쉽게 망가뜨려서는 안 된다. 예를 들어 자동차 한 대가 다른 사람의 섬으로 들어갔다고 해서 그 섬의 모든 엔티티를 지워버릴 수 있어서는 안 된다.

Verse는 Scene Graph에 안정성과 이식성을 위한 제약 기반을 제공한다.

그림 속 “남의 섬에 차가 들어와 모든 엔티티를 지워버리는” 반례는 영상이 제시한 구체적인 위협 모델이다. Verse의 많은 설계 선택은 이런 파괴가 언어 차원에서 불가능해지도록 하기 위한 것이다.

4.2 Verse의 네 가지 핵심 속성

영상에서 명확히 언급한 Verse 특성은 다음과 같다.

  • 강타입 + 하위 호환성: Scene Graph 오브젝트의 장기 사용 가능성을 보장한다. 발표자는 가상의 상황을 예로 든다. 2030년에 누군가 2025년에 공개한 당신의 Verse 코드를 다운로드해 실행하더라도, 새 버전에서 여전히 돌아간다. Verse가 하위 호환성을 약속하기 때문이다.
  • 전역 공유 네임스페이스: 공개된 Verse 코드는 evan.epic.com/...citybuilder.verse 같은 전역 유일 네임스페이스에 놓인다. 창작자 간 이름 충돌을 피하기 위해서다. 처음 공개된 tycoon builder.verse가 그 이름을 독점하지 않는다.
  • 트랜잭션성(transactional): 발표자는 이것을 Verse의 “가장 큰 초능력 중 하나”라고 부른다.
  • 낮은 진입 장벽: 메모리 관리, 멀티스레딩, 멀티플레이 네트워크 같은 전통적인 난점이 언어 차원에서 감싸진다. 창작자는 코드를 쓰고, Verse device를 끌어다 놓고, Play를 누르기만 해도 이미 멀티플레이에서 쓸 수 있는 경험을 만들게 된다.

4.3 트랜잭션성: 제약이 붙은 rollback 모델

Verse의 트랜잭션 컨텍스트는 예외를 롤백해 경험을 망가뜨리지 않게 한다.

발표자는 매우 엔지니어링적인 예를 든다. 플레이어에게 팀 무기를 배정하는 함수다.

  1. playspace를 가져온다.
  2. team collection을 가져온다.
  3. player를 기준으로 team을 찾는다.
  4. 이 team의 player에게 무기를 지급한다.

이 네 단계는 모두 failable(실패할 수 있음) 하다. 전통적인 언어에서는 중간 단계 하나가 실패하면 직접 null check를 하고, 상태를 직접 롤백해야 한다. Verse의 트랜잭션 모델은 전체 컨텍스트를 하나의 트랜잭션으로 본다. 어떤 단계든 실패하면, 예를 들어 배열 범위 초과, null pointer, 비즈니스 실패가 발생하면, 전체 트랜잭션이 rollback되고 heap에 쓰지 않으며, 경험을 망가뜨리지 않는다. 섬은 계속 실행되고, 다른 플레이어는 영향을 받지 않는다.

여기서 증거의 경계는 분명히 해야 한다. 영상은 트랜잭션 의미론과 그 엔지니어링 가치를 강조했지만, 구체적인 성능 데이터, rollback 비용, 모든 API의 정확한 정의는 제시하지 않았다. 따라서 이 글은 어떤 benchmark 결론도 추론하지 않는다. 실제 프로젝트에서는 직접 측정해야 한다.

5. 핵심 예시: 컴포넌트로 장면 안의 모든 엔티티 조회하기

영상에서 Scene Graph와 Verse가 함께 만들어내는 가치를 가장 잘 보여주는 코드 예시는 “시뮬레이션 시작 시 장면 안의 모든 light가 있는 엔티티에 파티클 효과를 붙이는” 컴포넌트다.

커스텀 Verse 컴포넌트가 컴포넌트 쿼리로 전체 엔티티 트리를 탐색한다.

발표자는 이 코드가 무엇을 하는지 단계별로 설명한다. 아래는 영상 설명을 바탕으로 한국어 흐름에 맞게 정리한 의사 코드다.

# [AI 추정] 영상 설명을 바탕으로 정리한 최소 의사 코드.
light_vfx_bolt := class(component):
    OnBeginSimulation():void =
        # 1. 컴포넌트가 붙은 엔티티에서 simulation entity(최상위 entity)를 가져온다.
        SimEntity := GetEntity().GetSimulationEntity[]

        # 2. 컴포넌트 타입으로 전체 엔티티 트리를 조회해
        # light_component를 가진 모든 엔티티를 반환한다.
        LitEntities := SimEntity.FindDescendantEntitiesWithComponent[light_component]

        # 3. 각 대상 엔티티에 particle system component를 만들고 추가한다.
        for (LitEntity : LitEntities):
            VFX := particle_system_component{ ParticleSystem := blowing_particles_asset }
            LitEntity.AddComponents[array{ VFX }]
            VFX.Enable()

이 예시를 자세히 볼 가치가 있는 이유는, device 모델에서는 매우 하기 어려웠던 몇 가지를 보여주기 때문이다.

  • 조회 대상이 특정 Creative prop 클래스가 아니다. 수동으로 관리하는 배열도 아니다. “light component를 가진 모든 엔티티”다.
  • 조회 범위가 simulation entity에서 시작해 전체 트리를 덮을 수 있다. 모든 엔티티가 이 통일 구조 아래에 있기 때문이다.
  • 새 능력은 대상에 ‘외부에서 붙이는’ 것이 아니라, 컴포넌트로서 그 엔티티의 일부가 된다. 이것은 접착이 아니라 조합이다.
  • 같은 로직을 임의의 컴포넌트에 붙일 수 있다. 생명주기는 그 컴포넌트가 붙어 있는 엔티티가 구동한다. 더 이상 전역 device에 의존하지 않는다.

발표자는 이것을 “really, really, really hard to do with devices”, 즉 “device 모델에서는 정말 정말 정말 어렵다”고 평가했다. 이것이 이 절의 엔지니어링 핵심이다. Scene Graph는 본질적으로 UEFN의 “오브젝트-행동” 관계를 중앙 스케줄링에서 통일된 쿼리로 바꾼다.

6. 샘플 레벨: 먼저 devices로 만들고, 다시 Scene Graph로 만들기

6.1 왜 플랫폼 레벨을 예시로 골랐는가

영상의 데모 부분은 가장 고전적인 플랫폼 레벨(platformer)을 선택했다. 플레이어가 태어나고, 여러 장애물을 건너 목적지에 도달한다. 장애물 중 가장 흔한 것은 “깊은 구덩이 위를 가로지르는 움직이는 플랫폼”이다.

최소 플랫폼 하나는 entity + transform + mesh만으로도 돌아간다.

발표자는 이 최소 플랫폼을 매우 깔끔하게 추상화한다.

  • 그것은 하나의 엔티티다.
  • transform component가 있어 월드 안의 위치를 알려준다.
  • mesh component가 있어 플레이어가 보고 올라설 수 있다.

이 두 컴포넌트를 붙이고 Prefab으로 저장하면, 전체 맵 안에 수십 개의 플랫폼을 끌어다 놓을 수 있다. 5분 만에 기초 플랫폼 레벨을 만드는 것이 과장이 아니다.

진짜 문제는 능력을 확장하기 시작할 때 생긴다.

  • 플랫폼을 움직이고 싶다? movement component를 붙인다.
  • 플레이어가 오래 서 있으면 피해를 주고 싶다? damage-on-stand component를 붙인다.
  • 플레이어가 밟을 때 폭발하거나 NPC를 생성하고 싶다? 해당 컴포넌트를 붙인다.

이런 능력들은 컴포넌트 형태로 필요에 따라 조합된다. “device A가 이동 담당, device B가 피해 담당, device C가 몬스터 생성 담당” 같은 다중 device 연결 방식으로 되돌아갈 필요가 없다.

6.2 먼저 devices 버전 보기: 왜 400줄까지 갔는가

팀이 처음 이 플랫폼 예제를 만들 때는 전통적인 device 모델을 사용했다. 출발점은 UEFN 문서의 “animating prop movement” 튜토리얼이고, Fall Guys 템플릿 섬을 사용했다. 레벨에는 몇 그룹의 애니메이션이 있다.

  • 좌우로 이동하는 플랫폼
  • 제자리에서 회전하는 플랫폼
  • transform scale을 기반으로 커졌다 작아지는 플랫폼
  • 이동 + 회전을 동시에 하는 플랫폼

Device 모델의 이동 플랫폼은 중앙 관리 클래스에 의존한다.

발표자는 device 구현 방식을 다시 정리한다. 여기서는 영상의 논리 순서에 맞게 정리한다.

  • Creative prop 자체는 Verse 코드를 실행할 수 없다. 그것은 월드 안의 오브젝트일 뿐, 데이터도 없고 행동도 없다.
  • 그래서 먼저 movable prop class를 만든다. 그 안에는 prop reference, 이동 시간, 이동 타입, easing, 시작점, 되돌아갈지 여부 같은 파라미터가 들어간다.
  • 애니메이션 자체는 key frame으로 쪼개야 한다. 각 key frame은 목표 transform + 다음 key frame까지 걸리는 시간이다. 보간도 직접 만들고, key frame 배열도 직접 조립한 뒤, 해당 prop의 animation controller에 넘겨 재생해야 한다.
  • 여기까지만 해서는 Play를 눌러도 아무 일도 일어나지 않는다. 이 movable prop class 인스턴스들을 시작해줄 “누군가”가 없기 때문이다.

Creative prop은 스스로 Verse를 실행할 수 없기 때문에 prop movement initiator 같은 중앙 장치가 생긴다.

“누가 시작할 것인가” 문제를 해결하기 위해 팀은 다시 prop movement initiator라는 Verse device를 추가했다.

  • 모든 animating prop의 레퍼런스를 보유한다.
  • OnBegin에서 이들을 순회하며 setup을 호출한다.
  • 이들을 통일적으로 구동한다.

발표자는 이 initiator를 “거대한 손 하나가 말들을 움직이는 것 같다”고 묘사한다. prop 자체는 자신이 무엇을 해야 하는지 모른다. 이 손이 그것을 옮기고, 시작시키고, 다른 prop과 조율해줘야 한다.

여기서 또 다른 문제가 나온다. 이 prop들은 서로 소통할 방법이 없다. 플레이어가 어디까지 갔는지 알고 싶은가? 안 된다. prop에는 상태가 없기 때문이다. 어떤 교차 오브젝트 조율도 반드시 중앙 device를 거쳐야 한다. 모델은 필연적으로 “별 모양 + 중앙 권위”로 향한다.

발표자가 제시한 규모는 이렇다. 전체 device 버전은 약 400줄의 코드다. 이것은 성능 데이터가 아니다. 예제 자체는 복잡하지 않은데, “오브젝트가 자체 행동을 가질 수 없다”는 사실이 코드량과 사고 복잡도를 모두 키웠다는 의미다.

Device 버전의 또 다른 고통점은 동적 생성 비용이 매우 높다는 것이다.

영상이 강조한 또 다른 핵심 비용은 정적성이다.

  • 레벨에 새 플랫폼 하나를 추가하고 싶다. prop을 복사하고, 목표 지점을 복사하고, 이름을 바꾸고, device로 돌아가 설정 항목을 추가하고, prop과 목표 지점을 모두 끌어다 연결해야 한다.
  • 런타임 동적 생성은 더 힘들다. prop을 spawn하고, 목표 지점을 spawn하고, movable prop 클래스를 new하고, 모든 파라미터를 할당하고, key frame을 생성하고, 배열에 push해야 한다. 게다가 다른 시스템이 setup을 호출해야 실제로 움직인다.
  • 행동을 확장하고 싶다. 예를 들어 플랫폼을 오래 밟으면 체력을 깎고 싶다. 그러면 베이스 클래스에 계속 쌓아 더러워지거나, 새 device를 만들고 접착 코드를 다시 써야 한다.

6.3 Scene Graph로 바꾸기: entity가 자기 행동을 스스로 책임진다

이제 Scene Graph 모델로 전환한다. 발표자는 전체 사고방식을 뒤집는다. 하나의 중앙 device가 모든 플랫폼을 움직이게 하지 말고, 플랫폼 엔티티가 스스로 이동 능력을 갖게 하라.

animate targets 컴포넌트는 엔티티가 스스로 key frame movement를 구동하게 한다.

구체적인 구현은 animate_targets_component라는 사용자 정의 Verse 컴포넌트다. 의사 코드 흐름은 다음과 같다.

# [AI 추정] 영상 설명을 바탕으로 정리한 최소 의사 코드.
animate_targets_component := class(component):
    Targets : []transform = array{}
    Segments : []segment_info = array{}  # 각 segment는 정지 시간 등을 설명한다.

    OnBeginSimulation():void =
        # 이 엔티티에서 내장 key_frame_movement_component를 가져온다.
        KeyFrameMover := GetEntity().GetComponent[key_frame_movement_component]

        loop:
            for (I -> Target : Targets):
                KeyFrameMover.MoveToTransform(Target)
                if (Seg := Segments.FindSegmentAtIndex[I]):
                    Sleep(Seg.PauseSeconds)

핵심은 두 가지다.

  • 호출하는 것은 엔진 내장 key frame movement component다. transform / mesh / light / key frame movement는 영상에서 명확히 “이미 노출된” 컴포넌트로 언급된다. 선형 보간을 직접 쓸 필요가 없다.
  • 이 컴포넌트는 “나, 이 엔티티”가 어떻게 움직일지만 신경 쓴다. 레벨 안의 다른 플랫폼을 알 필요가 없다.

이렇게 하면 device 버전의 initiator 문제가 바로 사라진다. 각 플랫폼 엔티티가 자기 시뮬레이션 루프를 스스로 시작한다. 이 행동이 필요한 오브젝트는 그냥 이 컴포넌트를 붙이면 된다.

같은 컴포넌트 구조가 전혀 다른 두 시각 표현, 즉 회색 박스와 건물 전체를 구동한다.

발표자는 일부러 비교 이미지를 보여준다. 왼쪽은 지루한 회색 박스가 좌우로 움직이고, 오른쪽은 건물 한 채 전체가 같은 움직임을 한다. 둘은 밑바닥에서 완전히 같은 Prefab, 같은 컴포넌트 조합, 같은 행동이다. 차이는 mesh와 자식 엔티티 구조뿐이다.

이 그림의 엔지니어링 의미는 흥미롭다. 행동이 더 이상 특정 시각 오브젝트에 묶이지 않는다. “수평 왕복 이동” Prefab의 mesh를 태양으로 바꿀 수도 있고, 도시 전체로 바꿀 수도 있다. 발표자는 농담처럼 말했다. “진짜 그렇게 하지는 마라. 컴퓨터가 폭발할 것이다. 하지만 그런 능력은 갖고 있다.” 이동 로직은 그대로 재사용된다.

6.4 작업 흐름: 수십 초에서 몇 초로

발표자는 “에디터에서 새 플랫폼 하나를 추가하는” 전체 과정을 비교한 영상도 보여준다.

Device 버전에서 새 플랫폼 하나를 추가하려면 editables, targets, keyframes를 묶어야 한다.

device 버전은 화면을 3배속으로 재생했는데, 실제로는 약 1분이 걸린다.

  1. 플랫폼 prop을 복사한다.
  2. 그 목표 지점들을 복사한다.
  3. 모든 위치를 수동으로 조정한다.
  4. 식별하기 쉽도록 목표 지점 이름을 바꾼다.
  5. Verse device로 돌아간다.
  6. animating prop 항목을 새로 추가한다.
  7. 플랫폼과 모든 목표 지점을 끌어다 연결한다.
  8. 저장한다.

Scene Graph 버전: Prefab을 끌어다 놓으면 끝이다.

Scene Graph 버전은 이렇다. Prefab 패널을 열고, 레벨에 끌어다 놓는다. 끝.

발표자는 이 경험을 네 단어로 정리한다. easy, fast, dynamic, reusable. 엔지니어링식으로 번역하면, “행동을 가진 오브젝트를 월드에 배치하는 일”의 한계 비용을 최소화했다는 뜻이다.

6.5 런타임 동적 생성: 진짜 차이는 여기서 나온다

Scene Graph가 진짜 힘을 발휘하는 곳은 사실 정적 레벨이 아니라 런타임이다.

Prefab이 런타임에 인스턴스화되고, 컴포넌트가 즉시 시뮬레이션을 시작한다.

  • 플레이어가 스위치를 밟으면 좌우로 움직이는 플랫폼 한 줄을 동적으로 생성하고 싶다. 이 Prefab을 바로 spawn하면 된다.
  • 엔티티가 인스턴스화될 때 그 위의 animate_targets_component가 OnBeginSimulation에서 실행을 시작한다.
  • device를 새로 만들 필요도 없고, editables를 연결할 필요도 없고, 수동 setup도 필요 없다. 스스로 움직인다.

이런 “Prefab은 spawn되는 순간 완전한 실행 단위가 된다”는 행동은 영상 시작 부분의 추상 원칙을 검증 가능한 장면으로 떨어뜨린다. 시뮬레이션 로직의 소속이 완전히 엔티티로 내려간다.

7. 컴포넌트화 사고와 중앙 관리 사고의 경계

영상 마지막 부분에서 발표자는 “device 사고방식으로 되돌아가지 말라”는 점을 여러 번 강조한다.

entity는 중앙 device에 의해 원격 조종되는 것이 아니라, 자기 의사결정권을 가져야 한다.

발표자의 의도를 엔지니어링 원칙 두 가지로 나누면 다음과 같다.

  • 컴포넌트가 데이터와 행동을 부여하게 하고, 엔티티가 스스로 판단하게 하라: 컴포넌트는 중앙 device의 원격 핸들이 아니다. 엔티티가 가진 모듈이고, 외부에는 쿼리 지점을 제공하며 내부에서는 자기 로직을 실행한다.
  • “보이지 않는 손”을 다시 등장시키지 말라: 흔한 퇴행 경로가 있다. 형식상으로는 컴포넌트를 썼지만, 실제로는 “God Component / Manager”를 만들어 모든 엔티티를 원격 조종하는 방식이다. 발표자는 이 패턴을 명확히 피해야 한다고 말한다.

7.1 컴포넌트화가 Creative device 폐기를 뜻하지는 않는다

영상은 Creative device가 이제 낡은 방식이라고 선언하지 않는다. 오히려 발표자는 매우 절제된 톤으로 중요한 점을 짚는다.

Creative devices are still incredibly incredibly useful. 발표자는 특히 mutator zones가 없다면 자신도 바다 위의 배처럼 길을 잃을 것이라고 말한다.

따라서 문맥상 다음과 같은 엔지니어링 판단을 할 수 있다. 이것은 영상 맥락에 기반한 추론이지 Epic의 공식 규정은 아니다.

  • Scene Graph(컴포넌트 구동)가 더 적합한 경우: 오브젝트가 자체 상태와 행동을 가지며, 자주 재사용되고, 런타임에 대량으로 동적 생성되는 장면. 대표적으로 플랫폼, 장치, 조명, 상호작용 오브젝트, NPC spawner가 있다.
  • Verse device(중앙 스케줄링)가 더 적합한 경우: 전역 규칙 진입점, 라운드 / 레벨 상태, 오브젝트 간 조율, 기존 Creative 장치(mutator zones, game modes 등)와 깊게 통합된 로직.
  • 혼합 방식이 현실 프로젝트의 일반적인 형태: “컴포넌트 순도”를 위해 모든 전역 규칙을 억지로 entity 하나에 밀어 넣지 말고, 반대로 mega-device 하나가 모든 로컬 행동을 계속 제어하게 두지도 말라.

8. 현재 제한과 로드맵

발표자는 마지막에 매우 솔직하게 한 가지를 설명한다. “왜 Scene Graph로 그 플랫폼 레벨 전체를 완전히 재현하지 않았는가?”

Scene Graph는 현재도 아직 노출되지 않은 저수준 컴포넌트가 있다. 특히 physics가 그렇다.

영상에서 명확히 언급된 경계는 다음과 같다.

  • 이미 노출되었거나 사용 중인 컴포넌트: transform, mesh, light, key frame movement 등.
  • Physics는 아직 진행 중이다. 특히 캐릭터와의 상호 운용에는 더 많은 저수준 작업이 필요하다. 이것이 영상에서 완전한 Scene Graph 버전 플랫폼 레벨을 시연하지 않은 핵심 이유다.
  • Fortnite characters는 최종적으로 entity + component 형태로 존재하게 될 것이지만, 단계적으로 출시될 것이다.
  • Fab의 Scene Graph 지원도 아직 개발 중이다. 이후에야 창작자 간 asset 재사용을 더 자연스럽게 이야기할 수 있을 것이다.
  • Itemization(아이템화 시스템)은 로드맵에 있으며 graph가 구동한다. 이후 출시될 예정이다.

여기서는 보수적이어야 한다. 영상은 구체적인 버전 번호, 출시 날짜, 완전한 API 목록을 제시하지 않았다. 실제 프로젝트에서 의존성을 평가할 때는 현재 사용 가능한 API를 기준으로 해야 하며, roadmap 항목을 이미 존재하는 기능처럼 취급해서는 안 된다.

9. 실전 적용 제안

영상의 큰 흐름과 엔지니어링 맥락에 기반한 판단을 합쳐, 바로 가져갈 수 있는 규칙을 정리해보자. 단, 피해야 할 점 / 베스트 프랙티스 두 부분은 영상의 의미 + 일반 엔지니어링 경험을 바탕으로 정리한 것이며 Epic의 공식 규범은 아니다.

9.1 방식 비교

  • 전통적인 device-driven 방식
    • 적합한 곳: 전역 규칙 진입점, mutator zones / 라운드제 / 전역 점수 관리, 기존 Creative 장치와 밀접하게 통합된 로직.
    • 비용: 오브젝트 행동이 중앙화되기 쉽고, 동적 생성 비용이 높으며, 확장은 보통 새 device 추가 또는 클래스 비대화를 뜻한다.
  • Scene Graph / component-driven 방식
    • 적합한 곳: 자체 행동을 가진 오브젝트(플랫폼, 장치, 조명, NPC 생성기), 고빈도 Prefab화 콘텐츠, 런타임 동적 인스턴스화.
    • 비용: 엔티티와 컴포넌트 모델링 습관을 다시 세워야 한다. 현재 노출된 컴포넌트 집합은 계속 확장 중이므로 physics / characters / Fab 같은 경계를 주의해야 한다.
  • 혼합 방식
    • 적합한 곳: 현 단계 대부분의 프로덕션 프로젝트.
    • 핵심 원칙: Scene Graph로 오브젝트를 관리하고, Verse device / Creative 장치로 전역 조율을 처리한다.

9.2 피해야 할 점

  • 예전의 “중앙 관리자 사고방식”을 그대로 컴포넌트 안으로 옮기지 말라. 컴포넌트는 엔티티의 일부여야지, “중앙 device의 원격 리모컨”이어서는 안 된다.
  • 재사용을 이유로 여러 능력을 하나의 초대형 컴포넌트에 몰아넣지 말라. 이동, 피해, 상호작용, 생성 같은 능력은 조합 가능한 작은 컴포넌트로 나눠야 한다.
  • “모든 엔진 기능이 이미 컴포넌트화되었다”고 가정하지 말라. 특히 physics, character, Fab처럼 영상에서 아직 진행 중이라고 명확히 언급한 방향은 개발 전에 실제 API를 확인해야 한다.
  • 전체 장면 쿼리를 남용하지 말라. 컴포넌트 기반 쿼리는 강력하지만, 매 프레임 전체 트리를 스캔하면 체감 가능한 비용이 생길 수 있다. 영상은 성능 데이터를 제시하지 않았으므로, 프로덕션에서는 직접 profile해야 한다.
  • Prefab을 정적인 템플릿으로만 보지 말라. Prefab의 진짜 가치는 “구조 + 컴포넌트 + 행동”을 함께 재사용하고, Prefab 레벨과 인스턴스 레벨의 두 가지 override 지점을 유지하는 데 있다.
  • 하위 호환성이 과거의 모든 작성 방식을 완전히 보호한다고 가정하지 말라. 영상은 Verse가 하위 호환성을 약속한다고 말하지만, 당신의 모든 UEFN 설계 결정이 무손실로 이전된다는 뜻은 아니다. 컴포넌트화 리팩터링을 염두에 둔다면 마이그레이션 window를 남겨둬야 한다.

9.3 베스트 프랙티스

  • 엔티티 이름은 외형만 묘사하지 말고 역할을 드러내라. 예를 들어 BlueBlock_01보다 MovingPlatform_Prefab이 장기 유지보수에 더 낫다.
  • 컴포넌트 이름은 능력을 우선해서 설명하라. AnimateToTargetsComponent, DamageOnTouchComponent, SpawnGuardsOnOverlapComponent 같은 식이다.
  • 독립적으로 재사용 가능한 오브젝트는 Prefab으로 만들고, 반드시 전역적으로 알아야 하는 규칙은 더 높은 레벨 시스템에 둔다.
  • 동적으로 생성되는 콘텐츠는 Prefab 인스턴스화 후 컴포넌트 생명주기가 자동으로 실행되는지 먼저 검증하라. 수동 setup 흐름을 조용히 다시 도입하지 않도록 한다.
  • 엔티티 간 통신은 우선 컴포넌트 쿼리 + 엔티티 계층 + 명확한 인터페이스를 사용하라. 암묵적 전역 상태로 되돌아가지 말라.
  • Verse의 트랜잭션성은 “여러 단계로 된 실패 가능 작업”의 방어 코드를 단순화하는 데 쓸 수 있다. 하지만 이것을 “아무것도 검사하지 않아도 되는 만능 방패”로 취급하지는 말라.

10. “Scene Graph dev 사고방식”의 좌표를 잡기

Scene Graph를 devices 및 다른 API와 결합하는 것을 두려워하지 말라.

발표자의 마지막 조언은 매우 명확하다. Scene Graph dev처럼 생각하기 시작하라.

실행 가능한 세 문장으로 바꾸면 이렇다.

  1. Entity는 백지다. 피와 살이 있는 “물체”가 아니다. 기존 클래스에서 잘라내는 것이 아니라, 컴포넌트로 그것이 무엇인지 결정한다.
  2. Component는 능력의 단위다. 하나의 컴포넌트는 되도록 한 가지 문제만 해결한다. 능력은 상속이 아니라 조합으로 얻는다.
  3. Verse device / Creative 장치는 여전히 유효하다. “순수 Scene Graph”를 위해 기존 도구와 싸우지 말라. 혼합 방식이 현 단계에서 가장 현실적인 경로다.

맺음말: Scene Graph 위에서 계속 무언가를 만들어보자.

발표자는 마지막에 열린 힌트도 남겼다. Scene Graph 실험 단계에서는 이미 “미친 것처럼 보이고, 심지어 게임을 crash시킬 수도 있지만, 매우 인상적인” 커뮤니티 실험들이 있었다. 엔지니어링 관점에서 이 말의 진짜 의미는 “창작자들이 더 과격해졌다”가 아니다. 오브젝트-행동의 조합 공간이 드디어 열렸다는 뜻이다.

팀 입장에서는 Prefab을 합리적으로 나누고, 컴포넌트를 절제해서 분리하며, 중앙 관리자 습관을 진짜 전역 위치로만 눌러두는 일을 빨리 시작할수록 좋다. 나중에 더 완전한 Scene Graph 워크플로로 옮겨갈 때 저항이 그만큼 작아진다.

Scene Graph와 Verse의 조합이 바꾸는 것은 “코드를 몇 줄 덜 쓴다” 같은 표면적 효율이 아니다. UEFN 프로젝트에서 오브젝트가 어떻게 정의되는가, 행동은 누구에게 속하는가, 런타임에는 어떻게 생성되는가라는 세 가지 근본 질문의 기본 답을 바꾸는 것이다.