[Unreal Engine 5] DataAsset VS PrimaryDataAsset

2026. 2. 20. 20:57·프로그래밍/Unreal Engine 5

1. 개념/설계: DataAsset vs PrimaryDataAsset

가장 중요한 핵심은 "언리얼 엔진의 '에셋 매니저(Asset Manager)'가 이 데이터를 어떻게 추적하고 로드하는가?"이다.

  • UDataAsset (데이터 에셋):
    • 단순한 데이터 보관함.
    • 에셋 매니저가 고유 ID로 추적하지 않는다.
    • 주로 다른 블루프린트나 C++ 클래스에서 하드 레퍼런스(Hard Reference)로 직접 연결해서 사용할 때 적합하다. (예: 특정 캐릭터가 항상 고정적으로 들고 있는 기본 무기 스탯)
  • UPrimaryDataAsset (프라이머리 데이터 에셋):
    • UDataAsset을 상속받은 특수한 보관함으로, 고유한 주민등록번호(PrimaryAssetId)를 가진다.
    • 게임이 시작될 때 언리얼의 에셋 매니저가 이 에셋들의 목록을 쫙 스캔해서 카탈로그를 만든다.
    • 데이터가 필요할 때 메모리에 무겁게 미리 올려두지 않고, ID를 통해 비동기 로딩(Async Loading)을 하거나 소프트 레퍼런스(Soft Reference)로 관리할 때 압도적으로 유리하다. 수백 개의 아이템이 존재하는 RPG의 인벤토리 시스템 등에 필수적.


2. 헤더 (.h) 구현

이제 실제 RPG 게임의 '무기 아이템' 데이터를 만든다고 가정하고 코드를 작성해 보겠습니다. 무기 아이템은 많아질 수 있으므로 UPrimaryDataAsset을 사용하는 것이 모범 답안입니다.

RPGWeaponItem.h

#pragma once

#include "CoreMinimal.h"
#include "Engine/DataAsset.h" // UPrimaryDataAsset이 포함된 헤더
#include "RPGWeaponItem.generated.h"

// Forward Declaration (전방 선언): 컴파일 시간 최적화를 위해 헤더 include를 최소화합니다.
class UTexture2D;
class UStaticMesh;

/**
 * 무기 아이템 데이터를 정의하는 Primary Data Asset 클래스입니다.
 */
UCLASS(BlueprintType)
class YOURGAME_API URPGWeaponItem : public UPrimaryDataAsset
{
    GENERATED_BODY()

public:
    // 에셋 매니저가 이 에셋을 고유하게 식별하기 위해 반드시 오버라이드해야 하는 함수입니다.
    virtual FPrimaryAssetId GetPrimaryAssetId() const override;

public:
    // TEXT() 매크로를 사용하지 않는 순수 식별자용 문자열이므로 FName을 사용합니다.
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Info")
    FName ItemName;

    // 공격력 같은 수치 데이터
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Stats")
    int32 AttackPower;

    // 메모리 최적화를 위해 하드 레퍼런스(UTexture2D*) 대신 소프트 레퍼런스 사용!
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Visual")
    TSoftObjectPtr<UTexture2D> ItemIcon;

    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Visual")
    TSoftObjectPtr<UStaticMesh> WeaponMesh;
};

💡 Rider IDE 팁 (VS 2022 키맵):

  • UPrimaryDataAsset이 정확히 어떤 기능을 갖는지 궁금하다면 커서를 올리고 F12 (정의로 이동)를 눌러 엔진 코드를 확인해 보세요.
  • GetPrimaryAssetId()를 타이핑하다가 Alt + Enter를 누르면 Rider가 선언 및 C++ 구현부까지 자동으로 생성해 주어 생산성이 크게 오릅니다.

3. 소스 (.cpp) 구현

RPGWeaponItem.cpp

#include "RPGWeaponItem.h"
// 구조화된 로그(Structured Logging)를 위해 추가합니다. Build.cs에 꼭 추가할 필요는 없지만 Core에 포함되어 있습니다.
#include "Logging/StructuredLog.h" 

FPrimaryAssetId URPGWeaponItem::GetPrimaryAssetId() const
{
    // "Weapon"이라는 타입 이름과, 현재 에셋의 이름(GetFName)을 조합하여 고유 ID를 생성합니다.
    // 예: Weapon:Sword_Basic
    FPrimaryAssetId AssetId = FPrimaryAssetId(FPrimaryAssetType("Weapon"), GetFName());

    // 디버깅을 위한 최신 UE5 로그 포맷 사용 예시
    // UE_LOGFMT(LogTemp, Log, "Weapon Asset ID Generated: {0}", AssetId.ToString());

    return AssetId;
}

