mcpField
U
ue-input-system

ue-input-system

github.com/quodsoler開発4191.2k 回インストール4 週間前に更新
リポジトリ

ue-input-system について

UE 5.8 の Enhanced Input 開発スキルです。入力アセット、C++ バインド、ランタイム設定に加え、トリガー、モディファイア、マッピングコンテキスト、キー再割り当て、入力モードフィルタリングを扱います。

主な機能

  1. 01Input Action と Mapping Context の設定
  2. 02C++ 入力イベントのバインドと解除
  3. 03トリガーイベントと標準トリガー
  4. 04入力モディファイアと軸変換
  5. 05コンテキスト優先度とランタイム再割り当て

活用シーン

  1. 01キャラクターアクションへのキーと入力イベントの割り当て
  2. 02長押し、タップ、連続タップ動作の設定
  3. 03スティックのデッドゾーン、感度、軸マッピングの調整
  4. 04ゲーム内キー再割り当て設定画面の作成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/quodsoler/unreal-engine-skills --skill ue-input-system

インストール後、Claude Code で/ue-input-systemを入力して読み込まれたか確認します。

同梱ファイルreferences/input-action-reference.md

詳細

UE Input System

対象エンジン:UE 5.8。以下の API は 5.8 のヘッダーに基づいて検証済みです。古い形式は「Deprecated — do not use」に記載しています。

Enhanced Input は、エンジンがサポートする唯一の入力経路です。EnhancedInput プラグイン(Engine/Plugins/EnhancedInput、5.8 ではデフォルトで有効)に含まれています。Build.cs の PublicDependencyModuleNames に "EnhancedInput" を追加してください。FKey/EKeys を直接扱う場合は "InputCore" も、入力モードのフィルタリングまたはユーザー設定の失敗理由コンテナを使用する場合は "GameplayTags" も追加します。ランタイムを構成するのは、UEnhancedPlayerInput、UEnhancedInputComponent、UEnhancedInputLocalPlayerSubsystem、データアセットの UInputAction/UInputMappingContext、およびプレイヤーのキー再割り当てに使用する UEnhancedInputUserSettings です。

Context

.agents/ue-project-context.md が存在する場合は読み込んでください(モジュール名、規約、有効なプラグイン、GAS/ネットワーク設定)。ファイルがなくても作業を中断しないでください。

リクエストとコードベースから対象領域を特定してください。異なるコードになる可能性のある解釈が 2 つある場合に限り、確認してください。

リクエストの内容…参照先
プラグイン、モジュール、ini の設定セットアップ
アクションとマッピングコンテキストの作成入力アセット
C++ でのハンドラーのバインドC++ でのアクションのバインド
バインドするイベント(Started、Triggered、Completed)トリガーイベント
長押し、タップ、ダブルタップ、パルス、コード組み込みトリガー
デッドゾーン、感度、WASD→2D、Y 軸反転組み込みモディファイアー
コンテキストの追加/削除、優先度、分割画面マッピングコンテキストと優先度
ゲームプレイ状態によるコンテキストの有効化/無効化入力モードのフィルタリング
プレイヤーのキー再割り当て、設定画面、保存ランタイムのキー再割り当て
PlayerController を持たないアクターでの入力PlayerController を使わない入力
プラットフォームごとのマッピングコンテキストの切り替えプラットフォームごとの入力データ
新しいトリガーまたはモディファイアーの作成カスタムトリガー、カスタムモディファイアー
メニュー、カーソル、CommonUIUI 入力モード
デバッグオーバーレイデバッグ

クラスごとの詳細なパラメーターテーブルは、references/input-action-reference.md にあります。

Setup

// Build.cs
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput" });

DefaultInput.ini — エンジンのデフォルトクラスを Enhanced Input に設定します:

[/Script/Engine.InputSettings]
DefaultPlayerInputClass=/Script/EnhancedInput.EnhancedPlayerInput
DefaultInputComponentClass=/Script/EnhancedInput.EnhancedInputComponent

