본문 바로가기

언리얼5/언리얼5 개발

UE5 향상된 입력 Unreal C++ 에서 사용방법

UE Input System 구조

https://docs.unrealengine.com/4.27/ko/InteractiveExperiences/Input/

 

입력

Input 오브젝트는 플레이어로부터의 입력을 액터가 이해하고 활용할 수 있는 형태의 데이터로 변환하는 작업을 담당합니다.

docs.unrealengine.com


입력

언리얼의 입력 구조에 대해 이해하고 현제 언리얼5에서 입력 이벤트 처리에 사용되는 향상된 입력 기능을 활용하여

컨텐츠 구현 알아보겠습니다.

 

글을 통해 알수있는것들

  • 언리얼 입력 시스템의 처리 플로우
  • 향상된 입력 사용법

Input 오브젝트

Input 오브젝트는 플레이어로부터의 입력을 액터가 이해하고 활용할 수 있는 형태의 데이터로 변환하는 작업을 담당합니다.

 

PlayerInput

PlayerInput 은 PlayerController 클래스 안에서 플레이어 입력을 관리하는 UObject 이며, 클라이언트에서만 스폰됩니다. PlayerInput 안에는 ActionMappings,AxisMappings 구조체가 둘 정의됩니다. 

  • ActionMappings  - 점프 ,공격 등의 트리거와 같은 경우
  • AxisMappings - 이동 ,마우스, 등의 연속적인 플레이어의 인풋을 사용하는 경우

InputComponent

inputComponent 는 프로젝트의 AxisMappings 와 ActionMappings 를 보통 C++ 나 블루프린트 그래프로 구성된 게임 액션에 연결시킵니다.

 

 

언리얼 인풋 시스템 플로우 차트

 

 

1. 플레이어가 하드웨어(키보드 ,마우스 ,조이스틱)에서 인풋이 일어난다.

2. 받은 인풋값을 player input 2개의 구조체 타입으로 매핑한다.

3. InputComponent에서 분리된 구조체 매핑을 C++ , 블루프린트에게 우선순위에 맞게 전달한다.

4. 플레이어 컨트롤러 확인

5. 레벨 블루프린트 확인

6. 폰 마지막 확인

7. 게임 로직에 반영


향상된 입력 Enhanced Input

기존 사용해왔던 언리얼 입력 시스템은 버그, 게임 로직에서 입력 코드를 같이 사용하거나 확장성의 제한등의 불편함이 있어 이를 보안하기 위해 현제는 향상된 입력 시스템이 사용됩니다.

 

https://docs.unrealengine.com/4.27/ko/InteractiveExperiences/Input/EnhancedInput/

 

enhanced input

Using the Enhanced Input Plugin to read and interpret user input

docs.unrealengine.com

 

향상된 입력 주요 기능

향상된 입력 시스템에는 InputAction,Input Mapping Contexts map,Modifiers,Triggers 네 가지 주요 개념이 존재합니다.

이번 글은 제가 주로 사용하는 두가지 계념인 InputActions와 InputMapping Contexts map 두가지만 다룹니다.

  • InputAction 
    향상된 입력 시스템과 프로젝트 코드 간의 통신 링크입니다. InputAction 시스템으로 입력값을 제어하면 좋은 장점은
    입력값에 두개의 축값을 표현할수있다는 장점을 가집니다. 이동은 방향과 속도를 설명하기위해 두개의 축이 필요로하는경우 우리는
    InputAction을 활용하여 효율적인 코드 제어가 가능해집니다.
  • InputMappingContextsMap
    사용자의 입력을 작업에 매핑하여 각 사용자에 대해 동적으로 추가 제거 또는 우선순위를 지정할수있습니다.
    향상된 입력 로컬 플레이어 하위(Enhanced Input Local Player Subsystem) 시스템을 통해 하나 이상의 컨텍스트를 로컬 플레이어에 적용 하고 우선순위를 지정하여 동일한 입력을 사용하려는 여러 작업 간의 충돌을 해결할 수 있습니다.

실습

실습은 C++로 향상된 인풋 시스템 사용법과 블루프린트로 셋업 두가지로 간단한 설명글과 이미지를 공개합니다.

 

코드

 

1. 프로젝트에 향상된 입력 플러그인 체크

 

2. Build.cs  향상된 인풋 시스템 모듈 추가

// Fill out your copyright notice in the Description page of Project Settings.

using UnrealBuildTool;

public class MHProject : ModuleRules
{
	public MHProject(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;     
		
		PublicIncludePaths.AddRange(new string[] {"MHProject"});
	
		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore","EnhancedInput" });

		PrivateDependencyModuleNames.AddRange(new string[] {  });

		// Uncomment if you are using Slate UI
		// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
		
		// Uncomment if you are using online features
		// PrivateDependencyModuleNames.Add("OnlineSubsystem");

		// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
	}
}

 

3.InputMappingContent , InputAction 생성

 

  InputMappingContext 초기화

  1. DefaultMappingContent 초기화
  2. InputActions 초기화 
  3. 인풋 로컬 플레이어 서브 시스템의 레퍼런스를 로컬 플레이어에서 가져온다.
  4. 플레이어 서브 시스템 초기화된 DefualtMappingContent를 0번 플레이어에게 MappingContext를 추가한다.

 

//Player.cs

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "MHCharacterBase.h"
#include "InputActionValue.h"
#include "MHCharacterPlayer.generated.h"

/**
 * 
 */
