[Unreal Engine] Data Definition & Instance

이매·2026년 3월 24일

Unreal Data Driven Design

목록 보기
7/12
post-thumbnail

1. Static Data & Runtime Data

게임에서 데이터를 다루다 보면, 실행 중에도 변하지 않는 데이터와 실행 중 지속적으로 변화하는 데이터를 명확히 구분할 필요가 있다.

일반적으로 프로그래밍에서 Static 데이터는 런타임 동안 값이 변하지 않거나 초기 상태를 유지하는 데이터를 의미하며, 반대로 Dynamic(또는 Runtime) 데이터는 실행 중 생성되거나 변경될 수 있는 데이터를 의미한다.

특히 게임에서는 이러한 구분이 더욱 중요해진다. 게임 내 오브젝트 수는 생성·소멸되며 상태가 계속 변하기 때문에, 동적인 데이터 구조는 게임 상태와 상호작용을 관리하는 데 핵심적인 역할을 한다고 알려져 있다.

Unreal Engine과 같은 게임 엔진에서는 이러한 데이터 구분이 설계 수준에서 확장되어, 아이템이나 캐릭터의 “정의 데이터(Data Definition)”와 실제 게임 내에서 변화하는 “상태 데이터(Instance)”를 분리하는 방식이 일반적으로 사용된다.

Data Definition과 Data Instance란 용어는 편의상 임의로 붙인 용어입니다. 이러한 개념에 대해서는 사람마다 용어는 다르게 쓰일 수 있다.

1-1. Data Definition

Data Definition이란 게임에서 사용되는 데이터의 “기준 값”을 정의하는 영역이다. 캐릭터의 기본 능력치, 아이템의 효과 수치, 스킬의 계수와 같이 여러 객체에서 공통적으로 참조되는 데이터를 의미한다.

일반적으로 소프트웨어 공학에서 “정의(Definition)”는 특정 객체나 시스템이 가져야 할 속성과 값을 미리 규정하는 것을 의미하며, 이는 실제 실행 시 생성되는 객체와 구분되는 개념이다.

게임 개발에서도 이러한 개념은 동일하게 적용되며, Data Definition은 개별 객체의 상태를 직접 저장하는 것이 아니라, 객체가 생성될 때 참조되는 기준 데이터를 제공하는 역할을 한다. 즉, Definition은 데이터를 “사용하는 대상”이 아니라 여러 객체가 공유하는 참조 기준으로 동작한다.

Unreal Engine에서도 캐릭터나 아이템의 기본 정보는 Data Table이나 Data Asset에서 별도의 데이터로 정의되고, 실제 게임 객체는 이를 참조하여 초기화 및 동작을 수행하는 구조를 가진다.

1-2. Data Instance

Data Instance는 Data Definition을 기반으로 생성되어 실제 게임에서 사용되는 데이터의 실행 상태를 의미한다. 캐릭터의 현재 HP, 버프 상태, 쿨타임과 같이 게임 플레이 중 지속적으로 변화하는 값을 포함하는 영역이다.

일반적으로 컴퓨터 과학에서 Instance는 클래스나 템플릿과 같은 정의로부터 생성된 실제 객체를 의미하며, 각 Instance는 동일한 구조를 가지면서도 서로 다른 상태를 가질 수 있다.

게임 개발에서도 이 개념은 동일하게 적용되며, Data Instance는 Definition을 기반으로 생성되지만 각 객체마다 독립적인 상태를 유지하고 실행 중 지속적으로 변경된다. 즉, 동일한 Definition을 사용하더라도 각각의 Instance는 서로 다른 값을 가지며 게임 상태를 표현한다.

Unreal Engine에서도 이러한 구조는 Actor나 Component와 같은 런타임 객체를 통해 나타나며, 실제 게임 내 캐릭터나 오브젝트는 각각 독립적인 상태를 가지는 Instance로 동작한다.

1-3. Definition → Instance 생성 흐름

Data Definition과 Data Instance는 단순히 구분되는 개념이 아니라, 실제 게임 실행 과정에서 서로 연결되어 동작하는 구조를 가진다. 일반적으로 Instance는 Definition을 기반으로 생성되며, 이 과정에서 데이터를 복사하여 사용할 것인지, 참조하여 사용할 것인지에 대한 설계가 필요하다.

Definition → Instance 생성 과정은 일반적으로 다음과 같은 흐름을 가진다.

  1. Definition 데이터 로드
  2. Instance 생성
  3. Definition 값을 기반으로 Instance 초기화

이때 중요한 설계 포인트는

  • Definition 데이터를 직접 참조할 것인지
  • Instance 내부에 값을 복사하여 사용할 것인지

이다.

복사 방식의 경우, Instance는 Definition의 값을 초기값으로 가져온 뒤 독립적으로 값을 변경한다.

반면 참조 방식의 경우, Definition 데이터를 그대로 참조하기 때문에 Definition이 변경되면 모든 Instance에 영향을 줄 수 있다.

이러한 특성 때문에, 일반적인 게임 상태 데이터는 복사 기반으로 초기화하는 방식이 널리 사용된다. 다만, 참조 방식은 모든 상황에서 잘못된 것은 아니다. 예를 들어 변하지 않는 설정값이나 공통 리소스의 경우에는 참조를 통해 메모리 사용을 줄이고 일관성을 유지하는 방식이 사용되기도 한다.

Unreal Engine에서도 이러한 구조와 고민은 유사하게 표현되며, DataAsset이나 DataTable과 같은 Definition 데이터를 기반으로 Actor나 Component가 생성되고, 이후에는 각 Instance가 독립적인 상태를 가지도록 동작한다.

1-3-1. 주의 사항