Enhanced Input のプロジェクト設定は UEnhancedInputDeveloperSettings(プロジェクト設定 → Engine → Enhanced Input)にあり、DefaultInput.ini の [/Script/EnhancedInput.EnhancedInputDeveloperSettings] に書き込まれます。C++ の動作を変更するキーは、bEnableUserSettings、UserSettingsClass、DefaultPlayerMappableKeyProfileClass、InputSettingsSaveSlotName、bEnableWorldSubsystem、DefaultWorldInputClass、bEnableInputModeFiltering、DefaultMappingContextInputModeQuery、DefaultInputMode、bEnableDefaultMappingContexts、bSendTriggeredEventsWhenInputIsFlushed です。

入力アセット

UInputAction : UDataAsset — 論理的なプレイヤーアクションごとに1つ作成します。C++の動作を変えるプロパティは次のとおりです。

PropertyDefaultMeaning
ValueTypeEInputActionValueType::BooleanBoolean、Axis1D(float)、Axis2D(FVector2D)、Axis3D(FVector)
AccumulationBehaviorTakeHighestAbsoluteValueまたは Cumulative。すべてのマッピングを合算するため、W + S は相殺されます
bConsumeInputtrue同じキーに対する優先度の低いEnhanced Inputマッピングをブロックします
bConsumesActionAndAxisMappingsfalseそのキーに対するレガシーのAction/Axisマッピングもブロックします
bReserveAllMappingsfalse優先度の高いコンテキストによってマッピングが上書きされなくなります
bTriggerWhenPausedfalseゲームの一時停止中もアクションが発火します
Triggers / Modifiersemptyアクションレベルで適用され、マッピングごとの設定の後に処理されます
PlayerMappableKeySettingsnullptrUPlayerMappableKeySettings — アクションを再バインド可能にします

UInputMappingContext : UDataAsset — キーとアクションのバインドをまとめて追加・削除します。

MemberNotes
DefaultKeyMappingsFInputMappingContextMappingData。GetMappings()で配列を読み取ります
MappingProfileOverridesTMap<FString, FInputMappingContextMappingData> — キープロファイルごとのオーバーライド
RegistrationTrackingModeUntracked(デフォルト)またはCountRegistrations
InputModeFilterOptionsUseProjectDefaultQuery(デフォルト)、UseCustomQuery、DoNotFilter
MapKey(Action, Key) / UnmapKey(Action, Key)エディター/設定画面向けのヘルパーであり、実行時のリバインドAPIではありません
HasMappingForInputAction(Action)デフォルトのマッピングとプロファイルのオーバーライドを検索します

各FEnhancedActionKeyMappingには、Action、Key、マッピングごとのTriggersとModifiers、SettingBehavior(EPlayerMappableKeySettingBehaviors:InheritSettingsFromAction、OverrideSettings、IgnoreSettings)、および省略可能なPlayerMappableKeySettingsのオーバーライドが含まれます。GetPlayerMappableKeySettings()とGetMappingName()で取得できます。

C++でのアクションのバインド

// MyCharacter.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyCharacter.generated.h"

class UInputAction;
class UInputMappingContext;
struct FInputActionValue;

UCLASS()
class MYGAME_API AMyCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	virtual void BeginPlay() override;
	virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override;

protected:
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
	TObjectPtr<UInputMappingContext> DefaultMappingContext;
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
	TObjectPtr<UInputAction> MoveAction;
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
	TObjectPtr<UInputAction> JumpAction;

	void Move(const FInputActionValue& Value);
	void StartJump();
	void StopJump();
};
// MyCharacter.cpp
#include "MyCharacter.h"

#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "InputActionValue.h"
#include "Engine/LocalPlayer.h"
#include "GameFramework/PlayerController.h"

void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(PlayerInputComponent);
	if (!EIC)
	{
		return;
	}

	EIC->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AMyCharacter::Move);
	EIC->BindAction(JumpAction, ETriggerEvent::Started,   this, &AMyCharacter::StartJump);
	EIC->BindAction(JumpAction, ETriggerEvent::Completed, this, &AMyCharacter::StopJump);
}

void AMyCharacter::BeginPlay()
{
	Super::BeginPlay();

	APlayerController* PC = Cast<APlayerController>(GetController());
	if (UEnhancedInputLocalPlayerSubsystem* Subsystem =
			ULocalPlayer::GetSubsystemFromController<UEnhancedInputLocalPlayerSubsystem>(PC))
	{
		Subsystem->AddMappingContext(DefaultMappingContext, 0);
	}
}

