Animation은 Sequence와 Montage 두개로 나누어져있다.
Mongtage가 여러모로 관리하기가 편하고 C++, BP로 불러오기도 편하다. 내가 다운받은 애셋에 있는 애니메이션들은 모두 Sequence 형태였다. Sequence를 Montage로 변형할수는 있기는 하지만 이번 프로젝트에서는 그냥 Sequence를 사용하였다.
그럼 이제 이 Animation들을 조합하여 몬스터에게 자연스러운 움직임을 주어야하나는데 이것들을 모두 Animation Bluprint(ABP)로 관리하게 된다. ABP에는 애니메이션의 흐름을 제어하는 AnimGraph와 다른 블루프린트처럼 값을 변경하고, 이벤트를 호출하는 역할을 하는 EventGraph로 나누어져있다.
이 두개를 연동하여 쓰는 이유는
이렇게 EventGraph를 통해서 실시간으로 변경되는 데이터값들을 통해서 AnimGraph가 실행되기 때문이다.
만약 IsAccelerating 값이 True가 되면 캐릭터에게 움직이는 모션을 주고 IsAttack함수가 활성화되면 공격하는 모션을 준다.
이 블루프린트에서는 기본적인 움직임 데이터만을 변경하고 공격, 피격, 사망 애니메이션 관련 데이터들은 C++로 관리하고 있다.
AnimGraph에서 상태에 따른 애니메이션을 출력하는 State Machine이다.
Loco Pose는 에셋상에서 기본적으로 구현해놓은 이동, 대기, 추락, 점프등의 애니메이션이 구현되어 있다.
여기서 IsAttack, IsHit, IsDeath 세개의 bool값을 통해서 이 StateMachine을 제어하게 된다.
3개의 값은 통신의 원할함을 위해서 ABP가 아닌 AnimInstance에서 관리하게 된다.
UGrux_AnimInstance::UGrux_AnimInstance()
{
IsAttacking = false;
IsHit = false;
IsWaiting = false;
IsDeath = false;
}
void UGrux_AnimInstance::UpdateAttack(bool value)
{
IsAttacking = value;
}
void UGrux_AnimInstance::UpdateHit(bool value)
{
IsHit = value;
GetWorld()->GetTimerManager().SetTimer(TimerHandle, [this]()
{
IsHit = false;
AActor* OwnerActor = GetOwningActor();
}, 0.7f, false);
}
void UGrux_AnimInstance::UpdateDeath(bool value)
{
IsDeath = value;
}
void UGrux_AnimInstance::AnimNotify_EndHit()
{
IsHit = false;
AActor* OwnerActor = GetOwningActor();
if (OwnerActor)
{
ANormalMonster* Monster = Cast<ANormalMonster>(OwnerActor);
if (Monster)
{
Monster->RPCIsHit(IsHit, OwnerActor);
}
}
}
void UGrux_AnimInstance::AnimNotify_EndAttack()
{
AActor* OwnerActor = GetOwningActor();
if (OwnerActor)
{
ANormalMonster* Monster = Cast<ANormalMonster>(OwnerActor);
if (Monster)
{
AActor* Target = Monster->TargetCharacterActor;
if (Target)
{
Monster->RealAttack(Target);
}
}
}
}
void UGrux_AnimInstance::AnimNotify_AttackValue()
{
IsAttacking = false;
AActor* OwnerActor = GetOwningActor();
if (OwnerActor)
{
ANormalMonster* Monster = Cast<ANormalMonster>(OwnerActor);
if (Monster)
{
Monster->MulticastIsAttack(IsAttacking);
}
}
}
ABP는 기본적으로 AnimInstance를 부모클래스로 사용된다. Monster클래스에서 Attack, TakeDamage, Death함수가 호출될 때 AnimInstance->UpdateAnim 를 같이 호출하기 때문에 정확한 상태에 맞춰서 Anim이 출력된다.
아랫쪽에 작성해놓은 AnimNotify는 애니메이션이 끝날 때 자동으로 호출되는 함수이다. 즉 애니메이션이 끝나면 해당 bool값을 false로 만들어 StateMachine을 정상화 시키는 방법이다.
UpdateHit에서 굳이 타이머를 추가하여 다시 IsHit값을 False로 바꿔주는 이유는 이유를 알 수 없는 버그로 인해서 AnimNoify_EndHit이 호출될 때 IsHit이 정상적으로 False로 바뀌지 않아서이다.
'UE5' 카테고리의 다른 글
NavMesh Invoker (0) | 2025.04.23 |
---|---|
언리얼 Monster AI 구현(4): 통신 (0) | 2025.04.22 |
언리얼 Monster AI구현(2): Behavior Tree (0) | 2025.04.15 |
언리얼 Monster AI 구현(1): 전투 (0) | 2025.04.15 |
C++ Behavior Tree (0) | 2025.04.08 |