1. サイトトップ
  2. ブログ
  3. C++
  4. 【UE5】EnhancedInputによる入力管理

【UE5】EnhancedInputによる入力管理

こんにちは!
情熱開発部・プログラム課の長谷です。

最近は暑かったと思えば、急激に気温が下がってきて、
体調管理が難しい時期になってきました。

管理が難しいと言えば、ゲームの入力情報の管理です。

そんな入力管理を快適にしてくれる

EnhancedInput」 

について紹介していこうと思います!

環境

UnrealEngine5.3.2を使用しています。

EnhancedInputとは?

UnrealEngine独自のプラグインで、

入力管理を行うことができるフレームワークになります。

キーやデバイスに依存しない形で「入力アクション」を定義することができ、柔軟で直感的に管理できます。

事前準備

まず、この機能を使うための設定をしていきます。

プロジェクト名Build.csを開き、以下のように"EnhancedInput"と追加する必要があります。
(このバージョンでは初期設定されています)

入力アセットについて

入力のやり取りには、以下の2つのアセットが必要になります。

  • 入力アクション
  • 入力マッピングコンテキスト(以下「入力マップ」という)

入力アクション

入力アクションは、

「ジャンプ」=入力アクション

のように1つの動作に対して作成します。

設定項目については、主に以下の3つを使います。

1. 入力軸(ValueType)
 入力時の取得する値の型を指定します。


2. 入力トリガー(Triggers)
 アクションが実行される条件の定義を行えます。

例)Downを選択した場合、入力中は常にトリガーONになります。

トリガーの種類については、以下のサイトを参考にしていただければと思います!
【UE5.0.x/UE5.1】Enhanced Input の備忘録

3. モディファイア(Modifiers)
 受け取った入力値に対して、変換・修正します。

例)Negateの場合、入力値が「+1.0」のだった時、「-1.0」に反転して返てくれます。

この作成した入力アクションは次のアセットで使用します!

入力マップ

入力マップは、

入力アクションと物理デバイス(ボタンやキーなど)を紐づけることができます。

一つの入力アクションに対し、複数のキーを設定することができ、

それによって、同じアクション内で異なるデバイスのキーを設定することができたりもします。

これで準備は完了です!

実際に動かしてみる

今回はキャラクターをジャンプをさせていきます!
(ブループリント、C++の両方で紹介します)

アセット作成

クラスの作成

ブループリント、またはC++でCharacterを継承したクラスの作成をします。

入力アクションの作成と設定

ジャンプをするためのアクションになります。

今回はPressedを設定しましたが、
未設定の場合以下のようになります。

入力方法イベント名
入力した瞬間Started, Triggered
長押し入力中Triggered
入力を終了Completed

入力マップの作成とアクション登録

先ほど作成した、ジャンプ用のアクションとキーの設定をします。

ブループリント

1 )入力マップの登録

作成したキャラクターブループリントクラスを開いて、以下のノードを作成します。

AddMappingContextノードに作成したアセットを設定しておきます。

2 )アクションの呼び出し

入力アクション名をノード検索すると、
以下のようなイベント関数がでてくるので、

そのノードと呼び出したい関数ノードを接続します。

これでジャンプさせることができました!
非常に楽しそうに飛んでくれて嬉しいです。

C++

こちらも作成したキャラクタークラスを使用していきます!

ヘッダーはこんな感じで作成しました。

// 前方宣言
class UInputMappingContext;
class UInputAction;
struct FInputActionValue;

UCLASS()
class ACharactorInput_Blog : public ACharacter
{
	GENERATED_BODY()

public:
	ACharactorInput_Blog();

protected:
	virtual void BeginPlay() override;

public:
	// ジャンプ関数
	void InputAction_Jump(const FInputActionValue& InputActionValue);

protected:
    // 入力マップ
	UPROPERTY(EditAnywhere, Category = "Input")
	TSoftObjectPtr<UInputMappingContext> InputMapping;
	
	// インプットアクション
	UPROPERTY(EditAnywhere, Category = "Input")
	UInputAction* InputAction;
};

.cpp側のincludeになります。

#include "Charactor/CharactorInput_Blog.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet/GameplayStatics.h"
#include "EnhancedInputSubsystems.h"
#include "EnhancedInputComponent.h"
#include "InputActionValue.h"
#include "InputMappingContext.h"
#include "InputAction.h"

1 ) 入力時に呼び出す関数の作成

FInputActionValueを引数にして関数を作成します。
 →指定したValueTypeにもとづいた型のデータを取得できます。

※今回はこの関数が呼ばれるだけで問題ないので、コメントアウトしています。

void ACharactorInput_Blog::InputAction_Jump(const FInputActionValue& InputActionValue)
{
	/*	
	EInputActionValueType ValueType = InputActionValue.GetValueType();

	if (ValueType == EInputActionValueType::Boolean)
	{
		bool bIsPressed = InputActionValue.Get<bool>();
	}
	*/

	// ジャンプさせる
	Jump();
}

2 )入力アクションを設定

入力アクションのバインド

UEnhancedInputCompoentのBindActionを使って設定していきます。