void AMyCharacter::Move(const FInputActionValue& Value)
{
	const FVector2D Axis = Value.Get<FVector2D>();
	AddMovementInput(GetActorForwardVector(), Axis.Y);
	AddMovementInput(GetActorRightVector(), Axis.X);
}

void AMyCharacter::StartJump() { Jump(); }
void AMyCharacter::StopJump() { StopJumping(); }
ハンドラーのシグネチャ

UEnhancedInputComponent::BindActionはFEnhancedInputActionEventBinding&を返し、3種類のネイティブデリゲートのいずれかに一致するメンバー関数、または名前で指定するUFUNCTIONを受け取ります。

SignatureHandler
FEnhancedInputActionHandlerSignaturevoid Handler()
FEnhancedInputActionHandlerValueSignaturevoid Handler(const FInputActionValue& Value)
FEnhancedInputActionHandlerInstanceSignaturevoid Handler(const FInputActionInstance& Instance)
FEnhancedInputActionHandlerDynamicSignatureBindAction(Action, Event, Object, FName("OnFirePressed"))

FInputActionInstanceは、GetValue()、GetTriggerEvent()、GetElapsedTime()(Started + Ongoing + Triggered)、GetTriggeredTime()(Triggeredのみ)、GetLastTriggeredWorldTime()、GetTriggers()、GetModifiers()、GetSourceAction()を公開します。

ラムダとポーリング可能な値:

EIC->BindActionValueLambda(InteractAction, ETriggerEvent::Triggered,
	[this](const FInputActionValue& Value) { TryInteract(Value.Get<bool>()); });

EIC->BindActionInstanceLambda(ChargeAction, ETriggerEvent::Ongoing,
	[this](const FInputActionInstance& Instance) { SetChargeProgress(Instance.GetElapsedTime()); });

// No delegate — just reflects the current value, poll it from Tick
FEnhancedInputActionValueBinding& LookBinding = EIC->BindActionValue(LookAction);
const FVector2D LookAxis = LookBinding.GetValue().Get<FVector2D>();

バインドの解除:

FEnhancedInputActionEventBinding& Binding =
	EIC->BindAction(JumpAction, ETriggerEvent::Started, this, &AMyCharacter::StartJump);
const uint32 BindingHandle = Binding.GetHandle(); // uint32, EnhancedInputComponent.h:165

EIC->RemoveBindingByHandle(BindingHandle);   // one binding, later
EIC->ClearBindingsForObject(this);           // every binding owned by this object; ClearActionBindings() drops all

トリガーイベント

ETriggerEventは、このティックで発生したトリガー状態の遷移を表すビットマスク(ENUM_CLASS_FLAGS)です。

EventBitState transitionBind it for
Triggered1 << 0None→Triggered、Ongoing→Triggered、Triggered→Triggeredアクティブなすべてのフレーム。連続的な移動
Started1 << 1None→Ongoing、None→Triggered評価の最初のフレーム。一度だけの押下アクション
Ongoing1 << 2Ongoing→Ongoing押し続けているが、まだトリガーされていない状態(チャージ中)
Canceled1 << 3Ongoing→Noneトリガー条件を満たす前に離した場合
Completed1 << 4Triggered→Noneトリガー後に離した場合。連続アクションを停止します

同じティックで両方が発生する場合、Startedは必ずTriggeredより先に発火します。アクションのいずれかのトリガーがOngoingを報告するティックでは、Completedは発火しません。押下と解放の両方を確実に検出する必要がある場合は、2つのアクションに分けてください。

組み込みトリガー

クラスごとのプロパティとデフォルト値については、references/input-action-reference.mdを参照してください。

クラス表示名動作
UInputTriggerDown押下値が作動しているフレームごとに発火します(アクションにトリガーがない場合の暗黙的なデフォルト)
UInputTriggerPressed押したとき最初に作動したときに一度だけ発火します。押し続けても繰り返しません
UInputTriggerReleased離したとき作動後、値がActuationThresholdを下回ったときに一度だけ発火します
UInputTriggerHold長押しHoldTimeThreshold秒経過後に発火します。bIsOneShot = falseの場合は発火し続けます
UInputTriggerHoldAndRelease長押しして離したときHoldTimeThreshold以上押し続けた場合、離したときに発火します
UInputTriggerTapタップTapReleaseTimeThreshold以内に離したときに発火します
UInputTriggerRepeatedTap連続タップNumberOfTapsWhichTriggerRepeat回タップし、各タップの間隔がRepeatDelay未満の場合に発火します
UInputTriggerPulseパルス押し続けている間、Interval秒ごとに発火します。発火回数はTriggerLimitが上限となります
UInputTriggerChordActionコードアクションChordActionがトリガーされている間のみ発火し、同じキーの優先度が低いマッピングにUInputTriggerChordBlockerを挿入します

