Notice
Recent Posts
Recent Comments
Link
«   2026/06   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

MOONSUN

[UE5] 입력 처리 : Axis, Action 바인딩 (Legacy 버전) 본문

UE5

[UE5] 입력 처리 : Axis, Action 바인딩 (Legacy 버전)

MoonSun_v 2026. 3. 27. 21:04

 

  

구분 Axis Action
입력 형태 연속 값 이벤트
함수 인자 float 없음
호출 방식 매 프레임 눌렀을 때 / 뗐을 때
대표 용도 이동, 회전 점프, 공격

 

 

 

1. SetupPlayerInputComponent()의 역할

UCLASS() 
class UNREALSTUDY_API AIMCPawn : public APawn
{
	...
public:	
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
 	...
}

 

SetupPlayerInputComponent()는

"어떤 입력이 들어왔을 때 어떤 함수를 실행할지 연결(바인딩)하는 함수” 이다.

 

즉, 이 함수는 직접 입력을 처리하는 곳 이라기보다,

  • W 키를 누르면 어떤 함수가 실행될지
  • 마우스를 움직이면 어떤 함수가 실행될지
  • 스페이스바를 누르면 어떤 함수가 실행될지

이런 입력 규칙을 등록하는 곳.

 

 

  • 예를 들어 아래 코드는
    • "UpDown" 축 입력이 들어오면 UpDown() 함수를,
    • "LeftRight" 축 입력이 들어오면 LeftRight() 함수를 실행하도록 바인딩하고 있다.
void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent->BindAxis(TEXT("UpDown"), this, &AMyPawn::UpDown);
	PlayerInputComponent->BindAxis(TEXT("LeftRight"), this, &AMyPawn::LeftRight);
}

 

이 함수는 입력이 들어올 때마다 호출되는 함수가 아니라
보통 Pawn이 PlayerController에 의해 Possess될 때 한 번 호출되어, 입력 바인딩을 세팅한다.

 

 

 

 

2. Axis란?

Axis는 연속적인 값(continuous value)을 처리하는 입력 방식

 

쉽게 말해:

  • 얼마나 앞으로 이동할지
  • 얼마나 오른쪽으로 이동할지
  • 마우스를 얼마나 움직였는지
  • 조이스틱을 얼마나 기울였는지

처럼 크기와 방향이 계속 변할 수 있는 입력을 다룰 때 사용한다.

 

2-1. Axis의 특징

 

2-1-1. float 값을 받는다

Axis로 바인딩된 함수는 보통 float 값을 받는다.

void AMyPawn::UpDown(float Value)
{
	// Value 사용
}

이 값은 보통 다음처럼 들어온다.

  • 1.0 : 정방향 입력
  • -1.0 : 반대 방향 입력
  • 0.0 : 입력 없음

예를 들어 키보드에서:

  • W = +1
  • S = 1

로 설정하면, UpDown 값은 상황에 따라 -1 ~ 1 사이의 값이 된다.

 

 

2-1-2. Axis 바인딩 함수는 매 프레임 호출된다

  • W를 누르고 있으면 계속 1.0
  • 아무 입력이 없으면 계속 0.0

이런 식으로 현재 입력 상태를 지속적으로 전달 받는다.

(그래서 로그를 찍어보면 입력이 없을 때도 계속 함수가 불리는 것을 볼 수 있음)

 

2-1-3. 이동, 회전, 카메라 처리에 적합

  • Axis는 계속 변화하는 입력을 처리하는 데 적합하다.
    • 캐릭터 이동
    • 카메라 회전
    • 마우스 이동
    • 게임패드 스틱 입력

 

2-2. Axis 예제 코드

에디터 Input 세팅 설정

void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent->BindAxis(TEXT("UpDown"), this, &AMyPawn::UpDown);
	PlayerInputComponent->BindAxis(TEXT("LeftRight"), this, &AMyPawn::LeftRight);
}

void AMyPawn::UpDown(float Value)
{
	if (!FMath::IsNearlyZero(Value))
	{
		UE_LOG(LogTemp, Warning, TEXT("UpDown: %f"), Value);
	}

  // Pawn의 앞 방향으로 value 만큼 이동
	AddMovementInput(GetActorForwardVector(), Value);
}

