본문 바로가기

Unreal/언리얼 엔진 5로 개발하는 멀티플레이어 게임(Book)

[Unreal] 애니메이션 연결(달리기, 던지기)

달리기 애니메이션

 

달리기 애니메이션을 연결하려면 Mesh 컴포넌트의 디테일에서 Animation의 Anim Class에 작성한 Animation BluePrint를 할당한다.

해당 애니메이션은 Speed를 기준으로 동작하는데, 이 변수를 서버에서 받아 사용하므로 클라이언트에서는 값이 갱신되지 않아 오류가 발생한다. 이를 해결하기 위해 코드를 수정해야 한다.

 

US_Character.h

UFUNCTION(NetMulticast, Reliable)
void SprintStart_Client();

UFUNCTION(NetMulticast, Reliable)
void SprintEnd_Client();

 

US_Character.cpp

void AUS_Character::SprintStart_Server_Implementation()
{
    SprintStart_Client();
}

void AUS_Character::SprintEnd_Server_Implementation()
{
    SprintEnd_Client();
}

void AUS_Character::SprintStart_Client_Implementation()
{
    if (GetCharacterStats())
    {
        GetCharacterMovement()->MaxWalkSpeed = GetCharacterStats()->SprintSpeed;
    }
}

void AUS_Character::SprintEnd_Client_Implementation()
{
    if (GetCharacterStats())
    {
        GetCharacterMovement()->MaxWalkSpeed = GetCharacterStats()->WalkSpeed;
    }
}

 

SprintStart_Server_Implementation을 보면 NetMulticast로 선언된 _Client()를 호출하고 있다. NetMulticast는 서버에서 오브젝트가 함수를 호출하면, 서버와 함수를 호출하는 오브젝트의 모든 클라이언트 버전에서 실행된다. 이러한 특징으로 자신뿐만 아니라 다른 클라이언트에서도 오류 없이 처리할 수 있게 된다.

 

던지기 애니메이션

US_WeaponProjectileComponent.h

UFUNCTION(NetMulticast, Unreliable)
void Throw_Client();

 

이번 UFUNCTION을 주목해야 하는 점은 Unreliable로 설정된 부분이다. 애니메이션은 단지 시각적인 효과일 뿐이므로, 네트워크상에서 데이터 손실이 발생해도 괜찮기 때문에 이러한 설정을 가지게 되었다.

 

US_WeaponProjectileComponent.cpp

void UUS_WeaponProjectileComponent::Throw_Client_Implementation()
{
    const auto Character = Cast<AUS_Character>(GetOwner());
    if (ThrowAnimation != nullptr)
    {
        if (const auto AnimInstance = Character->GetMesh()->GetAnimInstance(); AnimInstance != nullptr)
        {	
            AnimInstance->Montage_Play(ThrowAnimation, 1.f);
        }
    }
}
  • AnimInstance->Montage_Play(ThrowAnimation, 1.f): 지정된 애니메이션 몽타주를 1배속으로 재생하는 것을 의미한다.

US_WeaponProjectileComponent.cpp

void UUS_WeaponProjectileComponent::Throw_Server_Implementation()
{
    if (ProjectileClass)
    {
        Throw_Client();
        FTimerHandle TimerHandle;
        GetWorld()->GetTimerManager().SetTimer(TimerHandle, [&]()
            {
                const auto Character = Cast<AUS_Character>(GetOwner());
                const auto ProjectileSpawnLocation = GetComponentLocation();
                const auto ProjectileSpawnRotation = GetComponentRotation();
                auto ProjectileSpawnParams = FActorSpawnParameters();
                ProjectileSpawnParams.Owner = GetOwner();
                ProjectileSpawnParams.Instigator = Character;

                GetWorld()->SpawnActor<AUS_BaseWeaponProjectile>(ProjectileClass, ProjectileSpawnLocation, ProjectileSpawnRotation, ProjectileSpawnParams);
            }, .4f, false);
    }
}

 

물체를 던질 때 미리 스폰되어 던지는 것은 어색한 시각적 효과를 주므로, 스폰 로직을 약간 지연시켜야 한다. 이를 위해 약 0.4초 지연시킨다.