ETriggerTypeは、同じアクション上のトリガーをどのように組み合わせるかを決定します。Explicit(少なくとも1つが発火する必要があります)、Implicit(すべてが発火する必要があります)、Blocker(IsBlockingがtrueを返す間、すべてをブロックします)。ETriggerEventsSupported(None、Instant、Uninterruptible、Ongoing、All)は、トリガーが生成できるETriggerEventを宣言します。

組み込みモディファイア

マッピングごとのモディファイアが最初に実行され、その後、アクションレベルのModifiers配列が実行されます。各グループ内では配列の順序で実行されます。

クラス表示名効果
UInputModifierDeadZoneデッドゾーンLowerThreshold未満をゼロにし、UpperThresholdで1にリマップします。TypeはAxial、Radial、UnscaledRadialです
UInputModifierScalarスカラー各軸にFVector Scalarを乗算します
UInputModifierScaleByDeltaTimeデルタタイムによるスケーリングフレームのDeltaTimeを乗算します
UInputModifierNegate符号反転bX/bY/bZで選択した軸の符号を反転します
UInputModifierSwizzleAxis入力軸の値を並べ替え軸を並べ替えます。OrderのデフォルトはEInputAxisSwizzle::YXZです
UInputModifierSmooth平滑化直近のサンプルの移動平均を計算します
UInputModifierSmoothDeltaデルタを平滑化平滑化された正規化デルタです。SmoothingMethod、Speed、EasingExponentを使用します
UInputModifierResponseCurveExponential応答曲線 - 指数関数軸ごとにsign(x) * pow(abs(x), CurveExponent)を適用します
UInputModifierResponseCurveUser応答曲線 - ユーザー定義軸ごとに1つのUCurveFloatを使用します
UInputModifierFOVScalingFOVスケーリングズーム中も角速度を一定に保つため、カメラのFOVに応じてスケーリングします
UInputModifierToWorldSpaceワールド空間に変換2D軸をワールド空間に変換します

WASD → Axis2D(アクションのAccumulationBehavior = Cumulative):

  • W:Swizzle Input Axis Values (YXZ) → Y = +1
  • S:Swizzle Input Axis Values (YXZ) + Negate (bY) → Y = −1
  • D:なし → X = +1
  • A:Negate (bX) → X = −1

ゲームパッドのスティック:各スティックのマッピングにDead Zone (Radial, LowerThreshold = 0.2)を設定します。 マウスルック:マッピングにScalar(0.4, 0.4, 1.0)、次にSmooth、続けてFOV Scalingを設定します。

コンテキストのマッピングと優先度

Subsystem->AddMappingContext(GameplayContext, 0);   // higher integer = higher priority
Subsystem->AddMappingContext(VehicleContext, 1);

FModifyContextOptions Options;
Options.bForceImmediately = true;     // rebuild now instead of at end of frame
Options.bNotifyUserSettings = true;   // register these mappings with UEnhancedInputUserSettings
Subsystem->AddMappingContext(MenuContext, 2, Options);

Subsystem->RemoveMappingContext(VehicleContext);
Subsystem->ClearAllMappings();

int32 FoundPriority = 0;
const bool bActive = Subsystem->HasMappingContext(GameplayContext, FoundPriority);
const FInputActionValue Current = Subsystem->GetPlayerInput()->GetActionValue(MoveAction);

FModifyContextOptions のデフォルト値は、bIgnoreAllPressedKeysUntilRelease = true、bForceImmediately = false、bNotifyUserSettings = false です。最初の設定によって、コンテキストの切り替え時に押されたままのキーから発生するゴースト入力はすでに抑制されています。オプトインだと考えて明示的に設定しないでください。押されたままのキーを新しいコンテキストに引き継ぐ場合に限り、false に設定します。

