언리얼 - 엔진 14 : 캐릭터 입력 구현 Enhanced Input System

김정환·2025년 4월 11일
0

Unreal Engine

목록 보기
15/24

PlayerController

  • GameMode에서 사용자의 입력을 처리하는 클래스.
    • 사용자가 키보드, 마우스, 게임패드 등에서 입력을 받으면 그 입력을 해석하여 캐릭터나 다른 오브젝트에게 동작을 명령하는 핵심 클래스
  • 언리얼 엔진의 중요 철학 : 플레이어 입력은 PlayerController에서 처리한다. (SPR)
    • 이를 통해 입력 처리 로직과 실제 캐릭터의 동작 로직을 분리할 수 있음.
    • 코드를 구조적으로 관리하기가 훨씬 수월해짐.
  • 입력이 처리되는 기본 흐름
    1. 키보드, 마우스, 게임 패드 등 입력 장치로부터 사용자 조작 신호 수신
    2. 조작 신호를 PlayerController가 해석
    3. PlayerController가 현재 소유(Possess)하고 있는 Pawn에게 이동, 회전, 공격 등 구체적인 명령을 내림
  • 특히 멀티플레이 환경에서는, 각 플레이어마다 개별 PlayerController가 생성되어
    여러 사용자의 입력을 충돌없이 분리하고 관리할 수 있음.

주요기능

입력 처리

  • 다양한 입력 장치의 이벤트를 처리
  • UE5에서 제공하는 Enhanced Input 시스템을 이용하면 액션, 축 매핑을 보다 체계적으로 설정할 수 있음.
  • C++에서는 SetupInputComponent() 함수를 오버라이드해서 구현
  • BP에서는 이벤트 그래프를 통해 입력 로직을 구현

카메라 제어 로직

  • 마우스나 게임패드의 축 입력을 받아 캐릭터의 시점 회전이나 줌 인/아웃 같은 카메라 동작을 수행

HUD 및 UI와의 상호작용

  • UMG (언리얼 모션 그래픽) 기반 UI를 통해 버튼 클릭, 드래그, 터치 등의 이벤트를 PlayerController에서 받을 수 있음.
    • 인벤토리 열기, 스킬 사용 등의 명령을 UI에서 트리거하면
      PlayerController가 이를 해석해 Pawn 또는 GameMode 등 다른 시스템으로 전달

Possess / UnPossess

  • 특정 Pawn에 빙의 (Possess)하여 해당 Pawn을 제어
    • UnPossess() 함수로 Pawn과 연결을 해제하고 다른 Pawn을 제어할 수도 있음.
  • 멀티플레이 시, 각 플레이어마다 고유의 PlayerController가 있고
    이 컨트롤러가 특정 Pawn을 소유함으로써 서로 다른 캐릭터 조작이 가능.

PlayerController C++ 클래스 생성

  • PlayerController 클래스를 상속받아 작성.
// .h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "Cp2PlayerController.generated.h"

UCLASS()
class CHAPTER2_API ACp2PlayerController : public APlayerController
{
	GENERATED_BODY()
};

// .cpp
#include "Cp2PlayerController.h"
  • GameMode에 새로 작성한 CP2PlayerController 적용
    • DefaultPawnClass를 지정했던 것과 동일하게 할당
// .cpp
#include "Cp2GameMode.h"
#include "Cp2Character.h"
#include "Cp2PlayerController.h"

ACp2GameMode::ACp2GameMode()
{
	DefaultPawnClass = ACp2Character::StaticClass();	// 객체를 생성하지 않고 클래스를 반환해서 넣어줄 것임.
	PlayerControllerClass = ACp2PlayerController::StaticClass();
}
  • Cp2PlayerController 클래스를 BP로 래핑(Wrap).
    • 확인해보면 기본값으로 BP가 아닌 클래스가 들어가 있음.
    • 필요하다면 다음과 같이 BP로 변경해줄 것.
  • 플레이해보면 직접 작성한 GameMode와 거기에 할당했던 BP 액터들이 Spawn 돼 있음.

Enhanced Input System

  • 이전 버전에서 사용하던 Input 시스템을 확장, 대체하기 위해서 UE5부터 Enhanced Input 시스템을 제공함.
  • Enhanced Input 시스템은 입력 설정을 입력 맵 Input Mapping Context (IMC)
    입력 액션 Input Action (IA)이라는 개념으로 나눠 관리

Input Action (IA)

  • Input Action (IA) 은 캐릭터의 이동, 점프, 발사 등과 같이 특정 동작을 추상화한 단위.
    • WASD 이동을 담당하는 IA_Move, 스페이스바 점프를 담당하는 IA_Jump 등을 만들 수 있음.

생성 방법

Content Browser에서 우클릭 > Input > Input Action을 선택

주요 속성

