Unreal Character Class(2)

정혜창·2025년 1월 23일
0

내일배움캠프

목록 보기
23/43

Enhanced Input System을 활용한 입력 매핑 구현

1. PlayerController 이해

1-1 PlayerController

  • PlayerController는 플레이어의 입력을 처리하고 게임 세계의 폰(Pawn)을 제어하는 언리얼 엔진의 핵심 클래스이다. 플레이어와 게임 세계 간의 다리역할을 하며, 폰을 직접 제어하지 않고 입력을 해석하여 폰에 명령을 전달한다. 멀티플레이어 환경에서는 각 플레이어마다 고유한 PlayerController가 생성된다.
    -> PlayerController는 플레이어 입력을 처리한다.

  • 입력이 처리되는 기본 흐름

    1. 키보드, 마우스 등 입력 장치로 부터 사용자 조작 신호가 들어온다.
    2. PlayerController가 받아서 해석한다.
    3. PlayerController가 현재 소유하고 있는 Pawn, Character에게 이동, 회전, 공격 등의 구체적인 명령을 내린다.

1-2 PlayerController 주요 역할

  • 플레이어의 입력 처리
    -키보드, 마우스, 게임패드 등의 입력을 받아 게임 내 동작으로 변환한다.

  • 카메라 관리

    • 카메라 제어 및 화면 회전, 줌 동작 등을 관리할 수 있다.
  • HUD 및 UI와의 상호작용

    • PlayerController는 HUD와 UI의 상호작용을 처리한다.
    • 커서 입력, 클릭 이벤트 등을 감지한다.
  • 폰 관리

    • PlayerController는 하나의 폰을 소유하며, 이를 통해 게임 세계와 상호작용한다.(Possess)
    • 새로운 폰을 스폰하거나 다른폰으로 전환하는 역할도 담당한다.(UnPossess)

1-3 PlayerController 클래스의 구조

PlayerControllerAController를 상속하며, 추가적인 입력 처리 및 플레이어 중심 로직을 제공한다.

클래스 상속 구조 : AActor - AController - APlayerController

주요 컴포넌트 :

  • Pawn : PlayerController가 제어할 폰 객체
  • PlayerInput : 입력 바인딩 및 처리를 담당
  • HUD : 게임 화면에 정보를 표시하는 HUD 객체

1-4 PlayerController의 주요 함수

1. Possess()

  • 폰(Pawn)을 소유하고 제어하기 위해 호출
  • PlayerControllerPossess()를 통해 폰과 연결된다.
    • 앞에서 배운 내용인 GameMode에서 DefaultPawnClass = ASpartaCharacter::StaticClass();로 기본 Pawn을 지정한거랑은 다른 의미이다.
    • GameMode를 통해서 월드에 Pawn을 스폰하고 PlayerController가 자동으로 해당 Pawn을 Possess해서 플레이어가 컨트롤이 가능해 지는 것이다.

2. UnPossess()

  • 현재 소유 중인 폰을 해제한다.

3. SetupInputComponent()

  • 입력을 바인딩하는 함수이다. 모든 입력 처리는 여기에서 설정 된다.

예시

void AMyPlayerController::SetupInputComponent()
{
	Super::SetupInputComponent();
    
    InputComponent->BindAxis("MoveForward", this, &AMyPlayerController::MoveForward);
    InputComponent->BindAxis("Turn", this, &AMyPlayerController::Turn);
}

4. GetPawn()

  • 현재 소유 중인 폰을 반환한다.
    APawn* ControlledPawn = GetPawn();

5. PlayerTick()

  • 매 프레일 호출되어 PlayerController의 틱 로직을 실행한다.

2. PlayerController C++ 클래스 생성

  • 다른 C++ 클래스를 만들 때 처럼 상속받을 부모클래스를 Player Controller를 선택하여 클래스를 생성한다. 실습에서는 SpartaPlayerController로 지정하였다.
  • 이후 Game모드에서 DefaultPawnClass를 지정해주었던 것처럼 PlayerControllerClass 또한 지정해주어야 한다.

SpartaGameMode.cpp

#include "SpartaGameMode.h"
#include "SpartaCharacter.h"
#include "SpartaPlayerController.h"