UInputAction の bConsumeInput = true(デフォルト)を設定すると、優先度の高いコンテキストで同じ物理キーがマッピングされている場合、そのキーに対応する優先度の低いバインディングがすべてブロックされます。優先度と bConsumeInput を使ってモードを分離します。たとえば、乗り物用コンテキストで Spacebar の入力を消費すると、運転中にキャラクターの Jump アクションが実行されなくなります。

IMC の RegistrationTrackingMode は、Untracked(追加回数にかかわらず、最初の RemoveMappingContext で削除されます)または CountRegistrations(追加と同じ回数だけ削除されるまで適用されたままになります。複数のシステムで IMC を共有する場合に使用します)です。

各ローカルプレイヤーは個別の UEnhancedInputLocalPlayerSubsystem を所有するため、分割画面のコンテキストがプレイヤー間で漏れることはありません。特定のプレイヤーのサブシステムは、ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(LocalPlayer) または ULocalPlayer::GetSubsystemFromController<UEnhancedInputLocalPlayerSubsystem>(PlayerController) で取得します。デバイスなしで入力をシミュレートするには、InjectInputForAction(Action, RawValue, Modifiers, Triggers) または InjectInputVectorForAction(Action, Value, Modifiers, Triggers) を使用します。

入力モードのフィルタリング

コンテキストを追加・削除する代わりに、ゲームプレイタグの状態に基づいてマッピングコンテキスト全体を制御します。UEnhancedInputDeveloperSettings で bEnableInputModeFiltering を有効にする必要があります。

  • サブシステムは現在のモードを保持します。GetInputMode()、SetInputMode(Tags, Options)、AppendTagsToInputMode、AddTagToInputMode、RemoveTagsFromInputMode、RemoveTagFromInputMode があり、いずれも省略可能な FModifyContextOptions を受け取ります。
  • 各 UInputMappingContext は InputModeFilterOptions でマッチング方法を選択します。UseProjectDefaultQuery(プロジェクトの DefaultMappingContextInputModeQuery)、UseCustomQuery(IMC 独自の InputModeQueryOverride)、または DoNotFilter です。
  • UEnhancedInputDeveloperSettings::DefaultInputMode は、新しい UEnhancedPlayerInput ごとにモードを初期設定します。
  • クエリに一致しないコンテキストは登録されたまま入力を生成しなくなるため、優先度や登録数は変わりません。
Subsystem->SetInputMode(FGameplayTagContainer(MyGameplayTags::TAG_InputMode_Menu));

実行時のキーの再バインド

UEnhancedInputUserSettings(UserSettings/EnhancedInputUserSettings.h)が、正式にサポートされている再バインド方法です。これは USaveGame であり、bEnableUserSettings が有効な場合にサブシステムごとに作成され、InputSettingsSaveSlotName で指定されたスロットに保存されます。

#include "EnhancedInputSubsystems.h"
#include "UserSettings/EnhancedInputUserSettings.h"

void UMyRebindWidget::RebindKey(FName MappingName, const FKey& NewKey)
{
	UEnhancedInputLocalPlayerSubsystem* Subsystem =
		ULocalPlayer::GetSubsystemFromController<UEnhancedInputLocalPlayerSubsystem>(GetOwningPlayer());
	UEnhancedInputUserSettings* Settings = Subsystem ? Subsystem->GetUserSettings() : nullptr;
	if (!Settings)
	{
		return;
	}

	FMapPlayerKeyArgs Args;
	Args.MappingName = MappingName;
	Args.Slot = EPlayerMappableKeySlot::First;
	Args.NewKey = NewKey;

	FGameplayTagContainer FailureReason;
	Settings->MapPlayerKey(Args, FailureReason);
	if (FailureReason.IsEmpty())
	{
		Settings->SaveSettings();
	}
}

設定 UI に表示する必要がある IMC は、サブシステムに一度も追加されていないものも含めて、RegisterInputMappingContext(IMC) で登録します。bNotifyUserSettings = true を指定してコンテキストを追加した場合は、自動的に登録されます。マッピングを取得するには FindMappingsInRow(MappingName) と FindCurrentMappingForSlot(MappingName, Slot)、リセットするには ResetAllPlayerKeysInRow または ResetKeyProfileIdToDefault、保存するには SaveSettings() / AsyncSaveSettings() を使用します。プロファイル識別子は FGameplayTag ではなく FString です。ProfileIdString、GetProfileIdString()、GetActiveKeyProfileId()、GetKeyProfileWithId()、SetActiveKeyProfile() を使用します。

