보키_기록용
C++에서 Enhanced Input System 사용하기 본문
Lyra 게임을 살펴보다가 테스트용으로 Enhanced Input System이라는 것을 적용해보기로 했다.
- Enhanced Input 핵심 요소
- 입력 액션(Input Actions) : Enhanced Input System과 프로젝트 코드 사이의 통신 링크. 점프하기, 문 열기 등 상호작용 캐릭터의 어떤 행동이든 입력 액션이 될 수 있다.
- 입력 매핑 컨텍스트(Input Mapping Contexts) : 사용자의 입력을 입력 액션으로 매핑한다.
- 모디파이어(Modifiers) : 사용자의 디바이스에서 나오는 원시 입력의 값을 조절한다. 입력 매핑 컨텍스트는 입력 액션에 대해 각 원시 입력과 관련된 모디파이어를 원하는 만큼 가질 수 있다.
- 트리거(Triggers) : 모디파이어 이후의 입력 값이나 다른 입력 액션의 출력 크기를 사용해 입력 액션의 활성화 여부를 결정한다. 입력 매핑 컨텍스트에 포함된 모든 입력 액션은 입력마다 하나 이상의 트리거를 가질 수 있다.
- Enhanced Input 주요 클래스
클래스 이름 | 역할 |
UInputAction | 입력이 이루어질 때 발생할 수 있는 작업 유형을 정의하는 데이터 자산. |
UInputMappingContext | UInputAction 에 대한 물리적 입력의 매핑을 집합적으로 정의하는 데이터 자산. |
UInputTrigger | UInputAction::Triggers 입력이 이루어졌는지 여부를 결정하기 위해 클래스에 의해 지정된 클래스 |
UInputModifier | UInputAction::Modifiers 입력 값을 트리거에 전달하기 전에 처리할 Trigger 클래스를 지정. |
UEnhancedInputComponent | UInputComponent 파생클래스 |
UEnhancedPlayerInput | UPlayerInput 파생클래스 |
UEnhancedInputLocalPlayerSubSystem | ULocalPlayer 가 소유하는 SubSystem |
- Enhanced Input 데이터 에셋 구조
1. 편집 > 플러그인 > Enhanced Input 플러그인을 추가한다.
2. MyGameplayTag 구조체 생성 (나는 TestGameplayTag로 했다.)
Tag를 사용하여 입력 바인딩을 한다.
※ 주의사항 : "GameplayTags"항목을 build.cs 파일의 PublicDependencyModuleNames 목록에 추가할것.
//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; }
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;
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.");
}
void FTestGameplayTags::AddTag(FGameplayTag& OutTag, const ANSICHAR* TagName, const ANSICHAR* TagComment)
{
OutTag = UGameplayTagsManager::Get().AddNativeGameplayTag(FName(TagName), FString(TEXT("(Native) ")) + FString(TagComment));
}
3. 본인프로젝트이름.h로 가서 Module 생성
DECLARE_LOG_CATEGORY_EXTERN나 DEFINE_LOG_CATEGORY는 그냥 로그 찍기위한 로그 카테고리용으로 만든거고, 중요한건 원래 만들어져있는 IMPLEMENT_PRIMARY_GAME_MODULE에 ModuleClass이름을 직접 만든걸로 바꿔야한다. (기본은 FDefaultGameModuleImpl로 되어있을것임.)
이거 때매 왜 태그를 못받아오지하고 한참 삽질했다..
//DediServerTest.h
#pragma once
#include "CoreMinimal.h"
DECLARE_LOG_CATEGORY_EXTERN(LogTestGame, Log, All);
class FDediServerTestGameModule final : public FDefaultGameModuleImpl
{
virtual void StartupModule() override;
virtual void ShutdownModule() override
{
}
};
//DediServerTest.cpp
#include "DediServerTest.h"
#include "TestGameplayTag.h"
#include "GameplayTagsManager.h"
DEFINE_LOG_CATEGORY(LogTestGame);
IMPLEMENT_PRIMARY_GAME_MODULE(FDediServerTestGameModule, DediServerTest, "DediServerTest" );
void FDediServerTestGameModule::StartupModule()
{
UE_LOG(LogTestGame, Warning, TEXT("Startup Module.."));
FTestGameplayTags::InitializeNativeTags();
UGameplayTagsManager::Get().DoneAddingNativeTags();
}
4. InputConfig 구성
InputAction과 Tag를 한 쌍으로 하는 구조체 데이터에셋을 만든다.Tag를 이용해 InputAction을 찾는다.
//TestInputConfig.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "GameplayTags/Classes/GameplayTagContainer.h"
#include "TestInputConfig.generated.h"
class UInputAction;
struct FGameplayTag;
/**
*
*/
USTRUCT(BlueprintType)
struct FTaggedInputAction
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly)
const UInputAction* InputAction = nullptr;
UPROPERTY(EditDefaultsOnly, meta = (categories = "InputTag"))
FGameplayTag InputTag;
};
UCLASS()
class DEDISERVERTEST_API UTestInputConfig : public UDataAsset
{
GENERATED_BODY()
public:
const UInputAction* FindInputActionFroTag(const FGameplayTag& InputTag) const;
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (TitleProperty = "InputAction"))
TArray<FTaggedInputAction> TaggedInputActions;
};
//TestInputConfig.cpp
#include "Input/TestInputConfig.h"
#include "GameplayTagContainer.h"
#include "EnhancedInput/Public/InputAction.h"
const UInputAction* UTestInputConfig::FindInputActionFroTag(const FGameplayTag& InputTag) const
{
for(const FTaggedInputAction& TaggedInputAction : TaggedInputActions)
{
if(TaggedInputAction.InputAction && TaggedInputAction.InputTag == InputTag)
{
return TaggedInputAction.InputAction;
}
}
return nullptr;
}
5. EnhancedInputComponent 구성
GameplayTag를 기반으로 Action을 바인딩하는 도우미 함수 포함.
//DediServerTestInputComponent.h
#pragma once
#include "CoreMinimal.h"
#include "EnhancedInputComponent.h"
#include "InputAction.h"
#include "TestInputConfig.h"
#include "GameplayTagContainer.h"
#include "DediServerTestInputComponent.generated.h"
/**
*
*/
UCLASS()
class DEDISERVERTEST_API UDediServerTestInputComponent : public UEnhancedInputComponent
{
GENERATED_BODY()
public:
template<class UserClass, typename FuncType>
void BindActionByTag(const UTestInputConfig* InputConfig, const FGameplayTag& InputTag, ETriggerEvent TriggerEvent, UserClass* Object, FuncType Func);
};
template <class UserClass, typename FuncType>
void UDediServerTestInputComponent::BindActionByTag(const UTestInputConfig* InputConfig, const FGameplayTag& InputTag,
ETriggerEvent TriggerEvent, UserClass* Object, FuncType Func)
{
check(InputConfig);
if(const UInputAction* IA = InputConfig->FindInputActionFroTag(InputTag))
{
BindAction(IA, TriggerEvent, Object, Func);
}
}
6. Character Setup
//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);
//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);
}
7. Editer 입력 설정
설정 > 프로젝트 세팅 > 엔진 > 입력에서 기존 입력 매핑을 지우고 '기본 플레이어 입력 클래스'와 '기본 입력 컴포넌트 클래스'를 다음과 같이 설정한다.
8. Editer에서 Input Asset 생성
- Input Action
- InputConfig (IC_MainInputs) : 아까 만들어놨던 InputCongif 데이터에셋을 사용하여 만든다.
- InputMappingContext(IMC_MainInputs)
- Character Blueprint에서 InputConfig 설정
참고
Enhanced Input Binding with Gameplay Tags C++ | Epic Developer Community (epicgames.com)
Enhanced Input Binding with Gameplay Tags C++ | Tutorial
This tutorial covers setting up a foundational Enhanced Input system in the First Person Template. This a minimalized version of the system implemented ...
dev.epicgames.com
Loading Native Gameplay Tags - Programming & Scripting / C++ - Unreal Engine Forums
Loading Native Gameplay Tags
This article was originally published for UDN Loading Native Gameplay Tags Native Gameplay tags need to be loaded very early during engine initialization for replication purposes. A common approach is to load native gameplay tags using the function UGamepl
forums.unrealengine.com
Using Gameplay Tags in C++ – James Baxter (jambax.co.uk)
Using Gameplay Tags in C++ – James Baxter
Gameplay tags are a powerful UE4 feature that allow for high-level tagging and categorisation of concepts and types. This concept of hierarchical tagging can be very powerful, and Gameplay Tags themselves have fully-featured editor support and a great API
jambax.co.uk
언리얼 엔진 5 향상된 입력 | 언리얼 엔진 5.0 문서 (unrealengine.com)
향상된 입력
향상된 입력 플러그인 개요
docs.unrealengine.com
【UE5】Lyra に学ぶ Enhanced Input - Qiita
【UE5】Lyra に学ぶ Enhanced Input - Qiita
【UE5】Lyra に学ぶ Enhanced Input UE5 の新しいサンプル Lyra Starter Game 。 その中で Enhanced Input プラグイン が、どのように利用されているかを読み解いていきます。 ...
qiita.com
'언리얼 > Enhanced Input System' 카테고리의 다른 글
UE5 Enhanced Input으로 카메라 터치 조작하기(Pan Camera) (0) | 2023.03.21 |
---|---|
Lyra에서 Input Mapping Context 살펴보기 (3) (0) | 2022.10.27 |
Lyra에서 Input Mapping Context 살펴보기 (2) (0) | 2022.10.26 |
Enhanced Input System을 위한 Game Feature 추가하기 (0) | 2022.10.14 |
Lyra에서 Input Mapping Context 살펴보기 (1) (0) | 2022.10.11 |