UCLASS()
class MHPROJECT_API AMHCharacterPlayer : public AMHCharacterBase
{
	GENERATED_BODY()
public:
	AMHCharacterPlayer();

protected:
	virtual  void BeginPlay() override;

public:
	virtual  void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override;
	
	
protected:
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category= Camera, meta =(AllowPrivateAccess = "true"))
	TObjectPtr<class USpringArmComponent> CameraBoom;

	//meta =(AllowPrivateAccess = "true") 폐쇠한전자에서도 블루프린트로 접근이 가능하게끔 사용이 가능하다.
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category= Camera, meta =(AllowPrivateAccess = "true"))
	TObjectPtr<class UCameraComponent> FollowCamera;
protected:
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category= Camera, meta =(AllowPrivateAccess = "true"))
	TObjectPtr<class UInputMappingContext> DefaultMappingContext;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category= Camera, meta =(AllowPrivateAccess = "true"))
	TObjectPtr<class UInputAction> JumpAction;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category= Camera, meta =(AllowPrivateAccess = "true"))
	TObjectPtr<class UInputAction> MoveAction;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category= Camera, meta =(AllowPrivateAccess = "true"))
	TObjectPtr<class UInputAction> LookAction;

	void Move(const FInputActionValue& Value);
	void Look(const FInputActionValue& Value);
	
};

 

 

 

//Player.cs

#include <MHCharacterPlayer.h>
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h" 

#include	"InputMappingContext.h"
#include	"EnhancedInputComponent.h"
#include	"EnhancedInputSubsystems.h"
#include 	"MHPlayerController.h"

AMHCharacterPlayer::AMHCharacterPlayer()
{
	CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	CameraBoom->SetupAttachment(RootComponent);
	CameraBoom->TargetArmLength = 400.0f;
	CameraBoom->bUsePawnControlRotation = true;

	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
	FollowCamera->SetupAttachment(CameraBoom,USpringArmComponent::SocketName);
	FollowCamera->bUsePawnControlRotation = false;

	static ConstructorHelpers::FObjectFinder<UInputMappingContext> InputMappingContextRef(TEXT("/Script/EnhancedInput.InputMappingContext'/Game/ThirdPerson/Input/IMC_Default.IMC_Default'"));
	if(InputMappingContextRef.Object)
	{
		DefaultMappingContext = InputMappingContextRef.Object;
	}

	
	static ConstructorHelpers::FObjectFinder<UInputAction> InputActionMoveRef(TEXT("/Script/EnhancedInput.InputAction'/Game/ThirdPerson/Input/Actions/IA_Move.IA_Move'"));
	if(InputActionMoveRef.Object)
	{
		MoveAction = InputActionMoveRef.Object;
	}

	static ConstructorHelpers::FObjectFinder<UInputAction> InputActionJumpRef(TEXT("/Script/EnhancedInput.InputAction'/Game/ThirdPerson/Input/Actions/IA_Jump.IA_Jump'"));
	if(InputActionJumpRef.Object)
	{
		JumpAction = InputActionJumpRef.Object;
	}

	static ConstructorHelpers::FObjectFinder<UInputAction> InputActionLookRef(TEXT("/Script/EnhancedInput.InputAction'/Game/ThirdPerson/Input/Actions/IA_Look.IA_Look'"));
	if(InputActionLookRef.Object)
	{
		LookAction = InputActionLookRef.Object;
	}
	
}

void AMHCharacterPlayer::BeginPlay()
{
	Super::BeginPlay();
	const AMHPlayerController* PlayerController = CastChecked<AMHPlayerController>(GetController());
	if(UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
	{
		Subsystem->AddMappingContext(DefaultMappingContext,0);
	}
}

void AMHCharacterPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	
	UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent);

	EnhancedInputComponent->BindAction(JumpAction,ETriggerEvent::Triggered,this,&ACharacter::Jump);
	EnhancedInputComponent->BindAction(JumpAction,ETriggerEvent::Completed,this,&ACharacter::StopJumping);
	EnhancedInputComponent->BindAction(MoveAction,ETriggerEvent::Triggered,this,&AMHCharacterPlayer::Move);
	EnhancedInputComponent->BindAction(LookAction,ETriggerEvent::Triggered,this,&AMHCharacterPlayer::Look);
	
}

void AMHCharacterPlayer::Move(const FInputActionValue& Value)
{
	UE_LOG(LogTemp,Log,TEXT("when call Move"));
	
	const FVector2D MovementVector = Value.Get<FVector2D>();

	const FRotator Rotation = Controller->GetControlRotation();
	const FRotator YawRotation(0,Rotation.Yaw,0);

	const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
	const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);

	AddMovementInput(ForwardDirection,MovementVector.Y);
	AddMovementInput(RightDirection,MovementVector.X);
		
}

void AMHCharacterPlayer::Look(const FInputActionValue& Value)
{
	const FVector2D LookAxisVector = Value.Get<FVector2D>();

	AddControllerYawInput(LookAxisVector.X);
	AddControllerYawInput(LookAxisVector.Y);
}

 

이후 추가되는 입력도 기존코드와 동일하게 Setup Player Input에서 반복코딩하여 추가한다.


블루 프린트

 

InputMappingContext 초기화

  1. 플레이어 BP 오브젝트에서 playerController를 가져온다.
  2. 코드와 동일하게 가져온 플레이어에서 케스팅한 플레이어 서브시스템으로 IMC_Player(인풋맵핑컨테스트)를 AddMpping 한다.

 

InputAction 사용

 


Input 제어

EnableInput(ControllerClass)
DisableInput(ControllerClass)

 

'언리얼5 > 언리얼5 개발' 카테고리의 다른 글

UE Fade 기능 만들기  (2) 2024.04.06
GA 유용한 가상 함수  (0) 2024.03.31
UE Hpbar 만들기  (0) 2024.03.29
UE 헤드업 디스플레이 (공부 정리)  (0) 2024.03.25
UE 아이템 시스템 (공부 정리)  (0) 2024.03.24