ASpartaGameMode::ASpartaGameMode()
{
	DefaultPawnClass = ASpartaCharacter::StaicClass();
    PlayerControllerClass = ASpartaPlayerController::StaticClass();
}

BP_SpartaGameMode에서 DefaultPawnClass를 설정해주었던 것과 마찬가지로 PlayerController를 블루프린트 클래스를 만들어서 BP_SprataGameMode에서 PlayerControllerClass를 설정해주도록 한다.


3. Enhanced Input System

언리얼 엔진의 Enhanced Input System은 기존의 입력 처리 시스템(Input Mapping System)을 대체하고 확장한 시스템이다. 더욱 유연하고 강력한 입력 관리 기능을 제공한다. 액션 중심의 입력 처리를 지원하며 여러 장치와 상황별 입력 처리를 더 쉽게 구현할 수 있도록 설계 되었다.

3-1 주요 개념

(1) 입력 액션(Input Action)

  • InputAction은 입력의 '의미'를 정의하는 추상적인 개념이다.

  • 단순히 키를 누르는 것에 국한되지 않고, 축, 데이터 처리(마우스 이동량) 및 디지털 입력(버튼 클릭)까지 처리할 수 있다.

  • 예시)

    • IA_Move: 캐릭터 이동
    • IA_Look: 카메라 회전
    • IA_Jump: 점프

(2) 입력 맵핑 컨텍스트(Input Mapping Context)

  • InputMappingContext는 입력 장치와 InputAction을 연결하는 매핑 테이블이다.
  • 특정 상황에서 활성화 되는 입력 컨텍스트를 정의할 수 있다.
  • 입력 우선순위를 설정하여 컨텍스트 간의 충돌을 방지한다.

3-2 입력처리 흐름

1. PlayerController가 Enhanced Input을 사용하도록 설정:

  • playerController는 Enhanced Input의 입력 데이터를 처리하도록 구성된다.

2. InputMappingContext 가 입력 장치와 액션을 맵핑:

  • InputMappingContext는 어떤 장치어떤 버튼어떤 액션에 연결되었는지 정의한다.

3. 입력 데이터가 InputAction에 전달:

  • 플레이어가 특정 키(또는 버튼)를 누르면, 입력 데이터가 InputAction에 전달 된다.
  • 예: W키를 누르면 IA_Move InputActiondl 이 활성화되고 이동 데이터가 전달된다.

4. PlayerController 또는 Pawn이 이를 처리:

  • PlayerController 또는 PawnInputAction 에서 전달된 데이터를 읽고, 실제 게임 동작(로직)을 수행한다.

4. PlayerController에서 IMC 활성화

4-1 변수 선언과 에셋 연결

에디터에서 IA_Move(FVector2D), IA_Look(FVector2D), IA_Jump(bool), IA_Sprint(bool)를 만들고 이들을 IMC에서 어떤 키와 연결할지 어느 축과 연결할지 세팅을 해주었다. 이제 이것들을 우리가 이전에 만들었던 PlayerController와 연결을 시켜주어야 한다.

우선 헤더파일에서 우리가 만든 IA파일들과 IMC를 멤버 변수로 선언하고 이를 에디터에서 지정할 수 있도록 리플렉션(UPROPERTY)처리 한다.

SpartaPlayerController.h

#pragma once

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

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

UCLASS()
class SPARTAPROJECT_API ASpartaPlayerController : public APlayerController
{
	GENERATED_BODY()

public:
	ASpartaPlayerController();

	// 에디터에서 세팅할 IMC
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
	UInputMappingContext* InputMappingContext;

	// 이후로는 IA를 지정할 변수들
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
	UInputAction* MoveAction;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
	UInputAction* LookAction;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
	UInputAction* JumpAction;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
	UInputAction* SprintAction;
};

SpartaPlayerController.cpp

#include "SpartaPlayerController.h"

// 초기화 리스트를 사용해서 IMC, IA 변수 초기화
ASpartaPlayerController::ASpartaPlayerController()
	: InputMappingContext(nullptr),
      MoveAction(nullptr),
      LookAction(nullptr),
      JumpAction(nullptr),
      SprintAction(nullptr) {}
      

이렇게 하고 ASpartaPlayerController를 상속받는 BP 클래스에서 우리가 만든 에셋들을 할당할 수 있다.

4-2 LocalPlayerSubsystem