void AMyPawn::LeftRight(float Value)
{
	if (!FMath::IsNearlyZero(Value))
	{
		UE_LOG(LogTemp, Warning, TEXT("LeftRight: %f"), Value);
	}

	AddMovementInput(GetActorRightVector(), Value);
}

 

 

 

 

3. Action이란?

Action은 이벤트성 입력(event input) 을 처리하는 방식

 

쉽게 말해:

  • 버튼을 눌렀다
  • 버튼을 뗐다

처럼 어떤 시점에 발생하는 입력을 다룰 때 사용한다.

 

 

3-1. Axis의 특징

 

3-1-1. Pressed / Released 같은 이벤트 기반이다

 

Action은 축 값처럼 연속적인 수치를 받는 것이 아니라, 특정 이벤트가 발생했을 때 함수가 호출된다.

  • IE_Pressed : 눌렀을 때
  • IE_Released : 뗐을 때

 

 

3-1-2. 매 프레임 호출되지 않는다

 

위와 같은 내용이지만, Axis와 달리 Action은 매 프레임 호출되지 않는다.

  • 스페이스바를 눌렀을 때 한 번
  • 스페이스바를 뗐을 때 한 번

이렇게 이벤트가 발생한 순간에만 호출된다.

 

 

3-1-3. 점프, 공격, 상호작용에 적합하다

 

Action은 순간적인 행동에 잘 어울린다.

  • 점프
  • 공격
  • 상호작용
  • 인벤토리 열기
  • UI 확인 버튼

 

 

 

3-2. Action 예제 코드

에디터 Input 세팅 설정

void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent->BindAction(TEXT("Jump"), IE_Pressed, this, &AMyPawn::JumpPressed);
	PlayerInputComponent->BindAction(TEXT("Jump"), IE_Released, this, &AMyPawn::JumpReleased);
}

void AMyPawn::JumpPressed()
{
	UE_LOG(LogTemp, Warning, TEXT("Jump Pressed"));
}

void AMyPawn::JumpReleased()
{
	UE_LOG(LogTemp, Warning, TEXT("Jump Released"));
}

 

이 코드는 "Jump"라는 Action 입력이 발생했을 때

  • 눌렀으면 JumpPressed()
  • 뗐으면 JumpReleased()

를 실행

 

 

4. Axis와 Action의 차이 

Axis

  • 연속적인 값 처리
  • float 값을 받음
  • 매 프레임 호출됨
  • 이동, 회전, 카메라 조작에 사용

Action

  • 이벤트성 입력 처리
  • Pressed / Released 같은 이벤트로 동작
  • 이벤트가 발생할 때만 호출됨
  • 점프, 공격, 상호작용에 사용

 

5. 최종 예시 코드

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "MyPawn.generated.h"


class UCapsuleComponent;
class USkeletalMeshComponent;
class UFloatingPawnMovement;
class UCameraComponent;
class USpringArmComponent;

UCLASS()
class UNREALSTUDY_API AMyPawn : public APawn
{
	GENERATED_BODY()

public:
	AMyPawn();

protected:
	virtual void BeginPlay() override;

public:	
	virtual void Tick(float DeltaTime) override;
	virtual void PostInitializeComponents() override;
	virtual void PossessedBy(AController* NewController) override;

	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

public:
	// 보통 Pawn/Character 은 CapsuleComponent를 Root Component로 설정하는 경우가 많음.
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
	TObjectPtr<UCapsuleComponent> Capsule;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
	TObjectPtr<USkeletalMeshComponent> SkeletalMesh;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
	TObjectPtr<UFloatingPawnMovement> Movement;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
	TObjectPtr<UCameraComponent> Camera;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
	TObjectPtr<USpringArmComponent> SpringArm;


private:
	// Axis
	void UpDown(float value);
	void LeftRight(float value);

	// Action
	void JumpPressed();
	void JumpReleased();
	bool bIsJumpPressed = false; // ing 상태는 따로 없음.
};
#include "MyPawn.h"

#include "Components/SceneComponent.h"
#include "Components/CapsuleComponent.h"

#include "Camera/CameraComponent.h"

#include "GameFramework/FloatingPawnMovement.h"
#include "GameFramework/SpringArmComponent.h"