アクションまたはマッピングを再バインド可能にするには、UPlayerMappableKeySettings(Name、DisplayName、DisplayCategory、Metadata、SupportedKeyProfileIds)を設定する必要があります。これは UInputAction に設定するか、SettingBehavior = OverrideSettings として FEnhancedActionKeyMapping に設定します。API と構造体の全一覧については、references/input-action-reference.md を参照してください。

PlayerController を使用しない入力

UEnhancedInputWorldSubsystem(5.8 で試験的に導入)を使うと、所有されることのないアクターでも入力デリゲートを受け取れるようになります。UEnhancedInputDeveloperSettings の bEnableWorldSubsystem で有効にしてください。

#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "Engine/World.h"

void AMyDoor::BeginPlay()
{
	Super::BeginPlay();

	// AddActorInputComponent reads AActor::InputComponent, created only for possessed actors.
	if (!InputComponent)
	{
		InputComponent = NewObject<UEnhancedInputComponent>(this, TEXT("DoorInputComponent"));
		InputComponent->RegisterComponent();
	}

	UEnhancedInputComponent* EIC = CastChecked<UEnhancedInputComponent>(InputComponent);
	EIC->BindAction(OpenAction, ETriggerEvent::Started, this, &AMyDoor::Open);

	if (UEnhancedInputWorldSubsystem* WorldInput =
			GetWorld()->GetSubsystem<UEnhancedInputWorldSubsystem>())
	{
		WorldInput->AddActorInputComponent(this);
		WorldInput->AddMappingContext(DoorContext, 0);
	}
}

AddActorInputComponent を呼び出すたびに、EndPlay で RemoveActorInputComponent も呼び出してください。このサブシステムはローカルプレイヤー用のものと同じ IEnhancedInputSubsystemInterface を実装しているため、AddMappingContext や InjectInputForAction などの動作は同じです。ただし、ユーザー設定もローカルプレイヤーもありません。

プラットフォームごとの入力データ

UEnhancedInputPlatformSettings(UPlatformSettings、UEnhancedInputPlatformSettings::Get())には、UEnhancedInputPlatformData のサブクラスを格納する InputData 配列があります。各サブクラスでは、特定のプラットフォームである UInputMappingContext を別のものに差し替える TMap の MappingContextRedirects を定義します。GetContextRedirect(Context) は置換先を返し、置換先がなければ元のコンテキストを返します。ゲームプレイコードで分岐することなく、タッチ用またはコンソール用のコンテキストに差し替える場合に使用してください。Get() の呼び出しには Build.cs に DeveloperSettings が必要です(インラインで UPlatformSettingsManager を呼び出します)。

カスタムトリガー

UInputTrigger をサブクラス化し、UpdateState_Implementation をオーバーライドして、ETriggerState::None、Ongoing、または Triggered を返します。

// MyDoubleClickTrigger.h
#pragma once

#include "EnhancedPlayerInput.h"
#include "Engine/World.h"
#include "InputTriggers.h"
#include "MyDoubleClickTrigger.generated.h"

UCLASS(EditInlineNew, meta = (DisplayName = "Double Click"))
class MYGAME_API UMyDoubleClickTrigger : public UInputTrigger
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Trigger Settings")
	float DoubleClickThreshold = 0.3f;

protected:
	virtual ETriggerType GetTriggerType_Implementation() const override { return ETriggerType::Explicit; }

	virtual ETriggerState UpdateState_Implementation(
		const UEnhancedPlayerInput* PlayerInput, FInputActionValue ModifiedValue, float DeltaTime) override
	{
		const bool bActuated = IsActuated(ModifiedValue);
		const float Now = PlayerInput->GetWorld()->GetTimeSeconds();

		ETriggerState Result = ETriggerState::None;
		if (bActuated && !bWasActuated)
		{
			if ((Now - LastPressTime) <= DoubleClickThreshold)
			{
				LastPressTime = 0.f;
				Result = ETriggerState::Triggered;
			}
			else
			{
				LastPressTime = Now;
			}
		}

		bWasActuated = bActuated;
		return Result;
	}