Definition과 Instance를 분리하지 않고 설계할 경우, 가장 대표적인 문제는 Definition 데이터의 변경이 모든 객체에 영향을 미치는 현상이다.

비슷한 예시로 Definition과 Instance를 분리하지 않았을 때의 문제는 UI에서도 쉽게 발생한다.

예를 들어 하나의 HP Bar 위젯을 생성한 뒤, 이를 여러 캐릭터에 Instance로 나누지 않고 동일 객체를 공유하도록 설계했다고 가정한다. 이 경우 특정 캐릭터가 데미지를 받아 HP 값이 변경되면, 동일한 위젯을 참조하는 모든 캐릭터의 HP Bar가 동시에 변경되는 현상이 발생한다.

이는 여러 객체가 하나의 상태를 공유하는 공유 상태(shared state) 문제와 동일한 유형이며, 하나의 변경이 모든 사용자에게 영향을 미칠 수 있는 구조적 문제로 알려져 있다.



2. Data Flow

Data Definition이 DataTable이나 DataAsset 혹은 다른 무언가의 형태로 정의되었다면, 다음으로 중요한 것은 해당 데이터가

  • 어디서 로드될 것인가?
  • 어디서 관리될 것인가?
  • 어디서 실제로 사용되는가?

에 대한 책임을 명확히 구분하는 것이다.

이러한 개념은 일반적으로 데이터의 Ownership(소유)과 Responsibility(책임)으로 표현한다.
즉, 특정 데이터에 대해 어디서 로드하는지, 누가 해당 데이터를 소유하는지, 그리고 어디서 실제로 사용하는지를 명확하게 구분하는 것이 중요하다.

사실 이러한 부분에서 Unreal Engine에서 이러한 역할 분리를 반드시 강제하는 규칙은 존재하지 않으며, 프로젝트 구조에 따라 다양한 방식으로 구현될 수 있다.

2-1. Loading Responsibility

데이터 로딩 책임(Loading Responsibility)은 Data Definition을 언제, 어디서, 어떤 주체가 메모리에 올리는지를 결정하는 역할이다.

Unreal Engine에서는 Asset Manager를 통해 에셋 로딩을 중앙에서 관리할 수 있으며, 특히 Primary Asset 시스템을 이용하면 필요한 시점에 데이터를 비동기로 로드하는 구조를 구성할 수 있다.

또한 Soft Reference는 에셋을 즉시 로드하지 않고, 필요한 시점에 로드하도록 지연시키는 방식을 제공한다. 이를 통해 초기 로딩 비용을 줄이고 메모리 사용을 최적화할 수 있다.

Asset ManagerAsync Loading은 이전 포스팅을 참고

이러한 시스템을 기반으로 실제 프로젝트에서는 GameInstance나 Subsystem과 같은 전역 초기화 지점에서 데이터를 로드하는 방식이 사용될 수 있다.

GameInstance에서의 데이터 로딩 예시

GameInstance는 게임 실행 시 가장 먼저 생성되는 객체 중 하나이기 때문에, 초기 데이터 로딩을 담당하는 위치로 사용되기 좋다.

UCLASS()
class UMyGameInstance : public UGameInstance
{
    GENERATED_BODY()

public:
    virtual void Init() override;

private:
    UPROPERTY()
    UPrimaryDataAsset* CharacterData;
};
void UMyGameInstance::Init()
{
    Super::Init();

    // Soft Reference 경로
    TSoftObjectPtr<UPrimaryDataAsset> DataRef(
        FSoftObjectPath(TEXT("/Game/Data/DA_Character.DA_Character"))
    );

    // 동기 로드 (예시)
    CharacterData = DataRef.LoadSynchronous();
}

2-2. Data Ownership

Data Ownership은 로드된 데이터(Data Instance)를 어떤 객체가 보관하고, 어떤 범위에서 접근을 허용할 것인지에 대한 책임 구조를 의미한다.

이러한 개념은 멀티플레이 환경에서도 중요한 개념인데 Unreal Engine의 멀티플레이 환경에서는 기본적으로 서버가 authoritative(권한 보유) 주체로 동작하며, 클라이언트는 서버의 상태를 복제(Replication) 받아 사용하는 구조를 따른다.

2-3. Using Data

이제 Data Definition으로부터 생성된 Data Instance를 실제 게임 로직에서 활용하는 단계를 알아보자.

Unreal Engine에서는 주로 Actor 또는 ActorComponent가 이러한 데이터를 소비하는 주체가 되며, 게임 내의 모든 상태 변화와 로직 처리는 이 계층에서 이루어진다. Actor는 게임 세계에 존재하는 객체의 기본 단위이며, Component를 통해 기능을 확장하는 구조를 가진다.

그래서 일반적으로 앞서 정의된 Data Definition(DataAsset, DataTable 등)은 Actor와 Component에서 Instance 형태로 변환되어 실제 게임 상태로 사용된다.

Actor에서의 데이터 활용 예시

UCLASS()
class AMyCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    UPROPERTY(Replicated)
    float CurrentHP;

    void InitializeFromData(const FCharacterData& Data);
};
void AMyCharacter::InitializeFromData(const FCharacterData& Data)
{
    CurrentHP = Data.MaxHP;
}

2-4. Data Usecase Flow

결론적으로 데이터 기반 설계 방식에서 일반적으로 전체 흐름은 다음과 같이 정리될 수 있다.

  1. Data Definition (DataAsset / DataTable)
  2. Loading 및 Ownership (GameInstance / Subsystem)
  3. 사용 주체(Actor 등)에서 Instance 생성
  4. 사용 주체에서 Instance를 실제 사용

profile
언리얼 엔진 주니어(신입) 개발자 | 소설 쓰는 취준 개발자

0개의 댓글