UPROPERTY()
class UABAnimInstance* ABAnim;
앞서 같은 애니메이션을 중복플레이를 방지하기 위해 플레이중임을 체크했는데 이보다는 애니메이션이 끝나면 자동으로 폰에게 알려주는 편이 더 효과적이다. 언리얼이 제공하는 델리게이션기능을 사용해서 구현할 수 있다.
델리게이션이란 보편적으로 특정 객체가 해야할 로직을 다른 객체가 대신 처리할 수 있도록 만드는 보편적인 개념이다. A가 B에게 작업명령을 내리고 자신을 등록후 끝나면 A에게 알려주는 설계방식이다.
애님 인스턴스에는 애니메이션 몽타주 재생이 끝나면 발동하는 OnMontageEnded라는 델리게이트를 제공한다. 어떤 언리얼오브젝트라도 UAnimMontage * 인자와 bool 인자를 가진 멤버함수를 가지고 있다면, 이를 OnMontageEnded 델리게이트에 등록해 몽타주 재생이 끝나는 타이밍을 파악할 수 있다.
OnMontageEnded델리게이트는 여러개의 함수를 받을 수 있어서 등록된 모든 함수들에게 멀티캐스트할수 있고 멀티캐스트델리게이트라고 한다. 언리얼에서는 Signature라고 매크로를 통해 정의되어 있다.
* Delegate for when Montage is completed, whether interrupted or finished
* Weight of this montage is 0.f, so it stops contributing to output pose
*
* bInterrupted = true if it was not property finished
*/
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnMontageEndedMCDelegate,
UAnimMontage*, Montage, bool, bInterrupted);
이렇게 두가지 기능이 있는 걸 다이내믹 멀티캐스트 델리게이트라고 할수 다. 여기서 사용하는 AddDynamic함수는 코딩할 때 비쥬얼 인텔리센스에서 검색되지 않지만 에러는 아니다
PostInitializeComponents() 에서 해당함수를 애님 이스턴스의 OnMontageEnded 델리게이트에 바인딩한다. 그리고 현재 공격중인지 아닌지를 파악할 수 있도록 bool변수를 추가로 선언한다.
ABCharacter.h
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
virtual void PostInitializeComponents() override;
private:
UFUNCTION()
void OnAttackMontageEnded(UAnimMontage* Montage, bool bInterrupted);
UPROPERTY(VisibleInstanceOnly, BlueprintReadOnly, Category = Attack, Meta = (AllowPrivateAccess = true))
bool IsAttacking;
ABCharacter.cpp
void AABCharacter::PostInitializeComponents()
{
Super::PostInitializeComponents();
ABAnim = Cast<UABAnimInstance>(GetMesh()->GetAnimInstance());
ABCHECK(nullptr != ABAnim);
ABAnim->OnMontageEnded.AddDynamic(this, &AABCharacter::OnAttackMontageEnded);
//....
}
void AABCharacter::Attack()
{
if (IsAttacking) return;
auto AnimInstance = Cast<UABAnimInstance>(GetMesh()->GetAnimInstance());
if(!AnimInstance) return;
AnimInstance->PlayAttackMontage();
IsAttacking = true;
}
void AABCharacter::OnAttackMontageEnded(UAnimMontage * Montage, bool bInterrupted)
{
ABCHECK(IsAttacking);
ABCHECK(CurrentCombo > 0);
IsAttacking = false;
//AttackEndComboState();
}
AnimInstance변수를 자주 사용하므로 헤더파일에 포함시키고
ABCharacter.h
UPROPERTY()
class UABAnimInstance* ABAnim;
ABCharacter.cpp의 PostIniializeCompoents()에서 구현한다.
void AABCharacter::PostInitializeComponents()
{
Super::PostInitializeComponents();
ABAnim = Cast<UABAnimInstance>(GetMesh()->GetAnimInstance());
ABCHECK(nullptr != ABAnim);
}
void AABCharacter::Attack()
{
if (IsAttacking) return;
Anim->PlayAttackMontage();
IsAttacking = true;
델리게이트에 의해 공격의 시작과 종료가 감지되므로 AnimInstance에서 사용한 Montage_IsPlaying 함수는 사용하지 않아도 된다. 이를 제거한 코드는 다음과 같다.
void UABAnimInstance::PlayAttackMontage()
{
Montage_Play(AttackMontage, 1.0f);
}
'언리얼C++게임개발 > 08.애니메이션 시스템 활용' 카테고리의 다른 글
콤보공격 (1) | 2024.02.14 |
---|---|
애니메이션 노티파이 (1) | 2024.02.06 |
애니메이션 시스템 활용 - 애니메이션 몽타주 (0) | 2023.11.26 |