1. Value Type

  • 입력 동작을 발생시킬 때, 어떤 유형의 값을 제공할지 결정
  • Bool (참/거짓)
    • 단순 On/Off 토글 입력
    • 예) 점프(스페이스바), 공격(마우스 왼쪽 버튼)
  • Axis1D (1차원 축 값)
    • 단일 축 (-1~1 범위)의 입력
    • 예) 게임패드 트리거(가속 페달), 전진/후진(W/S)
  • Axis2D (2차원 축 값)
    • X, Y 두 축을 동시에 처리
    • 예) 캐릭터 이동(WASD), 마우스 이동(가로+세로)
  • Axis3D (3차원 축 값)
    • X, Y, Z 세 축을 동시에 처리
    • 예) 비행 시뮬레이션에서 3축 제어

2. Trigger

  • 입력이 활성화되는 특정 조건
  • Pressed Trigger: 키를 누르는 순간에만 작동.
  • Hold Trigger: 키를 일정 시간 눌렀을 때 작동.
  • Released Trigger: 키를 뗄 때 작동.

등등

3. Modifier

  • 입력 값을 수정하거나 변환하기 위한 설정
  • Scale : 입력 값에 일정 배율을 곱해줌 (마우스 이동 속도 2배)
  • Negate : 입력 값을 반전 (상하 반전 카메라)
  • Deadzone : 일정 임계값보다 작은 입력은 무시 (게임패드 조이스틱 미세 떨림 방지)

사용 예

이동, 점프, 시점 회전, 스프린트 버튼 등을 적용해볼 것.

이동 IA_Move

  • 이동은 보통 WASD 또는 방향키로 입력받아서 앞뒤, 좌우와 같이 2개의 축으로 구현함.
    • Value Type을 Axis2D (Vector2D)로 설정해서 입력값을 Vector2D로 받도록 설정.
  • IA_Move는 상시 활성화 상태 에서 wasd 입력으로 구현할 것이므로
    Trigger나 Modifier는 특별히 필요하지 않음.

점프 IA_Jump

  • 스페이스바를 누르면 점프할 것.
    • Value Type을 Bool로 설정.
  • 점프 동작은 단순하게 On/Off로 동작할 것이라 별도의 옵션이 필요없음.

시점 회전 IA_Look

  • 마우스 입력은 항상 가로 (X축, 좌/우)와 세로 (Y축, 위/아래) 움직임을 동시에 포함.
    • Value Type을 Axis2D로 설정

스프린트 IA_Sprint

  • Shift 키 값으로 속도를 늘리거나 줄이고를 설정
    • Value Type을 Bool로 설정.

Input Mapping Context (IMC) 설정

  • Input Mapping Context (IMC)는 여러 개의 IA들을 한데 모아놓은 매핑 설정 파일
    • 플레이어 기본 이동, 점프, 시점 전환을 하나의 IMC에 넣고,
      UI 전용 입력을 다른 IMC로 분리하는 식으로 관리 가능
    • 게임 진행 중 특정 상황에서 IMC를 활성(Enable)하거나 비활성(Disable)하여 입력을 제어 가능

IMC 생성 방법

  • Content Browser 우클릭 > Input > Input Mapping Context 선택
  • 생성하고 Mappings에 만들어둔 Input Action들을 할당해줌.

Input Mapping Context (IMC) 맵핑

IA_Move 맵핑

  • WASD로 움직임을 맵핑할 것.
    • Swizzle Input Axis Values : 입력 축 (Axis)을 변환하거나 재구성하는 기능
      • UE는 입력 시스템에서는 입력 데이터를 X, Y, Z 축 중 하나로 맵핑함.
      • 만약 입력값이 올바른 축에 맞지 않는다면 특정 축으로 재배치하거나 변환할 수 있음.
    • W 키 : 앞
      • 입력 값이 X축 (앞뒤 방향)에 맞춰 정렬
      • 전진은 X축으로 +1(양의 값)이므로 추가적인 변환은 필요 없음.
        • 키의 입력을 받으면 1, 받지 않으면 0.
    • S 키 : 뒤
      • Swizzle로 X축 (앞뒤 방향)에 맞춰 정렬
      • 후진은 X축으로 -1(음의 값)이므로 Negate Modifier 추가
    • A 키 : 왼쪽
      • 입력 값이 Y축 (좌우 방향)에 맞춰 정렬
      • 왼쪽은 Y축으로 -1이므로 Negate 설정
    • D 키 : 왼쪽
      • 입력 값이 Y축 (좌우 방향)에 맞춰 정렬
      • 왼쪽은 Y축으로 +1이므로 별도 변환이 필요없음.

IA_Jump 맵핑

  • 스페이스바를 눌렀을 때 On/Off로 동작
    • 별도의 동작은 필요없음.