이제 C++ 클래스에서 선언한 변수들에 우리가 만든 에셋들이 연결이 되었으므로 IMC를 활성화하는 코드를 작성하면 된다. Local Player Subsystem을 통해 Input Mapping Context를 활성화하거나 비활성화 할 수 있다.

우선 LocalPlayerSubsystem이 무엇인가에 대해 알아야 한다.
LocalPlayerSubsystem은 언리얼 엔진의 서브시스템 프레임워크의 일부로, 플레이어의 로컬 입력 및 로직을 관리하는데 사용된다. 특히 IMC와 같은 로컬 입력 관련 설정을 관리하는데 중요한 역할을 한다.

1. Subsystem 프레임 워크는 또 무엇인가?

Subsystem 프레임워크는 언리얼 엔진에서 특정 컨텍스트에서 동작하는 전역적이고 재사용 가능한 로직을 구현하는 데 사용된다. 여러 유형이 있다.

2. Local Player Subsystem과 Enhanced Input System

  • Enhanced Input System은 로컬 플레이어 수준에서 작동하는 InputSubsystem을 통해 관리된다.

  • UEnhancedInputLocalPlayerSubsystem이 바로 이 역할을 담당하며,(즉, Local Player의 Input Subsystem이 UEnhancedInputLocalPlayerSubsystem이다) 로컬 플레이어의 입력 데이터를 기반으로 동작한다.

  • ULocalPlayer 객체는 게임 실행 시 GameInstance 초기화 과정에서 생성된다. 기본적으로, 각 로컬 플레이어는 고유한 LocalPlayer 객체를 가진다. 그리고 PlayerController와 연결된다.

  • UlocalPlayer는 연결된 PlayerController를 통해 입력과 뷰포트를 관리한다.

  • Enhanced Input System은 전체 시스템의 "입력 액션 정의"와 "전체 입력 시스템의 핵심 역할"을 한다

  • UEnhancedInputLocalPlayerSubsystem은 Local Player의 Input Subsystem이면서 Enhanced Input System의 "하위 시스템"으로, 특정 로컬 플레이어의 입력 처리를 담당한다. 로컬 플레이어의 입력 컨텍스트를 추가하거나 특정 상황에 맞게 동작하도록 제어한다.

헤드 파일에서 virtual void BeginPlay() override; 추가

SpartaPlayerController.cpp

#include "SpartaPlayerController.h"
#include "EnhancedInputSubsystems.h" // Enhanced Input System의 Local Player Subsystem을 사용하기 위해 포함

ASpartaPlayerController::ASpartaPlayerController()
    : InputMappingContext(nullptr),
      MoveAction(nullptr),
      JumpAction(nullptr),
      LookAction(nullptr),
      SprintAction(nullptr)
{
}

void ASpartaPlayerController::BeginPlay()
{
	Super::BeginPlay()
    
    // PlayerController에 연결된 Local Player 객체를 가져옴
    if(ULocalPlayer* LocalPlayer = GetLocalPlayer())
    {	
        // Local Player에서 EnhancedInputLocalPlayerSubsystem을 가져옴
    	if(UEnhancedInputLocalPlayerSubsystem* Subsystem = 
        Localplayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
        {
        	if (InputMappingContext)
            {
            	// InputMappingContext이 할당되어 있다면
				// Subsystem을 통해 우리가 할당한 IMC 활성화
                // 0은 우선순위 Index
                Subsystem->AddMappingContext(InputMappingContext, 0);
            }
        }
    }
}
// InputMappingContext는 앞서 선언한 변수

이 로직으로 인해서 IMC에 정의된 IA와 키들이 PlayerController에 적용된다. 하지만 지금은 구현이 되지 않은 상태이므로 캐릭터가 움직이진 않는다.

회고

캐릭터 입력 매핑 활성화시키는것이 되게 어려운 개념이였다. Local Player가 뭔지, Enhanced Input system과 EnhancedInputLocalPlayerSubsystem은 어떻게 다른지 그리고 이 서브시스템을 통해 InputMappingContext를 추가 및 삭제를 할 수 있는지 ... 이제야 조금 가닥이 잡히지만 처음엔 이름도 너무 길고 개념이 너무 추상적일 때도 있고 많아서 힘들었던 것 같다.

profile
Unreal 1기

0개의 댓글

관련 채용 정보