본문 바로가기

언리얼 + cpp

언리얼C++ 5일차(컨트롤러, 인풋시스템, IA, IMC)

플레이어 컨트롤러

입력장치(키보드, 마우스, 게임패드 등)에서 입력을 하면 플레이어 컨트롤러에서 입력을 받고 플레이어 컨트롤러가 소유하고 있는 폰에게 명령을 내린다.

주요 기능

1. 다양한 입력장치의 이벤트를 처리한다.

2. 마우스나 게임패드의 축 입력을 받아 카메라 동작을 수행할 수 있다.

3. 언리얼의 UMG 기반 UI를 통해 버튼 클릭, 드래그, 터치 등의 이벤트를 컨트롤러에서 받을 수 있다.

(인벤토리 열기, 스킬 사용 등의 명령을 UI에서 트리거하면 컨트롤러가 해석해 폰, 게임모드 등 다른 시스템으로 전달 가능)

4. 특정 폰에 빙의해서 폰을 제어하고 필요할 때 Unpossess로 연결을 해제하고 다른 폰과 연결이 가능하다.

5. 멀티플레이 시 각 플레이어마다 고유한 컨트롤러가 있어 서로 다른 캐릭터 조작이 가능하다.

클래스 생성

플레이어 컨트롤러 C++파일을 생성한 후 게임모드의 컨트롤러로 지정한다.

#include "FirstGameMode.h"
#include "JinCharacter.h"
#include "JinPlayerController.h"

AFirstGameMode::AFirstGameMode()
{
	DefaultPawnClass = AJinCharacter::StaticClass();
	PlayerControllerClass = AJinPlayerController::StaticClass();
}

PlayerControllerClass는 GameMode가 제공하는 속성으로, 게임 시작 시 사용할 PlayerController 타입을 지정합니다.

AJinPlayerController::StaticClass()는 언리얼 엔진이 AJinPlayerController클래스의 정보를 런타임에 참조할 수 있도록 제공하는 정적 함수입니다.

위 코드를 저장 후 프로젝트 빌드를 완료하면, 언리얼 에디터에서 GameMode가 SpartaPlayerController를 기본 PlayerController로 인식하게 됩니다.

C++로 만든 컨트롤러 클래스를 손쉽게 편집할 수 있도록 블루프린트로 래핑하는 과정을 거친다.(C++ -> 블루프린트로 만들기)

 

게임모드의 Player Controller Class를 만든 BP_컨트롤러로 바꾼다.

게임을 실행해서 아웃라이너에 생성이 잘 되는지 확인한다.

인핸스드 인풋 시스템

입력 설정을 “입력 맵(Input Mapping Context, IMC)”과 “입력 액션(Input Action, IA)”이라는 개념으로 나누어 관리한다.

IA와 IMC는 C++가 아닌 언리얼엔진 에디터에서 생성한다.

인풋 액션(IA)

IA는 캐릭터의 이동, 점프, 발사, 줌 등과 같이 특정 동작을 추상화한 단위이다.

이동은 IA_Move, 점프는 IA_Jump, 마우스 회전(시점)은 IA_Look 등으로 만들 수 있다.

Value Type

IA가 입력 동작을 발생시킬 때 어떤 유형의 값을 제공할지 결정하는 옵션이다.

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

트리거

입력이 활성화되는 특정 조건을 말한다.

  • Pressed Trigger: 키를 누르는 순간에만 작동.
  • Hold Trigger: 키를 일정 시간 눌렀을 때 작동.
  • Released Trigger: 키를 뗄 때 작동.

모디파이어

입력 값을 수정하거나 변환하기 위한 설정이다.

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

인풋 매핑 컨텍스트(IMC)

IMC는 여러 개의 IA를 모아놓은 매핑 설정 파일이다.

예를 들어 플레이어 기본 이동, 점프, 시점 전환 을 하나의 IMC에 넣고 UI 전용 입력을 다른 IMC로 분리하는 식으로 관리할 수 있다.