IA_Look 맵핑

  • 마우스 움직임을 통해 Yaw(좌우 회전)과 Pitch(상하 회전) 값을 동시에 전달받음.
    • Axis2D로 지정한 X축, Y축 값을 게임 내 좌표계에 맞춰 회전에 반영
    • 기본적으로 마우스 Y축의 움직임은 위(+), 아래(-)로 전달됨.
      • 하지만, 카메라 상하 회전(Pitch)은 엔진의 좌표계에서 위(-), 아래(+)로 작동하는 경우가 많음.
      • 따라서, Y축 값에 대해서만 Negate 적용
        • 마우스 위(+) Negate -> 위(-) : 카메라 위로
        • 마우스 아래(-) Negate -> 위(+) : 카메라 아래로
    • 마우스 X축 (좌우 회전, Yaw)의 경우, 입력과 엔진의 좌표계가 일치함.
      • 오른쪽 -> 양수 (+)
      • 왼쪽 -> 음수(-)

IA_Sprint 맵핑

  • Shift 키를 누르면 On/Off 형태로 동작할 것. (점프와 동일)

PlayerController에서 IMC 활성화

코드 작성

// .h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "Cp2PlayerController.generated.h"

class UInputMappingContext; // IMC 전방 선언
class UInputAction;			// IA 전방 선언

UCLASS()
class CHAPTER2_API ACp2PlayerController : public APlayerController
{
	GENERATED_BODY()

public:
	ACp2PlayerController();
	
    // 에디터에서 쓸 IMC
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Input")
	UInputMappingContext* InputMappintContext;

	// IA_Move 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
	UInputAction* MoveAction;
    // IA_Jump 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
	UInputAction* JumpAction;
    // IA_Look 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
	UInputAction* LookAction;
    // IA_Sprint 변수
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
	UInputAction* SprintAction;

protected:
	virtual void BeginPlay() override;
};

// .cpp
#include "Cp2PlayerController.h"
#include "EnhancedInputSubsystems.h"


ACp2PlayerController::ACp2PlayerController() 
	: InputMappintContext(nullptr),
	MoveAction(nullptr),
	JumpAction(nullptr),
	LookAction(nullptr),
	SprintAction(nullptr)
{
}

BP 클래스 생성 및 할당

  • 이렇게 에디터에서 할당할 수 있도록하고 BP 클래스 생성.
    • IMC와 IA들을 할당.

IMC 활성화 코드 작성

  • Enhanced Input System은 Local Player Subsystem을 통해 Input Mapping Context를 활성화하거나 비활성화할 수 있음.
  • Local Player Subsystem
    • 게임이 실행되면 UE는 각 플레이어를 표현하기 위해 Local Player 객체를 생성.
      • 싱글 플레이에서는 하나의 Local Player
      • 로컬 멀티 플레이에서는 플레이어 수만큼 Local Player 생성
    • UEnhancedInputLocalPlayerSubsystem은 Local Player에 부착되어 해당 플레이어가 사용할 입력 매핑(IMC)을 관리
    • 이를 통해 플레이 중에 동적으로 다른 IMC를 추가, 제거하여 입력 모드를 전환할 수 있음.
      • 사용 예시) 전투 중 (IMC_Character) -> UI 창 열림 (IMC_UI) -> UI 닫고 다시 (IMC_Character)
  • BeginPlay()에서 IMC를 활성화해볼 것
#include "Cp2PlayerController.h"
#include "EnhancedInputSubsystems.h"


ACp2PlayerController::ACp2PlayerController() 
	: InputMappintContext(nullptr),
	MoveAction(nullptr),
	JumpAction(nullptr),
	LookAction(nullptr),
	SprintAction(nullptr)
{
}

void ACp2PlayerController::BeginPlay()
{
	Super::BeginPlay();

	// imc 활성화
	if (ULocalPlayer* localPlayer = GetLocalPlayer())
	{
		if (UEnhancedInputLocalPlayerSubsystem* subSys = 
			localPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>()) 
		{
			if(InputMappintContext)
			{
				subSys->AddMappingContext(InputMappintContext, 0); // 우선 순위 0 설정
			}
		}
	}
}
  • #include "EnhancedInputSubsystems.h"
    • Enhanced Input System의 Local Player Subsystem을 사용하기 위해 포함
  • GetLocalPlayer()
    • PlayerController가 관리하는 Local Player를 반환.
  • GetSubsystem<UEnhancedInputLocalPlayerSubsystem>()
    • Local Player에 부착된 Enhanced Input Subsystem을 반환
    • AddMappingContext(), RemoveMappingContext() 등을 호출해서 입력 매핑을 동적으로 제어할 수 있음.
  • AddMappingContext()
    • 주어진 IMC를 Subsystem에 추가하여 입력 매핑을 활성화
    • 매개변수
      • 활성화할 IMC
      • 우선순위
    • 이 함수를 여러 번 호출해 여러 IMC를 활성화할 수 있음.
    • 우선순위를 달리 부여해, 특정 IMC가 다른 IMC보다 우선순위가 높도록 설정 가능
  • IMC에 정의된 모든 IA와 키 매핑이 이 PlayerController에 적용됨
profile
만성피로 개발자

0개의 댓글