private:
	float LastPressTime = 0.f;
	bool bWasActuated = false;
};

IsActuated(Value) は Value.GetMagnitudeSq() >= ActuationThreshold * ActuationThreshold です。時間ベースのトリガーには UInputTriggerTimedBase を派生元として使用してください。このクラスは、入力が作動すると Ongoing に遷移し、HeldDuration、CalculateHeldDuration(PlayerInput, DeltaTime)、および bAffectedByTimeDilation を利用できます。ブロッカーの場合は IsBlocking(const ETriggerState State) const を、デバッグ HUD の場合は GetDebugState() const をオーバーライドしてください。トリガーがマッピングの再構築をまたいで状態を保持する場合は、ReceiveTriggerReinstanced_Implementation(const UInputTrigger* OldTrigger) をオーバーライドして Super を呼び出してください。

カスタムモディファイアー

UInputModifier をサブクラス化し、次の関数をオーバーライドします。

virtual FInputActionValue ModifyRaw_Implementation(
	const UEnhancedPlayerInput* PlayerInput, FInputActionValue CurrentValue, float DeltaTime) override;

返された値は、後続の処理に進む前にアクションの ValueType に戻されるため、内部では任意の形状を返せます。FInputActionValue(CurrentValue.GetValueType(), Vector) を使うと、その形状を維持できます。デバッグオーバーレイの色を制御するには、GetVisualizationColor_Implementation(FInputActionValue SampleValue, FInputActionValue FinalValue) const をオーバーライドしてください。実例:references/input-action-reference.md。

UI 入力モード

CommonUI を使用しない場合は、PlayerController で SetInputMode(FInputModeUIOnly())、SetInputMode(FInputModeGameAndUI())、または SetInputMode(FInputModeGameOnly()) を使ってモードを切り替えます。

CommonUI では入力が UCommonActivatableWidget のスタック経由でルーティングされるため、手動で SetInputMode を呼び出す場面がほとんどなくなります。Enhanced Input と Common Input は統合されています。UCommonInputSettings::bEnableEnhancedInputSupport(プロジェクト設定 → ゲーム → Common Input。再起動が必要)を有効にすると、CommonUI のクリックアクションと戻るアクションがデータテーブルの行ではなく、UInputAction アセット(UCommonUIInputData::EnhancedInputClickAction と EnhancedInputBackAction)になります。ウィジェットスタック、アクティベート可能なウィジェット、入力設定については ue-ui-umg-slate を参照してください。

デバッグ

ShowDebug EnhancedInput は、適用されたマッピングコンテキスト、各アクションの値とトリガー状態、および各トリガーの GetDebugState() を出力します。ShowDebug WorldSubsystemInput は UEnhancedInputWorldSubsystem について同様の情報を出力します。ShowDebug InputSettings は開発者設定を出力します。VeryVerbose レベルの LogWorldSubsystemInput は、ワールドサブシステムが処理するすべてのキーをログに記録します。

非推奨 — 使用しないでください

