애니메이션 블루프린트 기초
애니메이션 블루프린트는 언리얼 엔진에서 캐릭터의 복잡한 애니메이션 로직을 시각적으로 구현할 수 있게 해주는 강력한 도구입니다.
이 절에서는 애니메이션 블루프린트의 기본 구조와 C++에서 이를 제어하고 확장하는 방법을 살펴보겠습니다.
애니메이션 블루프린트의 기본 구조
애니메이션 블루프린트는 크게 애님 그래프, 이벤트 그래프, 그리고 스테이트 머신으로 구성됩니다.
애님 그래프
애님 그래프는 포즈를 계산하고 블렌딩하는 주요 부분입니다.
C++에서 애님 그래프의 결과에 접근하려면 다음과 같이 할 수 있습니다.
UCLASS()
class UMyAnimInstance : public UAnimInstance
{
GENERATED_BODY()
public:
virtual void NativeUpdateAnimation(float DeltaSeconds) override;
private:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Animation", meta = (AllowPrivateAccess = "true"))
float Speed;
};
void UMyAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
APawn* Pawn = TryGetPawnOwner();
if (Pawn)
{
Speed = Pawn->GetVelocity().Size();
}
}
스테이트 머신
스테이트 머신은 캐릭터의 다양한 상태를 관리합니다.
C++에서 현재 스테이트를 확인하거나 변경하려면,
UCLASS()
class UMyAnimInstance : public UAnimInstance
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Animation")
void SetCurrentState(FName NewState);
UFUNCTION(BlueprintPure, Category = "Animation")
FName GetCurrentState() const;
private:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Animation", meta = (AllowPrivateAccess = "true"))
FName CurrentState;
};
void UMyAnimInstance::SetCurrentState(FName NewState)
{
CurrentState = NewState;
}
FName UMyAnimInstance::GetCurrentState() const
{
return CurrentState;
}
블렌드 스페이스
블렌드 스페이스는 여러 애니메이션을 부드럽게 혼합합니다.
C++에서 블렌드 스페이스 파라미터를 조정하려면,
UCLASS()
class UMyAnimInstance : public UAnimInstance
{
GENERATED_BODY()
public:
virtual void NativeUpdateAnimation(float DeltaSeconds) override;
private:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Animation", meta = (AllowPrivateAccess = "true"))
float DirectionAngle;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Animation", meta = (AllowPrivateAccess = "true"))
float Speed;
};
void UMyAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
APawn* Pawn = TryGetPawnOwner();
if (Pawn)
{
FVector Velocity = Pawn->GetVelocity();
Speed = Velocity.Size();
DirectionAngle = FMath::Atan2(Velocity.Y, Velocity.X);
}
}
C++에서 커스텀 애니메이션 노드 생성
커스텀 애니메이션 노드를 생성하여 애니메이션 블루프린트의 기능을 확장할 수 있습니다.
UCLASS()
class MYGAME_API UAnimNode_MyCustomNode : public UAnimNode_Base
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Links)
FPoseLink BasePose;
virtual void Initialize_AnyThread(const FAnimationInitializeContext& Context) override;
virtual void CacheBones_AnyThread(const FAnimationCacheBonesContext& Context) override;
virtual void Update_AnyThread(const FAnimationUpdateContext& Context) override;
virtual void Evaluate_AnyThread(FPoseContext& Output) override;
private:
// 커스텀 로직을 위한 변수들
};
void UAnimNode_MyCustomNode::Evaluate_AnyThread(FPoseContext& Output)
{
BasePose.Evaluate(Output);
// 여기에 포즈 수정 로직 추가
}
인스턴스 접근 및 변수 조작
게임플레이 코드에서 애니메이션 블루프린트 인스턴스에 접근하고 변수를 조작하는 방법
UCLASS()
class AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
void UpdateAnimationState();
private:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Animation", meta = (AllowPrivateAccess = "true"))
UMyAnimInstance* AnimInstance;
};
void AMyCharacter::UpdateAnimationState()
{
AnimInstance = Cast<UMyAnimInstance>(GetMesh()->GetAnimInstance());
if (AnimInstance)
{
AnimInstance->SetCurrentState(FName("Running"));
// 다른 변수들도 여기서 업데이트
}
}
게임플레이 코드와의 효과적인 연동
- 이벤트 기반 통신
UCLASS()
class UMyAnimInstance : public UAnimInstance
{
GENERATED_BODY()
public:
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnAnimationEventSignature);
UPROPERTY(BlueprintAssignable, Category = "Animation")
FOnAnimationEventSignature OnJumpStart;
UFUNCTION(BlueprintCallable, Category = "Animation")
void TriggerJumpStart();
};
void UMyAnimInstance::TriggerJumpStart()
{
OnJumpStart.Broadcast();
}
- 인터페이스를 통한 통신
UINTERFACE(MinimalAPI, Blueprintable)
class UAnimationCommunicationInterface : public UInterface
{
GENERATED_BODY()
};
class IAnimationCommunicationInterface
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Animation")
void OnAnimationEvent(FName EventName);
};
애니메이션 시스템의 성능 최적화 기법
- LOD (Level of Detail) 시스템 활용
UCLASS()
class UMyAnimInstance : public UAnimInstance
{
GENERATED_BODY()
public:
virtual void NativeUpdateAnimation(float DeltaSeconds) override;
private:
void UpdateLOD();
};
void UMyAnimInstance::UpdateLOD()
{
USkeletalMeshComponent* MeshComponent = GetOwningComponent();
if (MeshComponent)
{
int32 LODLevel = MeshComponent->GetPredictedLODLevel();
// LOD 레벨에 따라 애니메이션 복잡도 조절
}
}
- 애니메이션 압축 설정
void AMyCharacter::SetupAnimationCompression()
{
UAnimSequence* AnimSequence = LoadObject<UAnimSequence>(nullptr, TEXT("/Game/Animations/MyAnimation"));
if (AnimSequence)
{
AnimSequence->CompressionSettings.TranslationCompressionFormat = ACF_Float96NoW;
AnimSequence->CompressionSettings.RotationCompressionFormat = ACF_Float96NoW;
AnimSequence->CompressionSettings.ScaleCompressionFormat = ACF_Float96NoW;
AnimSequence->RequestSyncAnimRecompression();
}
}
복잡한 애니메이션 로직의 디버깅 방법
- 로깅 활용
void UMyAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
UE_LOG(LogAnimation, Verbose, TEXT("Current State: %s, Speed: %f"), *GetCurrentState().ToString(), Speed);
}
- 비주얼 디버깅
void UMyAnimInstance::DrawDebug(UCanvas* Canvas, APlayerController* Controller)
{
Super::DrawDebug(Canvas, Controller);
FVector2D ScreenPosition(50.0f, 50.0f);
FString DebugString = FString::Printf(TEXT("Current State: %s"), *GetCurrentState().ToString());
FCanvasTextItem TextItem(ScreenPosition, FText::FromString(DebugString), GEngine->GetSmallFont(), FLinearColor::White);
Canvas->DrawItem(TextItem);
}
프로젝트에서의 애니메이션 관리 전략
1. 모듈화
애니메이션 로직을 재사용 가능한 작은 단위로 분리합니다.
UCLASS()
class UAnimationModule_Locomotion : public UObject
{
GENERATED_BODY()
public:
void UpdateLocomotion(UMyAnimInstance* AnimInstance);
};
void UAnimationModule_Locomotion::UpdateLocomotion(UMyAnimInstance* AnimInstance)
{
// 이동 관련 애니메이션 로직
}
2. 데이터 주도 설계
애니메이션 설정을 데이터 에셋으로 관리합니다.
UCLASS()
class UAnimationConfig : public UDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, Category = "Animation")
float WalkSpeed;
UPROPERTY(EditAnywhere, Category = "Animation")
float RunSpeed;
UPROPERTY(EditAnywhere, Category = "Animation")
UBlendSpace* LocomotionBlendSpace;
};
3. 버전 관리 및 에셋 종속성 추적
애니메이션 에셋의 버전을 관리하고 종속성을 추적합니다.
UCLASS()
class UAnimationVersionManager : public UObject
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Animation")
bool IsAnimationVersionCompatible(UAnimSequence* Animation, int32 RequiredVersion);
UFUNCTION(BlueprintCallable, Category = "Animation")
TArray<UAnimSequence*> GetDependentAnimations(UAnimSequence* Animation);
};
애니메이션 블루프린트는 언리얼 엔진의 강력한 기능 중 하나로, 복잡한 애니메이션 로직을 효과적으로 구현할 수 있게 해줍니다.
C++와의 연동을 통해 더욱 강력하고 유연한 애니메이션 시스템을 구축할 수 있습니다.