4. 에디터 설정 (필수!)

코드를 컴파일(Ctrl + Shift + B)하고 에디터로 돌아왔다면, 에셋 매니저에게 *"Weapon이라는 타입의 에셋을 찾아라!"*라고 알려주어야 합니다.

  1. 언리얼 에디터에서 편집(Edit) -> 프로젝트 세팅(Project Settings)을 엽니다.
  2. 좌측 패널에서 Game -> Asset Manager (에셋 매니저)를 클릭합니다.
  3. Primary Asset Types to Scan (스캔할 프라이머리 에셋 타입) 배열에 항목을 추가(+)합니다.
  4. Primary Asset Type에 우리가 코드에 적은 "Weapon"을 입력합니다.
  5. Asset Base Class에 우리가 만든 RPGWeaponItem을 선택합니다.
  6. Directories에 이 데이터 에셋들을 저장할 폴더(예: /Game/Data/Weapons)를 지정해 줍니다.

이렇게 하면 게임 로딩 시 엔진이 해당 폴더를 가볍게 스캔하여 카탈로그를 완성합니다!


⚠️ 시니어의 추가 조언 (메모리와 참조)

만약 UPrimaryDataAsset 안에 UTexture2D* MyIcon; 처럼 포인터로(하드 레퍼런스) 이미지를 연결해 두었다면, 이 데이터 에셋이 메모리에 올라오는 순간 아이콘 텍스처와 무기 메쉬까지 전부 한 번에 메모리에 강제로 올라오게 됩니다. 수십 개의 무기가 있다면 심각한 메모리 낭비와 긴 로딩 타임(히치 현상)을 유발하죠.

따라서 위 코드처럼 반드시 TSoftObjectPtr을 사용하여 경로만 가지고 있다가, 플레이어가 장비창을 열 때 등 진짜 필요할 때만 비동기로 로드(Async Load)하는 습관을 들이셔야 합니다.


개념이 조금 명확해지셨나요?
이 데이터를 바탕으로 실제 인벤토리를 구현하실 계획이신가요? 혹시 C++에서 이 Soft Reference를 어떻게 비동기(Async)로 랙 없이 로드하는지 다음 단계가 궁금하시다면 말씀해 주세요!

'프로그래밍 > Unreal Engine 5' 카테고리의 다른 글

[Unreal Engine 5] 동기(Synchronous) VS 비동기(Asynchronous)  (0) 2026.03.09
[Unreal Engine 5] 언리얼 엔진 인풋(Input) 아키텍처 파헤치기: F4 vs Lyra 비교 및 CS 관점의 동작 원리  (0) 2026.03.05
[Unreal Engine 5] Unreal Engine 5 VS Schmetterling Engine 2.0  (0) 2026.02.05
[Unreal Engine 5] UFUNCTION()와 지정자(Specfier)들  (0) 2026.01.29
[Unreal Engine 5] GAS(Gameplay Ability System)  (0) 2026.01.26
'프로그래밍/Unreal Engine 5' 카테고리의 다른 글
  • [Unreal Engine 5] 동기(Synchronous) VS 비동기(Asynchronous)
  • [Unreal Engine 5] 언리얼 엔진 인풋(Input) 아키텍처 파헤치기: F4 vs Lyra 비교 및 CS 관점의 동작 원리
  • [Unreal Engine 5] Unreal Engine 5 VS Schmetterling Engine 2.0
  • [Unreal Engine 5] UFUNCTION()와 지정자(Specfier)들
hanong8
hanong8
hanong8 님의 블로그 입니다.
  • hanong8
    HaNong
    hanong8
  • 전체
    오늘
    어제
    • 분류 전체보기 (102) N
      • 프로그래밍 (99) N
        • Unreal Engine 5 (45)
        • C++ (22)
        • UML (2)
        • 자료구조 (2)
        • 알고리즘 (9)
        • 개발일지 (4)
        • DirectX11 (5)
        • Git (2)
        • 코드카타 (8) N
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
hanong8
[Unreal Engine 5] DataAsset VS PrimaryDataAsset
상단으로

티스토리툴바