보키_기록용

UE5 Enhanced Input으로 카메라 터치 조작하기(Pan Camera) 본문

언리얼/Enhanced Input System

UE5 Enhanced Input으로 카메라 터치 조작하기(Pan Camera)

bokki0117 2023. 3. 21. 18:40

Lyra 프로젝트를 보면 LyraHeroComponent에 Input_LookMouse()에 해당되는 마우스로 화면을 움직이는 조작을 모바일 터치조작(Pan)방식으로 하는 방법을 정리한다.

 

※ Pan 조작이란?

손가락을 댄 후, 손을 떼지 않고 계속적으로 드래그하는 움직임.

출처 : https://blog.naver.com/vinylx/220001249367

Enhanced Input 적용방식 참조 : https://bokki0117.tistory.com/33

 

C++에서 Enhanced Input System 사용하기

Lyra 게임을 살펴보다가 테스트용으로 Enhanced Input System이라는 것을 적용해보기로 했다. Enhanced Input 핵심 요소 입력 액션(Input Actions) : Enhanced Input System과 프로젝트 코드 사이의 통신 링크. 점프하

bokki0117.tistory.com


위 링크에서 보았듯이, Enhanced Input에서 Input을 추가하려면 

  • InputAction
  • InputMappingContext에 만든 InputAction 설정
  • InputConfig에 만든 InputAction 설정
  • 실제 코드와 바인딩

과정이 필요하다.

 

1. InputAction 생성

IA_PanCamera

값 타입을 Axis2D(Vector2D)로 하는 InputAction을 생성한다.

 

2. InputMappingContext에 만든 InputAction 설정

 

3.InputConfig에 만든 InputAction 설정

InputConfig에서 설정하기 전에 Enhanced Input은 Tag로 코드와 바인딩하기 때문에 Tag를 생성해야 한다.

GameplayTag 클래스에서 InputTag_PanCamera를 추가한다.

//TestGameplayTag.h
#pragma once

#include "CoreMinimal.h"
#include "GameplayTagContainer.h"

class UGameplayTagsManager;
/**
 * 
 */
struct DEDISERVERTEST_API FTestGameplayTags : public FNoncopyable
{
public:

	static const FTestGameplayTags& Get() { return GameplayTag; }

	static void InitializeNativeTags();

	FORCEINLINE const FGameplayTag& Move() const { return InputTag_Move; }
	FORCEINLINE const FGameplayTag& LookMouse() const { return InputTag_Look_Mouse; }
	FORCEINLINE const FGameplayTag& Jump() const { return InputTag_Jump; }
    	// PanCamera 추가!
    	FORCEINLINE const FGameplayTag& PanCamera() const { return InputTag_PanCamera; } 

protected:

	void AddAllTags(UGameplayTagsManager& Manager);

	void AddTag(FGameplayTag& OutTag, const ANSICHAR* TagName, const ANSICHAR* TagComment);

private:

	//Input Tag
	FGameplayTag InputTag_Move;
	FGameplayTag InputTag_Look_Mouse;
	FGameplayTag InputTag_Jump;
    	// PanCamera 추가!
    	FGameplayTag InputTag_PanCamera; 

	static FTestGameplayTags GameplayTag;
};
//TestGameplayTag.cpp

#include "TestGameplayTag.h"
#include "GameplayTagsManager.h"
#include "Engine/EngineTypes.h"

FTestGameplayTags FTestGameplayTags::GameplayTag;

void FTestGameplayTags::InitializeNativeTags()
{
	UGameplayTagsManager& GameplayTagManager = UGameplayTagsManager::Get();

	GameplayTag.AddAllTags(GameplayTagManager);

	GameplayTagManager.DoneAddingNativeTags();
}

void FTestGameplayTags::AddAllTags(UGameplayTagsManager& Manager)
{
	AddTag(InputTag_Move, "InputTag.Move", "Move input.");
	AddTag(InputTag_Look_Mouse, "InputTag.Look.Mouse", "Look (Mouse) input");
	AddTag(InputTag_Jump, "InputTag.Jump", "Jump input.");
    	//PanCamera 추가!!
    	AddTag(InputTag_PanCamera, "InputTag.PanCamera", "Pan Camera input.");
}

void FTestGameplayTags::AddTag(FGameplayTag& OutTag, const ANSICHAR* TagName, const ANSICHAR* TagComment)
{
	OutTag = UGameplayTagsManager::Get().AddNativeGameplayTag(FName(TagName), FString(TEXT("(Native) ")) + FString(TagComment));
}

