Game Development/Devlog

[UE5] Rifle 픽업, 착용 기능 구현, Replication 문제 해결 (TPS - 개발일지3)

Dlaiml 2024. 7. 29. 19:35

 

ProjectVT가 크라우드 펀딩을 앞두게 되어 개발할 것들이 크게 늘어 TPS 개발에 시간을 이전보다 많이 쓰지 못하였다. 저번 포스팅 이후 진척도를 공유하려 한다.

 

 

 

[UE5] 애니메이션 추가, Character 클래스 생성 (TPS 개발일지 - 2)

출시를 앞둔 프로젝트가 있어 개인 프로젝트에 시간을 많이 쓰지 못하고 있다. 저번 포스팅 이후 애니메이션 추가, Character 클래스 생성까지만 진행하였다. [UE5] 프로젝트 생성, 캐릭터 모델 impo

dlaiml.tistory.com

 

Content 파일 정리, 애니메이션 시스템 구조 확정

저번 포스팅 이후 Migrate 한 애니메이션의 파일이 필요 이상으로 많아 이를 정리하였다. AnimStarterPack, Mixamo, Lyra, Belica 애니메이션 중 우선 Idle, Walk, Jog, Ironsight(조준)을 제외한 파일을 모두 제거하였다. 

 

멀티플레이 기반의 TPS 게임이 아닌 다른 게임으로의 피봇팅도 생각중이라 우선 필요한 파일을 제외하고 최대한 import하지 않고 있다

 

Migrate를 할 때 애니메이션 시퀀스에 연결된 Skeletal Mesh와 관련된 파일들도 모두 함께 Migrate 되어 Content 폴더가 매우 지저분해졌는데 대신 다른 프로젝트에서 원하는 애니메이션을 XBot과 같이 간단한 구조의 캐릭터로 Retargeting 한 뒤 이를 Migrate 하는 방식으로 폴더를 한 번 정리하였다.

 

 

이전 포스팅에 ABP에 사용할 애니메이션 시스템으로 모션매칭과 Blend Space를 고민하였는데, 아직 간단한 애니메이션 시스템만 다뤄보았기 때문에 Blend Space로 하나하나 조정해 가면서 자연스러운 애니메이션을 만들어보려 한다. 

 

 

Locomotion 개선

처음에는 캐릭터의 Velocity를 받아서 이를 Axis로 Idle / Walk / Jog / Sprint까지 모든 애니메이션을 2D Blend Space에 빼곡하게 집어넣었다.

 

결과는 하단 Gif의 왼쪽을 보면 이동 방향이 바뀌면서 많은 애니메이션을 빠르게 뛰어넘는 과정에서 부자연스러운 부분이 있었다. 

 

추후 Jog, Sprint와 같이 달리는 상태에서는 조준까지의 시간, 아이템 사용, 총기 반동 등을 다르게 설정할 예정이기 때문에 어차피 State로 관리할 것으로 보여 Jog, Sprint 애니메이션을 가지로 Blend Space를 따로 구성하였다. (Paragon, Animation Starter Pack의 샘플 프로젝트도 같은 방식으로 Jog 이상을 State로 따로 관리하고 있었음)

 

이후 빠른 방향전환에서 애니메이션이 부자연스러워 Rotator를 보간하여 더 부드럽게 Rotation 값이 변하도록 하였다.

 

void UWarComposerAnimInstance::NativeUpdateAnimation(float DeltaSeconds) 
{
// ...

    FRotator AimRotation = WarComposerCharacter->GetBaseAimRotation();
    FRotator MovementRotation = UKismetMathLibrary::MakeRotFromX(WarComposerCharacter->GetVelocity());
    FRotator DeltaRot = UKismetMathLibrary::NormalizedDeltaRotator(MovementRotation, AimRotation);
    DeltaAimRotation = FMath::RInterpTo(DeltaAimRotation, DeltaRot, DeltaSeconds, 11.f);
    AimYawOffset = DeltaAimRotation.Yaw;
// ...
}

 

그 후  Blend Space에서 Sample Smoothing를 설정하였다.

Sample Smoothing의 Weight Speed가 크면 클수록 중간 단계를 건너뛰게 된다. 예시로 좌로 달리기 / 앞으로 달리기 / 우로 달리기와 같이 Rotation을 Axis로 설정된 1D Blend space가 있고 Weight Speed가 크게 설정되어 있다면 -90 -> 90도로 빠르게 방향이 전환될 때 앞으로 달리는 애니메이션이 거의 생략되고 좌 -> 우 애니메이션이 바로 재생된다.

 

 

