Unreal) AssetManager
DataAsset이란 무엇인가?
DataAsset은 언리얼 엔진에서 사용하는 데이터 컨테이너(Data Container) 애셋이다.
게임플레이 코드나 로직 없이, 정적 데이터(static data)의 묶음을 저장하는 용도로 특화되어 있다.
액터나 컴포넌트처럼 월드에 배치되거나 틱(Tick)을 실행하는 객체가 아니라, 순수하게 데이터를 담는 템플릿 또는 스펙 시트(spec sheet)와 같은 역할을 한다.
예를 들어, WeaponData
라는 데이터 애셋을 만들고 그 안에 공격력, 연사 속도, 탄약 종류, 무기 메시 등 무기와 관련된 모든 데이터를 정의할 수 있다.
이렇게 생성된 DA_Rifle
, DA_Pistol
등의 애셋들은 여러 캐릭터나 시스템에서 참조하여 해당 무기의 데이터를 일관되게 사용할 수 있도록 해준다.
DataAsset의 주요 장점
- 데이터와 로직의 분리:
- 게임의 핵심 로직(C++ 또는 블루프린트)과 실제 데이터 값(DataAsset)을 명확하게 분리할 수 있다.
- 프로그래머는 데이터의 구조(뼈대)를 정의하고, 기획자나 디자이너는 코드를 건드리지 않고 에디터에서 데이터 애셋의 값을 직접 수정하며 밸런싱 작업을 할 수 있다.
- 재사용성 및 일관성:
- 하나의 잘 정의된 데이터 애셋은 게임 내 여러 곳에서 참조될 수 있다.
- 예를 들어 ‘철검’ 데이터 애셋의 공격력을 수정하면, 게임 내 모든 ‘철검’ 아이템의 공격력이 즉시 일괄적으로 변경되어 데이터의 일관성을 유지하기 쉽다.
- 직관적인 데이터 관리:
- CSV 파일이나 복잡한 데이터 테이블에 비해, 언리얼 에디터에 완벽하게 통합된 UI를 통해 데이터를 훨씬 직관적으로 편집하고 관리할 수 있다.
- 성능:
- 데이터 애셋은 가벼운
UObject
이므로, 필요할 때 로드하고 참조하는 비용이 낮다. - 게임 시작 시 모든 데이터를 하드코딩하거나 거대한 테이블을 파싱하는 방식보다 효율적이다.
- 데이터 애셋은 가벼운
C++을 이용한 DataAsset 정의 및 사용
데이터 애셋 클래스 정의 (.h 파일)
먼저 UDataAsset
을 상속받는 새로운 C++ 클래스를 생성한다.
이 클래스는 데이터의 ‘틀’이 되며, 저장하고 싶은 변수들을 UPROPERTY
로 선언한다.
R1WeaponData.h
예시:
UCLASS(BlueprintType)
class YOURPROJECT_API UR1WeaponData : public UDataAsset
{
GENERATED_BODY()
public:
// 무기의 공격력
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stats")
float Damage;
// 초당 발사 속도
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Stats")
float FireRate;
// 표시될 무기 스켈레탈 메시
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Visuals")
TObjectPtr<class USkeletalMesh> WeaponMesh;
};
DataAsset은 순수하게 데이터를 담는 용도이므로, 특별한 기능이 추가되지 않는 한 .cpp
파일은 비어있는 경우가 많다.
에디터에서 데이터 애셋 생성 및 활용
C++ 코드를 컴파일한 후, 언리얼 에디터의 콘텐츠 브라우저에서 이 클래스를 기반으로 실제 데이터 애셋을 생성할 수 있다.
- 콘텐츠 브라우저에서 우클릭 -> 기타(Miscellaneous) -> 데이터 애셋(Data Asset)을 선택한다.
- 부모 클래스를 선택하는 창이 나타나면, 방금 생성한 C++ 클래스(
R1WeaponData
)를 선택한다. DA_Rifle
과 같이 새로운 애셋의 이름을 지정한다.- 생성된 애셋을 더블클릭하면,
.h
파일에UPROPERTY
로 선언했던 변수들(Damage, FireRate, WeaponMesh 등)을 편집할 수 있는 창이 나타난다. 디자이너는 이 창에서 각 무기에 맞는 데이터를 입력한다.
Blueprint/C++에서 데이터 애셋 참조
생성된 데이터 애셋은 다른 액터나 컴포넌트에서 변수로 참조하여 사용할 수 있다.
R1Weapon.h
(무기를 장착하는 액터) 예시:
// ...
public:
// 에디터에서 어떤 무기 데이터를 사용할지 지정할 수 있는 변수
UPROPERTY(EditAnywhere, Category = "Config")
TObjectPtr<class UR1WeaponData> WeaponData;
void Fire();
// ...
R1Weapon.cpp
예시:
void AR1Weapon::Fire()
{
if (WeaponData)
{
// 데이터 애셋에 저장된 값을 읽어와서 사용한다.
const float CurrentDamage = WeaponData->Damage;
const float CurrentFireRate = WeaponData->FireRate;
// ... 발사 로직 수행 ...
UE_LOG(LogTemp, Warning, TEXT("Damage: %f, FireRate: %f"), CurrentDamage, CurrentFireRate);
}
}
이제 에디터에서 이 AR1Weapon
액터의 디테일 패널을 보면 WeaponData
슬롯이 있고, 여기에 앞서 생성한 DA_Rifle
애셋을 할당하면, Fire()
함수가 호출될 때 DA_Rifle
에 정의된 데이터가 사용된다.
결론
DataAsset은 게임 데이터를 코드로부터 분리하여, 프로젝트의 유연성과 협업 효율성을 극대화하는 핵심적인 기능이다.
GameplayTag가 개념을 ‘식별’하고 ‘분류’하는 이름표 역할을 한다면, DataAsset은 그 이름표에 해당하는 구체적인 ‘내용물’과 ‘속성’을 담는 그릇의 역할을 한다.
이 둘을 함께 사용하면 매우 강력하고 체계적인 게임플레이 시스템을 구축할 수 있다.
댓글남기기