出力しないでください5.8 で使用ソース
UInputTriggerCombo置き換えなし — UInputTriggerChordAction、タイマー、またはステートマシンを使ってシーケンスを構築してくださいInputTriggers.h:571 の UE_DEPRECATED(5.8)
FInputComboStepData, FInputCancelAction置き換えなしInputTriggers.h:530,551 の UE_DEPRECATED(5.8)
FEnhancedInputKeys::ComboKey置き換えなしEnhancedInputModule.h:20 の UE_DEPRECATED(5.8)
UInputMappingContext::MappingsDefaultKeyMappings / GetMappings()InputMappingContext.h:93 の UE_DEPRECATED(5.7)
UEnhancedInputPlatformSettings::LoadInputDataClasses(), InputDataClassesGetInputData() / ForEachInputData()EnhancedInputPlatformSettings.h:77,88 の UE_DEPRECATED(5.7)
UEnhancedPlayerInput::GetAppliedInputContexts()GetAppliedInputContextData()EnhancedPlayerInput.h:175 の UE_DEPRECATED(5.6)
FMapPlayerKeyArgs::ProfileId (FGameplayTag), SetKeyProfile(FGameplayTag), GetCurrentKeyProfile(), GetCurrentKeyProfileIdentifier(), GetAllSavedKeyProfiles(), GetKeyProfileWithIdentifier(), ResetKeyProfileToDefault(FGameplayTag), GetProfileIdentifer()ProfileIdString (FString), SetActiveKeyProfile(FString), GetActiveKeyProfile(), GetActiveKeyProfileId(), GetAllAvailableKeyProfiles(), GetKeyProfileWithId(), ResetKeyProfileIdToDefault(FString), GetProfileIdString()UserSettings/EnhancedInputUserSettings.h:86,706,730,722,754,776,673,327 の UE_DEPRECATED(5.6)
UPlayerMappableKeySettings::SupportedKeyProfilesSupportedKeyProfileIds (TArray<FString>)PlayerMappableKeySettings.h:62 の UE_DEPRECATED(5.6)
UEnhancedInputDeveloperSettings::bShouldLogAllWorldSubsystemInputsVeryVerbose の LogWorldSubsystemInputEnhancedInputDeveloperSettings.h:150 の UE_DEPRECATED(5.6)
UPlayerMappableInputConfigUEnhancedInputUserSettingsPlayerMappableInputConfig.h:23 の UE_DEPRECATED(5.3)
UInputComponent::BindAxis, BindAction(FName, EInputEvent, Object, Func), BindAxisKey, BindVectorAxis, BindKey, BindTouch, BindGestureUEnhancedInputComponent::BindAction(UInputAction*, ETriggerEvent, Object, Func)UEnhancedInputComponent で = delete、EnhancedInputComponent.h:613-634

よくある間違い

SetupPlayerInputComponent でマッピングコンテキストを追加する: この呼び出しは、コントローラーとローカルプレイヤーが解決される前に実行される場合があります。コンテキストは BeginPlay、OnPossess/PossessedBy、または PlayerControllerChanged ハンドラーで追加してください。

「念のため」bIgnoreAllPressedKeysUntilRelease = true に設定する: FModifyContextOptions ではすでにデフォルト値です。false に設定する場合にのみ変更してください。

ボタンの押下に Triggered をバインドする: Triggered はアクティブなフレームごとに発生します。押下時に一度だけ実行するには Started を、離したときには Completed を使用してください。

Ongoing と同時に Completed が発生すると期待する: トリガーが Ongoing を報告するティックでは、Completed は抑制されます。それぞれに独自のトリガーを持つ2つのアクションに分けてください。

スティックにデッドゾーンがない: アナログスティックはゼロ以外の値で静止します。すべてのスティックマッピングに Dead Zone (Radial) を追加してください。

WASD のスウィズル設定がない: キーボードキーは X 軸に1D値を出力します。W と S に Swizzle Input Axis Values (YXZ) を設定しないと、前後の入力が Axis2D アクションの Y 成分に届きません。

プレイヤーのキー再割り当てに MapKey/UnmapKey を呼び出す: これらは IMC アセットを変更するもので、エディターや設定向けのヘルパーです。代わりに UEnhancedInputUserSettings::MapPlayerKey を使用してください。また、キー再割り当て UI に表示するコンテキストを追加するときは、bNotifyUserSettings = true を渡してください。

トリガーイベントをレプリケートする: 入力はクライアントローカルです。レプリケートするのは結果(移動入力、アビリティの起動など)であり、ETriggerEvent はレプリケートしないでください。

UEnhancedInputComponent でレガシーバインドを使用する: BindAxis と FName の BindAction オーバーロードは = delete であり、コンパイルに失敗します。ENHANCED_INPUT_ALLOW_LEGACY_BINDING=1 を定義するのではなく、移行してください。

関連スキル

  • ue-gameplay-framework — APlayerController、ポゼッション、SetupPlayerInputComponent のライフサイクル
  • ue-ui-umg-slate — CommonUI のアクティベート可能なウィジェットスタック、入力設定、カーソルとフォーカス
  • ue-character-movement — AddMovementInput を通じた FInputActionValue の消費
  • ue-gameplay-abilities — 入力からのアビリティの有効化、UAbilitySystemComponent の入力 ID
  • ue-actor-component-architecture — UActorComponent/UInputComponent の所有権、EnableInput、コンポーネントが所有する入力
  • こちらも関連します:ue-cpp-foundations、ue-game-features、ue-gameplay-cameras、ue-mover

コメント