- 이전 포스팅에서 작업한 직업 구분을 토대로 애니메이션 설정하기
- 무기를 소지 후 장착하고 장착 해제하는 애니메이션 적용하기
- Warrior의 Locomotion 애니메이션을 추가하여 무기를 장착했을 때 Warrior Locomotion을 토대로 애니메이션이 재생되게 만들어보겠습니다.
- 직업에 따라, 무기 착용 여부에 따라 애니메이션을 블렌딩해줘야 합니다.
- 애니메이션의 업데이트에 사용할 인터페이스를 선언하고, 애님 인스턴스 클래스에서 해당 변수들을 업데이트 합니다.
// MMAnimationUpdateInterface Header
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "GameData/MMEnums.h"
#include "MMAnimationUpdateInterface.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UMMAnimationUpdateInterface : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class MYSTICMAZE_API IMMAnimationUpdateInterface
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
virtual EClassType GetClassType() = 0;
virtual bool GetIsGuard() = 0;
virtual bool GetIsEquip() = 0;
};
// MMPlayerCharacter CPP
// Member Variable
protected:
FORCEINLINE virtual EClassType GetClassType() override { return ClassType; };
FORCEINLINE virtual bool GetIsGuard() override { return bIsGuard; }
FORCEINLINE virtual bool GetIsEquip() override { return bIsEquip; }
// MMPlayerAnimInstance Class
void UMMPlayerAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
IMMAnimationUpdateInterface* Player = Cast<IMMAnimationUpdateInterface>(TryGetPawnOwner());
if (Player)
{
bIsGuard = Player->GetIsGuard();
ClassType = Player->GetClassType();
bIsEquip = Player->GetIsEquip();
}
}
- 플레이어 애니메이션 블루프린트 수정하기
- 무기를 장착하면 Warrior, 해제하면 Beginner Locomotion
- 직업 타입에 따라 구분할 수 있도록 해줍니다.
- IA_ConvertWeapon 이라는 공용 입력 액션을 추가해주도록 합니다.
- 무기를 장착/장착 해제를 스위치하는 로직을 구현합니다.
// MMPlayerCharacter Header
protected:
UPROPERTY(VisibleAnywhere, Category = CommonInput, Meta = (AllowPrivateAccess = "true"))
TObjectPtr<class UInputAction> IA_ConvertWeapon;
// 무기 스왑용 매핑 함수
void ConvertWeapon();
// 무기 장착 함수
void DrawWeapon();
void DrawEnd(class UAnimMontage* Montage, bool IsEnded);
// 무기 해제 함수
void SheatheWeapon();
void SheatheEnd(class UAnimMontage* Montage, bool IsEnded);
UPROPERTY(EditAnywhere, Category = Montage, Meta = (AllowPrivateAccess = "true"))
TMap<EClassType, TObjectPtr<class UAnimMontage>> DrawMontage;
UPROPERTY(EditAnywhere, Category = Montage, Meta = (AllowPrivateAccess = "true"))
TMap<EClassType, TObjectPtr<class UAnimMontage>> SheatheMontage;
// MMPlayerCharacter Cpp
void AMMPlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent);
...
EnhancedInputComponent->BindAction(IA_ConvertWeapon, ETriggerEvent::Triggered, this, &AMMPlayerCharacter::ConvertWeapon);
}
void AMMPlayerCharacter::ConvertWeapon()
{
if (bIsChange) return;
if (bIsEquip)
{
SheatheWeapon();
}
else
{
DrawWeapon();
}
}
void AMMPlayerCharacter::DrawWeapon()
{
if (CurrentWeapon)
{
bIsChange = true;
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance)
{
// 몽타주 재생
AnimInstance->Montage_Play(DrawMontage[ClassType]);
// 몽타주 재생 종료 바인딩
FOnMontageEnded EndDelegate;
EndDelegate.BindUObject(this, &AMMPlayerCharacter::DrawEnd);
// DrawMontage가 종료되면 EndDelegate에 연동된 DrawEnd함수 호출
AnimInstance->Montage_SetEndDelegate(EndDelegate, DrawMontage[ClassType]);
}
}
}
void AMMPlayerCharacter::DrawEnd(UAnimMontage* Montage, bool IsEnded)
{
bIsChange = false;
bIsEquip = true;
}
void AMMPlayerCharacter::SheatheWeapon()
{
if (CurrentWeapon)
{
bIsChange = true;
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance)
{
// 몽타주 재생
AnimInstance->Montage_Play(SheatheMontage[ClassType]);
// 몽타주 재생 종료 바인딩
FOnMontageEnded EndDelegate;
EndDelegate.BindUObject(this, &AMMPlayerCharacter::SheatheEnd);
// SheatheMontage가 종료되면 EndDelegate에 연동된 SheatheEnd함수 호출
AnimInstance->Montage_SetEndDelegate(EndDelegate, SheatheMontage[ClassType]);
}
}
}
void AMMPlayerCharacter::SheatheEnd(UAnimMontage* Montage, bool IsEnded)
{
bIsChange = false;
bIsEquip = false;
}
- 플레이어의 등에 부착된 무기를 Draw하며 손 위치로 이동시켜줘야 합니다.
- 전사 Draw/Sheathe Montage를 추가하고 AnimNotify를 통해 무기의 부착 위치를 변경시켜주도록 하겠습니다.
// MMAnimationWeaponInterface Header
UINTERFACE(MinimalAPI)
class UMMAnimationWeaponInterface : public UInterface
{
GENERATED_BODY()
};
/**
*
*/
class MYSTICMAZE_API IMMAnimationWeaponInterface
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
virtual class AMMWeapon* GetWeapon() = 0;
};
// MMPlayerCharacter Header
// Weapon Section
protected:
FORCEINLINE virtual class AMMWeapon* GetWeapon() override { return CurrentWeapon; }
// AnimNotify_MMEquipWeapon Cpp
#include "Animation/AnimNotify_MMEquipWeapon.h"
#include "Interface/MMAnimationWeaponInterface.h"
#include "Item/MMWeapon.h"
void UAnimNotify_MMEquipWeapon::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference)
{
Super::Notify(MeshComp, Animation, EventReference);
if (MeshComp)
{
// 무기 장착
IMMAnimationWeaponInterface* WeaponPawn = Cast<IMMAnimationWeaponInterface>(MeshComp->GetOwner());
if (WeaponPawn)
{
WeaponPawn->GetWeapon()->DrawWeapon(MeshComp);
}
}
}
// AnimNotify_MMUnEquipWeapon Cpp
#include "Animation/AnimNotify_MMUnEquipWeapon.h"
#include "Interface/MMAnimationWeaponInterface.h"
#include "Item/MMWeapon.h"
void UAnimNotify_MMUnEquipWeapon::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference)
{
Super::Notify(MeshComp, Animation, EventReference);
if (MeshComp)
{
// 무기 장착 해제
IMMAnimationWeaponInterface* WeaponPawn = Cast<IMMAnimationWeaponInterface>(MeshComp->GetOwner());
if (WeaponPawn)
{
WeaponPawn->GetWeapon()->SheatheWeapon(MeshComp);
}
}
}
제작한 AnimNotify를 사용해 2개의 몽타주(장착/장착해제)를 생성합니다.