【UE,C++メモ -5- 】 C++でEnhancedInputを実装する方法

## まずはBuild設定をいじくろう
しょっぱな嫌な気持ちになる。出鼻をくじかれる。しかしやるしかない。
C++でプロジェクトを新規作成するとIDEが立ち上がる。ファイルツリーの中から
自分が命名した**プロジェクト名.Build.cs**ファイルを見つけ開こう。
以下が開いて無編集の状態。
~~~C#
// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

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

		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
	}
}
~~~

なにがなにやら私はわからないが、このコードを以下のように編集すればよいらしい。

~~~C#
// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

public class HogeProject : ModuleRules
{
	public HogeProject(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
	
		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
	}
}
~~~

"EnhancedInput"と追加しよう。これを追加することでC++でEnhancedInputを扱えるようになるみたいです。
記述したけど動かない！って人は私もそうだった。ビルドし直したり再起動したりなんだりしていたら、直った。
## いよいよ実装
まずは.hファイル
~~~C++
// Bulid.csファイルをいじらないとこのincludeでエラーを吐く。
#include "InputMappingContext.h" // 追加
#include "InputAction.h" // 追加
#include "InputActionValue.h" // 追加

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class FOURHIT_API UMyInputComponent : public UActorComponent
{
	GENERATED_BODY()

public:	
	// Sets default values for this component's properties
	UMyInputComponent();

protected:
	// Called when the game starts
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

	UPROPERTY()
	class UInputMappingContext* DefaultMappingContext;
	UPROPERTY()
	class UInputAction* MyInputAction;

 	void MyInputPressedAction(const FInputActionValue& Value);
	void MyInputReleasedAction(const FInputActionValue& Value);
~~~

InputMappingContextとInputActionはエディタで作っている前提です。
まずはそれらを入れる変数、後にイベント関数に登録する関数を宣言する。

続いて.cppファイル
~~~C++
// Bulid.csファイルをいじらないとこのincludeでエラーを吐く。
#include "Kismet/KismetSystemLibrary.h" // 追加
#include "Kismet/GameplayStatics.h" // 追加
#include "Components/InputComponent.h" // 追加
#include "EnhancedInputComponent.h" // 追加
#include "EnhancedInputSubsystems.h" // 追加

UMyInputComponent::UMyInputComponent()
{
	PrimaryComponentTick.bCanEverTick = true;

	// IA_Actionを読み込み
	MyInputAction = LoadObject<UInputAction>(NULL, TEXT("/Game/Input/IA_MyInputAction.IA_MyInputAction"), NULL, LOAD_None, NULL);

	// IMCを読み込み
	DefaultMappingContext = LoadObject<UInputMappingContext>(NULL, TEXT("/Game/Input/IMC_Default.IMC_Default"), NULL, LOAD_None, NULL);
}
void UFourHitInputComponent::BeginPlay()
{
	Super::BeginPlay();

	// ...
		// PlayerContollerの取得
	APlayerController* Controller = UGameplayStatics::GetPlayerController(GetWorld(), 0);

	// 入力を有効にする
	GetOwner()->EnableInput(Controller);

	if (GetOwner()->InputComponent)
	{
		// InputComponentをUEnhancedInputComponentにCastしている
		if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(GetOwner()->InputComponent))
		{
			// Input Actionのイベント関数を登録していると思われる
			EnhancedInputComponent->BindAction(MyInputAction, ETriggerEvent::Triggered, this, &UFourHitInputComponent::MyInputPressedAction);
			EnhancedInputComponent->BindAction(RowCursorInput, ETriggerEvent::Completed, this, &UFourHitInputComponent::MyInputReleasedAction);
		}

		// !:if文の条件式内で変数宣言することで変数のスコープを短くできる
		if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
		{
			// Input Mapping Contextを登録する
			if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
			{
				Subsystem->AddMappingContext(DefaultMappingContext, 0);
			}
		}
	}
}
~~~

これで完了。ここまでお疲れ様。