AMyPawn::AMyPawn()
{
	PrimaryActorTick.bCanEverTick = true; // Tick() 함수 안쓰면 false로 해주는게 좋음.

	// 충돌체를 RootComponent 
	Capsule = CreateDefaultSubobject<UCapsuleComponent>(TEXT("Capsule"));
	RootComponent = Capsule;

	SkeletalMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("SkeletalMesh"));
	SkeletalMesh->SetupAttachment(Capsule);
	SkeletalMesh->SetRelativeRotation(FRotator(0.0f, -90.f, 0.0f)); // 메시의 기본 방향이 X축이므로, Y축이 앞으로 오도록 회전

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

	Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
	Camera->SetupAttachment(SpringArm);

	Movement = CreateDefaultSubobject<UFloatingPawnMovement>(TEXT("Movement"));
	Movement->UpdatedComponent = Capsule; // Movement 컴포넌트가 이동을 업데이트할 때 기준이 되는 컴포넌트. 보통 RootComponent로 설정

	static ConstructorHelpers::FObjectFinder<USkeletalMesh> SKM_Stone_Golem(TEXT("/Game/Stone_Golem/mesh/SKM_Stone_Golem.SKM_Stone_Golem"));
	if(SKM_Stone_Golem.Succeeded())
	{
		SkeletalMesh->SetSkeletalMesh(SKM_Stone_Golem.Object);
	}
}

void AMyPawn::BeginPlay()
{
	Super::BeginPlay();
	
}

void AMyPawn::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	if (bIsJumpPressed)
	{
		UE_LOG(LogTemp, Warning, TEXT("Jump Pressing"));
	}
}


// [ 어떤 입력이 들어왔을 때 어떤 함수를 실행할지 연결(바인딩)하는 함수 ]
// 
// - PlayerController에 의해 “Possess”될 때 한 번 호출 
// - Axis 바인딩   => 매 프레임 호출
// - Action 바인딩 => 입력이 들어올 때 호출

void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	
	PlayerInputComponent->BindAxis(TEXT("UpDown"), this, &AMyPawn::UpDown);
	PlayerInputComponent->BindAxis(TEXT("LeftRight"), this, &AMyPawn::LeftRight);

	PlayerInputComponent->BindAction(TEXT("Jump"), IE_Pressed, this, &AMyPawn::JumpPressed);
	PlayerInputComponent->BindAction(TEXT("Jump"), IE_Released, this, &AMyPawn::JumpReleased);
}

void AMyPawn::UpDown(float value)
{
	if (!FMath::IsNearlyZero(value)) // 입력값은 float라서 완전히 0이 되는 경우는 거의 없기 때문에, IsNearlyZero 함수로 0에 가까운지 체크
	{
		UE_LOG(LogTemp, Warning, TEXT("UpDown: %f"), value);
	}

	AddMovementInput(GetActorForwardVector(), value); 	// Pawn의 앞 방향으로 value 만큼 이동
}

void AMyPawn::LeftRight(float value)
{
	if (!FMath::IsNearlyZero(value))
	{
		UE_LOG(LogTemp, Warning, TEXT("LeftRight: %f"), value);
	}

	AddMovementInput(GetActorRightVector(), value);
}

void AMyPawn::JumpPressed()
{
	bIsJumpPressed = true;
	UE_LOG(LogTemp, Warning, TEXT("Jump Pressed"));
}

void AMyPawn::JumpReleased()
{
	bIsJumpPressed = false;
	UE_LOG(LogTemp, Warning, TEXT("Jump Released"));
}


void AMyPawn::PostInitializeComponents()
{
	Super::PostInitializeComponents();

}

void AMyPawn::PossessedBy(AController* NewController)
{
	Super::PossessedBy(NewController);
}

 

 

 


 

사실 위 처럼 사용하는 방식은 Legacy 방식으로,

 

UE5 이후부터는 BindAxis, BindAction 방식보다 Enhanced Input을 더 많이 쓰는 편이라고 한다..!

 

하지만 이 개념들이 어느정도 잡혀있어야, 이후 Enhanced Input으로 넘어가는게 더 수월할 거라고 생각해 한번 정리해보았다..