게임 진행 중 특정 상황에서 IMC를 활성화, 비화성화 하여 입력을 제어할 수 있다.

IMC에서 생성한 IA들을 어떤 키로 입력 받을건지 알맞게 매핑한다.

플레이어 컨트롤러에서 IMC 활성화 하기

플레이어 컨트롤러 헤더에 IA와 IMC를 C++ 멤버 변수로 선언하고 에디터에서 지정할 수 있도록 리플렉션 처리를 한다.

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
	UInputMappingContext* InputMappingContext;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
	UInputAction* Move;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
	UInputAction* Jump;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
	UInputAction* Look;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
	UInputAction* Sprint;

생성자 멤버 초기화 리스트로 변수를 nullptr로 초기화한다.

AJinPlayerController::AJinPlayerController()
	: InputMappingContext(nullptr),
	Move(nullptr),
	Jump(nullptr),
	Look(nullptr),
	Sprint(nullptr)
{
}

이렇게 선언해두면 에디터나 블루프린트에서 해당 멤버 변수에 만든 IA와 IMC를 할당할 수 있다.

 

이제 C++에서 실제로 IMC를 활성화 하는 코드를 작성한다.

언리얼 5의 인핸스드 인풋 시스템은 Local Player System을 통해 IMC를 활성화하거나 비활성화한다.

Local Player System

게임이 실행될 때 언리얼은 각 플레이어를 표현하기 위해 Local Player 객체를 생성한다.

 

싱글플레이어 상황에서는 하나의 로컬 플레이어, 로컬 멀티플레이(한 화면에서 여러 명 플레이)라면 플레이어 수 만큼 로컬 플레이어가 생성된다.

 

UEnhancedInputLocalPlayerSubsystem은 로컬 플레이어에 부착되어 해당 플레이어가 사용할 IMC를 관리한다.

이를 통해 플레이 중에 동적으로 다른 IMC를 추가, 제거하여 입력 모드를 전환할 수 있다.

예시) 전투중(IMC_Character) -> UI창 열림(IMC_UI) -> 전투 종료 후 다시(IMC_Character)

 

플레이어 컨트롤러.cpp에서 블루프린트에서 지정해둔 IMC를 활성화 하는 코드를 추가한다.

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

	if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
	{
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem =
			LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
		{
			if (InputMappingContext)
			{
				Subsystem->AddMappingContext(InputMappingContext, 0);
			}
		}
	}
}
  • GetLocalPlayer()
    • 현재 PlayerController가 관리하는 Local Player를 반환합니다.
  • GetSubsystem<UEnhancedInputLocalPlayerSubsystem>()
    • 해당 Local Player에 부착된 Enhanced Input Subsystem을 반환합니다.
    • 이를 통해 AddMappingContext나 RemoveMappingContext 등을 호출하여 입력 매핑을 동적으로 제어할 수 있습니다.
  • AddMappingContext()
    • 주어진 IMC를 Subsystem에 추가하여 입력 매핑을 활성화합니다.
    • SpartaInputMappingContext: 활성화할 IMC.
    • 0: 우선순위. 낮을수록 높은 우선순위를 가집니다.
    • 이 함수를 여러 번 호출해 여러 IMC를 활성화할 수도 있습니다.
      • 우선순위를 달리 부여해, 특정 IMC가 다른 IMC보다 우선순위가 높도록 설정할 수도 있습니다.

아직 이 부분은 이해가 잘 되지 않지만 공부를 더 한 후에 다시 볼 예정이다.

 

적용한 IMC가 잘 연결됐는지 확인해본다.

플레이어 컨트롤러 블루프린트의 이벤트 그래프에서 만들어 둔 입력 액션 이벤트들을 메세지 출력하는 노드와 연결하여 매핑한 키를 눌러서 잘 출력이 되는지 확인해보면 된다.