BossFight - AnimLayer를 통한 애니메이션 제어

김대겸·2025년 4월 3일

AnimLayer를 통한 애니메이션 제어

이번에 만들 게임에서는 대기소에서 무기를 선택하는 기능이 있다. 이때 각 무기마다, 애니메이션이 변경 되도록 할 계획이다.

그러나 매번 새로운 AnimBlueprint를 사용하는 것은 번거롭기 때문에 AnimLayer를 통해 수월하게 애니메이션의 변경을 할수있도록 구현 해보자.

우선 캐릭터의 AnimInstance를 생성 해보자.

AnimInstance의 구조는 아래와 같다

< AnimInstance 구조 >

UBFBaseAnimInstance -> 모든AnimInstance의 기초 Class
UBFCharacterAnimInstance -> UBFBaseAnimInstance를 상속받은 Character의 애님 인스턴스 Class
UBFPlayerAnimInstance -> 플레이어의 AnimInstance(UBFCharacterAnimInstance 상속)
UBFEnemyAnimInstance -> 적 캐릭터의 AnimInstance(UBFCharacterAnimInstance 상속) (* 추가 예정)

이제 본격저으로 코드를 작성 해보자

🎮 UBFBaseAnimInstance.h

UCLASS()
class BOSSFIGHT_API UBFBaseAnimInstance : public UAnimInstance
{
	GENERATED_BODY()
protected:
	UFUNCTION(BlueprintPure, meta = (BlueprintThreadSafe))
	bool DoseOwnerHasTag(FGameplayTag TagToCheck) const;
};

🎮 UBFBaseAnimInstance.cpp

bool UBFBaseAnimInstance::DoseOwnerHasTag(FGameplayTag TagToCheck) const
{
	if (APawn* OwningPawn = TryGetPawnOwner())
	{
		return UBFFunctionLibrary::NativeDoseActorHaveTag(OwningPawn, TagToCheck);
	}
	return false;
}

Base에서는 큰 기능을 추가하지는 않고 현재 OwningPawn에 특정 Tag가 있는지 확인하는 기능만 추가하였다. 앞으로 몇몇 상황에서는 Tag를 통해 애니메이션을 제어 할 것이다.

🎮 UBFCharacterAnimInstance.h

class ABFBaseCharacter;
class UCharacterMovementComponent;

UCLASS()
class BOSSFIGHT_API UBFCharacterAnimInstance : public UBFBaseAnimInstance
{
	GENERATED_BODY()

public:
	virtual void NativeInitializeAnimation() override;
	virtual void NativeThreadSafeUpdateAnimation(float DeltaSeconds)override;

protected:
	UPROPERTY()
	ABFBaseCharacter* OwningCharacter;

	UPROPERTY()
	UCharacterMovementComponent* OwningMovementComponent;

	UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Anim Data | LocomationData")
	float GroundSpeed;

	UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Anim Data | LocomationData")
	bool bHasAcceleration;

	UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Anim Data | LocomationData")
	float LocomationDirection;
};

🎮 UBFCharacterAnimInstance.cpp

void UBFCharacterAnimInstance::NativeInitializeAnimation()
{
	OwningCharacter = Cast<ABFBaseCharacter>(TryGetPawnOwner());

	if (OwningCharacter)
	{
		OwningMovementComponent = OwningCharacter->GetCharacterMovement();
	}
}

void UBFCharacterAnimInstance::NativeThreadSafeUpdateAnimation(float DeltaSeconds)
{
	if (!OwningCharacter || !OwningMovementComponent)
	{
		return;
	}
	GroundSpeed = OwningCharacter->GetVelocity().Size2D();
	bHasAcceleration = OwningMovementComponent->GetCurrentAcceleration().SizeSquared2D() > 0.0f;
}

캐릭터가 사용할 AnimInstance의 상위 Class다 기본적으로 현재 캐릭터, 캐릭터 무브먼트 컴포넌트, 이동 속도, 가속 여부 등 공통적으로 변수를 저장 및 업데이트하도록 하였다.

🎮 UBFPlayerAnimInstance.h

class ABFPlayerCharacter;

UCLASS()
class BOSSFIGHT_API UBFPlayerAnimInstance : public UBFCharacterAnimInstance
{
	GENERATED_BODY()

public:
	virtual void NativeInitializeAnimation() override;
	virtual void NativeThreadSafeUpdateAnimation(float DeltaSeconds) override;

protected:
	UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Anim Data | Refrence")
	ABFPlayerCharacter* OwningPlayerCharacter;
};

🎮 UBFPlayerAnimInstance.cpp

void UBFPlayerAnimInstance::NativeInitializeAnimation()
{
	Super::NativeInitializeAnimation();
	if (OwningCharacter)
	{
		OwningPlayerCharacter = Cast<ABFPlayerCharacter>(OwningCharacter);
	}
}

void UBFPlayerAnimInstance::NativeThreadSafeUpdateAnimation(float DeltaSeconds)
{
	Super::NativeThreadSafeUpdateAnimation(DeltaSeconds);
}

플레이어가 사용할 AnimInstance이다 현재는 OwnerCharacter가 유효하면 PlayerCharacter로 형변환 하여 OwningPlayerCharacter에 저장 하는 기능만 구현 하였다.

다음으로 AnimLayer를 작성하여보자.

UBFBaseAnimInstance를 상속받아 UBFAnimLinkedLayer를 작성 하였다.

🎮 UBFAnimLinkedLayer.h

class UBFPlayerAnimInstance;

UCLASS()
class BOSSFIGHT_API UBFAnimLinkedLayer : public UBFBaseAnimInstance
{
	GENERATED_BODY()

public:	
	UFUNCTION(BlueprintPure, meta = (NotBlueprintThreadSafe))
	UBFPlayerAnimInstance* GetPlayerAnimInstance() const;
};

🎮 UBFAnimLinkedLayer.cpp

UBFPlayerAnimInstance* UBFAnimLinkedLayer::GetPlayerAnimInstance() const
{
	return Cast<UBFPlayerAnimInstance>(GetOwningComponent()->GetAnimInstance());
}

이제 Class를 작성 하였으니 본격적으로 애님블루프린트 및 애님레이어를 구현 해보자.

우선 UBFPlayerAnimInstance를 상속 받아 ABP_Player를 생성 해주었다.

그후 에니메이션->에니메이션 레이어 인스턴스로 ALI_Player를 생성 아래와 같이 구성 해주었다.

그후 생성한 ABP_Player를에 ALI_Player 인터페이스를 추가 해주었고, 아래와 같이 노드를 구성 해주었다.

다음으로 UBFAnimLinkedLayer를 상속받는 AnimBlueprint를 추가해주고 이름을 MasterAnimLayer_Player로 지정, ALI_Player 인터페이스를 추가 하였다. 그후 아래와 같이 Locomation의 노드를 구성 해주었다

이동 말고, 공중 여부도 판단하여, 추락시 애니메이션이 나오도록 하고, 테스트 해보자.

작동 영상

추가로 기본 에셋이아닌 Mesh를 받아와서 애니메이션 리타겟팅을 하여 적용 하였다.

다음에는 무기 장착 기능을 구현 해보겠다.

0개의 댓글