언리얼 엔진/언리얼 엔진 활용

Unreal Engine - Custom Pawn 중력 없이 이동 구현

로안님 2025. 2. 9. 18:23

🚀 Unreal Engine 5에서 Custom Pawn을 활용한 이동 시스템 구현 (중력 효과 없음)

📌 1. 개요

언리얼 엔진 5에서 Pawn 클래스를 활용하여 직접 이동 로직을 구현했습니다. 기본적으로 Character 클래스에서는 CharacterMovementComponent를 제공하여 이동 및 충돌 처리를 자동으로 해주지만, Pawn을 활용하면 보다 세밀하게 커스텀 이동을 구현할 수 있습니다.

이번 프로젝트에서는 기본 중력 효과 없이 다음과 같은 요소를 직접 구현했습니다.

  • ✅ Pawn 클래스 생성 및 충돌 설정
  • ✅ Enhanced Input을 활용한 입력 처리
  • ✅ AddActorLocalOffset()을 이용한 직접 이동 구현
  • ✅ W/S 키로 상승 및 하강 구현 (가속 및 감속 적용)
  • ✅ A/D 키로 회전, 마우스로 기울기(Tilt) 조작 구현

📌 2. Pawn 클래스 구성 및 컴포넌트 설정

🔹 (1) Pawn 기본 컴포넌트 설정

  • UCapsuleComponent: 루트 컴포넌트로 설정 (충돌 처리)
  • USkeletalMeshComponent: 헬기 모델 부착
  • UArrowComponent: 방향을 나타내는 시각적 요소 추가
  • USpringArmComponent** & ****UCameraComponent**: 3인칭 카메라 설정

🔹 (2) 주요 코드 (AMyCustomPawn 클래스)

AMyCustomPawn::AMyCustomPawn()
{
    PrimaryActorTick.bCanEverTick = true;

    CollisionComp = CreateDefaultSubobject<UCapsuleComponent>(TEXT("Capsule"));
    SetRootComponent(CollisionComp);
    
    CollisionComp->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
    CollisionComp->SetCollisionObjectType(ECollisionChannel::ECC_Pawn);
    CollisionComp->SetCollisionResponseToAllChannels(ECR_Block);
    CollisionComp->SetSimulatePhysics(false);

    MeshComp = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mesh"));
    MeshComp->SetupAttachment(RootComponent);

    SpringArmComp = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
    SpringArmComp->SetupAttachment(RootComponent);

    CameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
    CameraComp->SetupAttachment(SpringArmComp, USpringArmComponent::SocketName);

    VerticalSpeed = 0.0f;
    Acceleration = 50.0f;
    MaxVerticalSpeed = 300.0f;
    Deceleration = 30.0f;
    TurnSpeed = 50.0f;
}

✅ 중력 없이 이동을 직접 처리하기 위해 SetSimulatePhysics(false); 설정


📌 3. Enhanced Input으로 입력 처리

🔹 (1) Input Mapping 설정

Enhanced Input을 활용하여 조작을 보다 정밀하게 구현할 수 있도록 설정했습니다.

  • IA_HeliUpDown: W/S 키로 상승 및 하강
  • IA_HeliRotate: A/D 키로 회전
  • IA_HeliTilt: 마우스로 기울기(Tilt) 조작

🔹 (2) Input 바인딩 코드

void AMyCustomPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);
    
    if (UEnhancedInputComponent* EnhancedInput = Cast<UEnhancedInputComponent>(PlayerInputComponent))
    {
        if (ACustomPlayerController* PlayerController = Cast<ACustomPlayerController>(GetController()))
        {
            EnhancedInput->BindAction(PlayerController->HeliUpDownAction, 
            ETriggerEvent::Triggered, 
            this, 
            &AMyCustomPawn::HeliUpDown
            );
            EnhancedInput->BindAction(PlayerController->HeliRotateAction, 
            ETriggerEvent::Triggered, 
            this,
            &AMyCustomPawn::HeliRotate
            );
            EnhancedInput->BindAction(PlayerController->HeliTiltAction, 
            ETriggerEvent::Triggered, 
            this,
            &AMyCustomPawn::HeliTilt
            );
        }
    }
}

📌 4. 이동 및 회전 구현

🔹 (1) W/S 키로 상승 및 하강 (HeliUpDown)

void AMyCustomPawn::HeliUpDown(const FInputActionValue& value)
{
    if (!Controller) return;

    const float UpDownValue = value.Get<float>();

    if (!FMath::IsNearlyZero(UpDownValue))
    {
        if (UpDownValue < 0 && VerticalSpeed > 0)
        {
            VerticalSpeed = 0.0f;
        }
        VerticalSpeed += UpDownValue * Acceleration * GetWorld()->DeltaTimeSeconds;
        VerticalSpeed = FMath::Clamp(
        VerticalSpeed, 
        -MaxVerticalSpeed, 
        MaxVerticalSpeed
        );
    }
    else
    {
        VerticalSpeed = FMath::FInterpTo(
        VerticalSpeed, 
        0.0f, 
        GetWorld()->DeltaTimeSeconds, 
        Deceleration
        );
    }
    AddActorLocalOffset(FVector(
    0,
    0,
    VerticalSpeed * GetWorld()->DeltaTimeSeconds), 
    true
    );
}

🔹 (2) A/D 키로 회전 (HeliRotate)

void AMyCustomPawn::HeliRotate(const FInputActionValue& value)
{
    if (!Controller) return;

    const float TurnInput = value.Get<float>();

    FRotator CurrentRotation = GetActorRotation();
    CurrentRotation.Yaw += TurnInput * TurnSpeed * GetWorld()->DeltaTimeSeconds;
    SetActorRotation(CurrentRotation);
}

🔹 (3) 마우스로 기울기 조작 (HeliTilt)

void AMyCustomPawn::HeliTilt(const FInputActionValue& Value)
{
    if (!Controller) return;

    FVector2D LookInput = Value.Get<FVector2D>();
    FRotator CurrentRotation = GetActorRotation();

    float NewPitch = CurrentRotation.Pitch + LookInput.Y * LookSpeed * GetWorld()->DeltaTimeSeconds;
    NewPitch = FMath::Clamp(NewPitch, -80.0f, 80.0f);

    float NewRoll = CurrentRotation.Roll + LookInput.X * LookSpeed * GetWorld()->DeltaTimeSeconds;
    NewRoll = FMath::Clamp(NewRoll, -80.0f, 80.0f);

    SetActorRotation(FRotator(NewPitch, CurrentRotation.Yaw, NewRoll));
}

📌 5. 결론

  • ✅ Pawn 클래스를 활용하여 CharacterMovementComponent 없이 직접 이동 로직 구현
  • ✅ AddActorLocalOffset()과 SetActorRotation()을 활용하여 헬기 조작 감각 구현
  • ✅ Enhanced Input을 사용하여 더 정밀한 컨트롤 가능
  • ✅ 중력 효과를 제외하고, 직접 속도를 제어하는 방식으로 이동 구현

🚀 추가적으로 중력 효과를 적용하려면 Tick()에서 구현가능!