2024.09.06
이번 글에서는 PickUpDefense
게임에서 캐릭터의 애니메이션을 C++ 코드로 관리하고, 데이터 테이블을 활용하여 다양한 캐릭터의 애니메이션을 설정하는 방법을 다룹니다. 애니메이션을 관리하는 과정에서 발생한 문제들과 해결 방법을 자세하게 설명하며, 코드 구현 과정을 공유합니다.
✅ 상단 스테이지 UI
✅ 하단 상점 UI
✅ 캐릭터 애니메이션 시스템
이번 작업에서는 각 캐릭터의 애니메이션을 관리하기 위해 데이터 테이블을 활용했습니다. 데이터 테이블을 통해 다양한 캐릭터의 걷기, 달리기, 대기(idle) 상태에 대한 애니메이션을 설정하고, 각 캐릭터가 가지고 있는 애니메이션 데이터를 쉽게 참조할 수 있도록 하였습니다.
먼저 캐릭터의 애니메이션 정보를 담을 데이터 테이블을 정의해야 합니다. 이 데이터 테이블에는 걷기, 달리기, idle 애니메이션을 정의해서 각 캐릭터의 애니메이션을 구분했습니다.
USTRUCT(BlueprintType)
struct FUnitAnimationData : public FTableRowBase
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UAnimSequence* WalkAnim;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UAnimSequence* RunAnim;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UAnimSequence* IdleAnim;
};
각 캐릭터의 애니메이션은 데이터 테이블에서 로드한 후, UCharacterAnimInstance
에 있는 변수에 애니메이션을 할당하는 방식으로 관리됩니다. 캐릭터의 애니메이션은 캐릭터가 스폰될 때마다 동적으로 설정되며, 각 캐릭터의 속성에 맞는 애니메이션이 적용됩니다.
캐릭터가 스폰될 때 해당 캐릭터의 속성에 맞는 애니메이션을 로드하고, 이를 캐릭터의 애니메이션 인스턴스에 반영하는 코드입니다. UCharacterAnimInstance
는 애니메이션 블루프린트에서 사용할 수 있도록 설정된 C++ 클래스입니다.
void ABaseUnit::InitializeUnit(const EUnitAttributeType InType, const int32 InLevel)
{
UnitAttributeType = InType;
CurrentLevel = InLevel;
// 데이터 테이블에서 애니메이션 데이터를 읽어옵니다.
UDataTable* AnimDataTable = LoadObject<UDataTable>(nullptr, TEXT("/Game/DataTable/Anim/AnimData.AnimData"));
if (!AnimDataTable) return;
// 캐릭터 속성에 맞는 애니메이션 데이터를 찾습니다.
FName RowName(*UEnum::GetDisplayValueAsText(UnitAttributeType).ToString());
FUnitAnimationData* AnimData = AnimDataTable->FindRow<FUnitAnimationData>(RowName, TEXT("Unit Animation Context"));
if (AnimData)
{
if (UCharacterAnimInstance* AnimInstance = Cast<UCharacterAnimInstance>(BaseSkeletalMeshComponent->GetAnimInstance()))
{
AnimInstance->WalkAnimation = AnimData->WalkAnim;
AnimInstance->RunAnimation = AnimData->RunAnim;
AnimInstance->IdleAnimation = AnimData->IdleAnim;
}
}
}
이 코드는 UnitAttributeType
에 맞는 애니메이션 데이터를 AnimDataTable
에서 찾아, 해당 애니메이션 데이터를 UCharacterAnimInstance
의 변수에 할당하는 구조입니다.
해당하는 부분은 Enum 클래스에서 해당하는 Value를 String으로 바꾸어서 FName에 넣는 코드입니다. Enum에서 특성을 구분하는 경우가 많은데 다음처럼 특성의 이름을 그대로 가져다 사용할 수 있으니 매우 편리합니다.
FName RowName(*UEnum::GetDisplayValueAsText(UnitAttributeType).ToString());
이 코드를 작성하면서 다음과 같은 문제들이 발생했습니다.
SkeletalMesh
를 변경할 경우, 그에 맞는 애니메이션 블루프린트가 적용되지 않는 문제를 발견했습니다. 이를 해결하기 위해, 각 캐릭터의 SkeletalMesh
에 맞는 애니메이션 블루프린트를 로드하고 설정하는 과정을 추가했습니다.이 데이터 테이블을 통해 각 캐릭터의 메시와 애니메이션 블루프린트를 설정할 수 있으며, 애니메이션의 동적 설정이 가능해집니다.
const TMap<EUnitAttributeType, FUnitMeshData> FUnitStats::UnitMeshData = {
{EUnitAttributeType::Ahri, {
LoadObject<USkeletalMesh>(nullptr, TEXT("/Game/Assets/Ahri/Ahri_gltf.Ahri_gltf")),
LoadObject<UClass>(nullptr, TEXT("/Game/Characters/ABP_Ahri.ABP_Ahri_C")),
FVector(1.f)
}},
{EUnitAttributeType::Jinx, {
LoadObject<USkeletalMesh>(nullptr, TEXT("/Game/Assets/Jinx/Jinx_gltf.Jinx_gltf")),
LoadObject<UClass>(nullptr, TEXT("/Game/Characters/ABP_Jinx.ABP_Jinx_C")),
FVector(1.f)
}}
};
캐릭터마다 다른 애니메이션을 설정해야 하는 경우, 데이터 테이블을 통해 캐릭터별로 설정된 애니메이션을 동적으로 적용할 수 있습니다. 이를 통해 코드 중복을 최소화하고, 각 캐릭터의 특성에 맞는 애니메이션을 손쉽게 설정할 수 있습니다.
다음은 각 캐릭터의 애니메이션을 데이터 테이블로 정의한 예시입니다. 이 데이터 테이블은 각각의 캐릭터가 스폰될 때 참조되어 애니메이션을 설정합니다. 각 캐릭터마다 본과 애니메이션이 다르기 때문에 각각의 캐릭터에 있는 애니메이션을 적용하고자 했습니다. 즉 애니메이션 모션은 전부 다르지만, 달리기에 해당하는 기능, Idle에 해당하는 기능은 다들 동일하니 최대한 관리를 편하게 만들고자 했습니다.
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "AnimData.generated.h"
/**
*
*/
USTRUCT(BlueprintType)
struct FAnimData : public FTableRowBase
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UAnimSequence* WalkAnim;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UAnimSequence* RunAnim;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UAnimSequence* IdleAnim;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<UAnimSequence*> AttackAnims;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TArray<UAnimSequence*> AttackAnimCriticals;
};
이번 작업을 통해 캐릭터의 애니메이션을 동적으로 설정하고, 데이터 테이블을 활용하여 각 캐릭터마다 다른 애니메이션을 할당하는 방법을 구현했습니다. 이를 통해 코드 중복을 최소화하고, 다양한 캐릭터의 애니메이션을 효과적으로 관리할 수 있게 되었습니다.
향후 작업에서는 캐릭터의 전투 애니메이션을 추가하고, UI와 상호작용하는 부분을 더 개선할 계획입니다. 이번 글이 언리얼 엔진에서 애니메이션을 다루는 데 도움이 되길 바랍니다.
감사합니다!