UEnhancedInputComponent::BindAction(UInputAction, ETriggerEvent, UserClass, Func);

BindActionの引数
 1. UInputAction・・・入力アクションオブジェクト
 2. ETriggerEvent・・・入力アクションが実行されるタイミング
 3. UserClass・・・呼び出すクラス(基本的にプレイヤー自身)
 4. Func・・・バインドする関数。入力を受け付けたときに実行される。

こんな感じで作成してみました。
4の関数には、先ほど作成したジャンプ関数を入れました。

// 入力アクションの設定
if (UEnhancedInputComponent* Component = CastChecked<UEnhancedInputComponent>(InputComponent))
{
	// 入力アクションのバインド
	Component->BindAction(InputAction, ETriggerEvent::Triggered, this, &ACharactorInput_Blog::InputAction_Jump);
}

3 )入力マップの登録と設定

以下の関数を使って作成した入力マップの登録をしていきます。

UEnhancedInputLocalPlayerSubsystem::AddMappingContext(MappingContext, Priority)

AddMappingContextの引数
 1. MappingContext・・・登録したい入力マップ
 2. Priority・・・入力の優先度。数字の大きい方の優先度が高くなります。

最終的には以下のような形になりました。

void ACharactorInput_Blog::BeginPlay()
{
	Super::BeginPlay();
	
	// 入力アクションのロード
	InputAction = LoadObject<UInputAction>(NULL, TEXT("/Game/Asset/Input/InputAction/IA_Jump.IA_Jump"), NULL, LOAD_None, NULL);
	// 入力マップのロード
    InputMapping = LoadObject<UInputMappingContext>(NULL, TEXT("/Game/Asset/Input/Mapping/IMC_Blog.IMC_Blog"), NULL, LOAD_None, NULL);
	
	// 入力アクションの設定
	if (UEnhancedInputComponent* Component = CastChecked<UEnhancedInputComponent>(InputComponent))
	{
		// 入力アクションのバインド
		Component->BindAction(InputAction, ETriggerEvent::Triggered, this, &ACharactorInput_Blog::InputAction_Jump);
	}
	
	if (const APlayerController* PlayerController = Cast<APlayerController>(GetController()))
	{
		if (UEnhancedInputLocalPlayerSubsystem* InputSystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
		{
			// 既存の入力マップの削除
			InputSystem->ClearAllMappings();

			// InputMapppingContextの設定
			int32 Priority = 0;
			InputSystem->AddMappingContext(InputMapping, Priority);
		}
	}
}

これでジャンプをさせることができましたが、

さらに手を加えてみようと思います。

動的な入力の切り替え

入力マップを未設定の状態で、動的に追加設定してみます。

入力キーの登録

MapKey関数で、指定した入力アクションとキーの紐づけを行えます。

UInputMappingContext::MapKey(UInputAction, FKey);

この処理をBeginPlayのBindAction前に追加しました。

// 入力アクションの設定

~~~~~~~

// キーの追加
if (InputAction)
{
	InputMapping->MapKey(InputAction, FKey(FName("SpaceBar")));
}

キーの定義名については、以下サイトにまとめられていましたのでご参考ください。
List of Key/Gamepad Input Names

キーの切り替え

ジャンプ関数を以下のように改造してみました。

ヘッダに適当なフラグを作成し、
そのON・OFFによって、スペースキーとシフトキーが切り替わるようにしてみました。

.h
bool InputFlag = false;

.cpp
void ACharactorInput_Blog::InputAction_Jump(const FInputActionValue& InputActionValue)
{
	bool value = InputActionValue.Get<bool>();
	
	Jump();

    // キーの変更
	for(auto& KeyMap : InputMapping->GetMappings())
	{
		auto& IA = KeyMap.Action;

		if (IA.GetFName() == FName("IA_Jump"))
		{
			// 現在のキーの削除
			InputMapping->UnmapKey(IA, KeyMap.Key);

			// 新たなキーの追加
			if(InputFlag)
			{
				InputMapping->MapKey(IA, FKey(FName("SpaceBar")));
				InputFlag = false;
			}
			else
			{
				InputMapping->MapKey(IA, FKey(FName("LeftShift")));
				InputFlag = true;
			}
		}
	}
}

実装内容の確認

実装内容は以下のような流れになっています。

  1. 実行して、初期化でアクションの自動追加
  2. ジャンプでスペースキーからシフトキーに切り替え
  3. 再度ジャンプでスペースキーに戻る

気分によって飛び方を変える、手のかかるかわいい子になりました。

まとめ

EnhancedInputは、次のような利点のある便利なシステムです。

  • 入力マッピングは柔軟性があり、複数のデバイスにも対応することができる
  • アクションの抽象化によって、特定のキーやボタンに依存せず、変更も簡単にできる
  • ランタイムの入力設定の切り替えが可能

他にもまだ様々な便利なシステムがありますので、
自分なりの入力システムを作ってみてはいかがでしょうか。

参考


【免責事項】

本サイトでの情報を利用することによる損害等に対し、
株式会社ロジカルビートは一切の責任を負いません。