앞으로 달리는 애니메이션 시퀀스가 특히 다른 애니메이션 보다 동작이 크고 디딤발이 뒤로 빠진 상태에서 시작하다 보니 주변 Space에서의 애니메이션이 전부 어색하던 것이 문제였다. Weight Speed를 3으로 증가시킨 뒤에는 문제가 많이 완화되었다. (하단 Gif 우측)

 

 

 

Weapon Actor 추가 & 무기 습득 기능 추가

프로젝트에 추가하였던 Weapon Pack의 Mesh를 사용할 Weapon 클래스를 만들었다.

 

 

캐릭터가 무기를 습득하여 장착할 수 있는 Pick Up 기능을 구현하였으며 이를 위해 현재 Weapon의 State를 나타내는 Enum과 캐릭터가 가까이 있는지 판단할 수 있도록 Collider를 추가하였다.

 

UENUM(BlueprintType)
enum class EWeaponState : uint8
{
	EWS_Initialized UMETA(DisplayName = "Initialized"),
	EWS_Equipped UMETA(DisplayName = "Equipped"),
	EWS_Unequipped UMETA(DisplayName = "UnEquipped"),
	EWS_Dropped UMETA(DisplayName = "Dropped"),

	EWS_MAX UMETA(Hidden)
};


void AWarComposerWeapon::OnSphereBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	AWarComposerCharacter* WarComposerCharacter = Cast<AWarComposerCharacter>(OtherActor);
	if (WarComposerCharacter != nullptr)
	{
		WarComposerCharacter->SetOverlappedWeapon(this);
	}
	else
	{
		UE_LOG(LogTemp, Warning, TEXT("NULL WarComposer Casting"));
	}
}

 

캐릭터와 Overlap이 일어났다면 아래 UserWidget의 Visibility를 조정하여 플레이어의 화면에 띄운다.

 

총기 습득 Input Action의 Trigger는 1초 동안 F키를 Hold 하는 것으로 지정하였다. ProgressBar를 사용하여 위젯의 색이 점점 변하거나 왼쪽 F키 배경의 투명도가 달라지도록 후에 변경할 예정이다.

 

 

추가로 무기를 착용한 뒤에는 카메라가 보는 방향이 캐릭터의 전방이 되지 않고 다른 TPS 게임처럼 마우스가 조준하고 있는 위치가 캐릭터의 앞이 되도록 변경하였다.

 

Replication 문제 해결

이전 프로젝트에서 만들었던 구조처럼 이번에도 전투 관련 시스템을 모두 ActorComponent에서 관리하고 있다.

현재 캐릭터가 장착한 무기와 조준 상태(Bool) 또한 모두 Component에서 관리하는데 클라이언트에서 무기를 착용하고 나면 이후 애니메이션이 정상적으로 작동하지 않던 문제가 있었다.

 

UPROPERTY(ReplicatedUsing = OnRep_OverlappedWeapon)
class AWarComposerWeapon* OverlappedWeapon;

UFUNCTION()
void OnRep_OverlappedWeapon(AWarComposerWeapon* LastWeapon);

 

 

멤버에 Replicate 세팅이 되어있음을 확인해도 문제가 발생하였는데 확인해 보니 캐릭터 클래스에서 ActorComponent로 전투 관련 로직을 옮기면서 ActorComponent의 Replicate 설정을 하지 않아서 생긴 문제였다. 

 

생성자에 SetIsReplicatedByDefault(true) 를 추가하여 해결하였다.

UWarComposerBattleComponent::UWarComposerBattleComponent()
{
	PrimaryComponentTick.bCanEverTick = false;
	SetIsReplicatedByDefault(true);
}

 

 

또 다른 문제로는 다른 플레이어가 착용 중인 무기에 가까이 접근하면 Overlap 이벤트가 발생하여 상대방의 무기를 주워서 착용할 수 있던 문제가 있었다. 

 

Overlap 이벤트 발생 시 캐릭터가 무기를 착용 중이면 이벤트를 무시하는 방식으로 구현해서 생긴 문제로, 대신 Weapon 클래스에서 Collision을 Disable 하는 방식으로 이를 해결하였다.

 

에디터의 Listen server mode로  테스트해 보았는데 애니메이션, 무기 장착 모두 잘 작동하는 것을 확인할 수 있었다.

 

 

Reference

[0]

 

[UE5] Session 기반 멀티플레이 Plugin 제작 - OnlineSubsystemSteam 환경에서 ServerTravel 디버깅

이전 포스팅에서 OnlineSubsystem의 Session Interface를 사용하여 멀리 떨어진 플레이어도 같이 게임을 즐길 수 있도록 간단하게 멀티플레이 기능을 만들어 보았다.  [UE5] 클라이언트-서버 모델언리얼

dlaiml.tistory.com