그 후 InputConfig에서 IA_PanCamera를 Tag과 함께 추가한다.

 

4. 실제 코드와 바인딩

바인딩은 EnhancedInputComponent를 상속받아 만들었던 InputComponent에서 

void BindActionByTag(const UTestInputConfig* InputConfig, const FGameplayTag& InputTag, ETriggerEvent TriggerEvent, UserClass* Object, FuncType Func);

해당 함수를 사용하여 바인딩한다.

 

//DediServerTestCharacter.h

public:
	ADediServerTestCharacter();

	UPROPERTY(EditDefaultsOnly, Category = "Input")
	UTestInputConfig* InputConfig;

protected:

	void Input_Move(const FInputActionValue& InputActionValue);
	void Input_Look(const FInputActionValue& InputActionValue);
	void Input_Jump(const FInputActionValue& InputActionValue);
    	//Pan Camera
    	void Input_StartedPanCamera(const FInputActionValue& InputActionValue);
    	void Input_TriggeredPanCamera(const FInputActionValue& InputActionValue);
        
protected:
	//Pan Camera
	FVector2D StartedPan = FVector2D::ZeroVector;
	UPROPERTY(EditAnywhere, Category = "DediServerTest|Input")
	float PanSpeed = 10.f;
//DediServerTestCharacter.cpp

void ADediServerTestCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
	UDediServerTestInputComponent* DediServerTestInputComponent = Cast<UDediServerTestInputComponent>(PlayerInputComponent);

	check(DediServerTestInputComponent);

	const FTestGameplayTags& GameplayTags = FTestGameplayTags::Get();

	DediServerTestInputComponent->BindActionByTag(InputConfig, GameplayTags.Move(), ETriggerEvent::Triggered, this, &ADediServerTestCharacter::Input_Move);
	DediServerTestInputComponent->BindActionByTag(InputConfig, GameplayTags.LookMouse(), ETriggerEvent::Triggered, this, &ADediServerTestCharacter::Input_Look);
	DediServerTestInputComponent->BindActionByTag(InputConfig, GameplayTags.Jump(), ETriggerEvent::Triggered, this, &ADediServerTestCharacter::Input_Jump);
    	// Pan Camera
    	DediServerTestInputComponent->BindActionByTag(InputConfig, GameplayTags.PanCamera(), ETriggerEvent::Started, this, &ADediServerTestCharacter::Input_StartedPanCamera);
    	DediServerTestInputComponent->BindActionByTag(InputConfig, GameplayTags.PanCamera(), ETriggerEvent::Triggered, this, &ADediServerTestCharacter::Input_TriggeredPanCamera);
}
//DediServerTestCharacter.cpp

void ADediServerTestCharacter::Input_StartedPanCamera(const FInputActionValue& InputActionValue)
{
	StartedPan = InputActionValue.Get<FVector2D>();
}

void ADediServerTestCharacter::Input_TriggeredPanCamera(const FInputActionValue& InputActionValue)
{
	APawn* Pawn = GetPawn<APawn>();
	if (Pawn == nullptr)
	{
		return;
	}

	if(GetWorld() == nullptr)
	{
		return;
	}

	const FVector2D Value = InputActionValue.Get<FVector2D>() - StartedPan;

	if (Value.X != 0.0f)
	{
		Pawn->AddControllerYawInput(Value.X * GetWorld()->DeltaTimeSeconds * PanSpeed);
	}

	if (Value.Y != 0.0f)
	{
		Pawn->AddControllerPitchInput(Value.Y * GetWorld()->DeltaTimeSeconds * PanSpeed);
	}

	StartedPan = InputActionValue.Get<FVector2D>();
}

ETriggerEvent를 Started로 먼저 받아서 시작 지점의 터치 위치를 저장한다음, AddControllerYawInput(), AddControllerPitchInput()으로 카메라를 조정했다.

 


정리해놓고 보니 별거 없는데 하나의 InputTag에 ETriggerEvent::Started하고 ETriggerEvent::Triggered 2개를 쓴다는 걸 알아내느라 좀 시간이 걸렸던거 같다. 역시 아직 EnhacedInput에 대해 좀 더 공부할 필요가 보인다.

 

참고

https://www.youtube.com/watch?v=FUqZNylFy-Y 

https://www.youtube.com/watch?v=5pnHzapGGak 

 

Comments