お世話になっております。
設定例のご提示ありがとうございます。
> 以上の条件でAddMappingContextを行う際、Priorityの関係がIMC_01 > IMC_02 = IMC_03となる場合について、
> 手元で確認したところ、すべてのアクションが機能していたため、Chord Actionで指定されたアクションについては
> 同優先度のアクションのブロックする機構の影響を受けないように感じました。
> こちら認識間違っておりますでしょうか?
当方の手元で確認したところ、IMC_02とIMC_03が同じプライオリティであったとしても、結果的にメモリ上で先になったIMCが、後に置かれたIMCのChordedマッピング(※Chorded Actionをトリガーに持つアクション)をブロックしました。よって、ご提示いただいたような「ブロック影響のなさ」は、通常の設定では起こりえないと認識しております。
[Image Removed]当方で作成したプロジェクトを本投稿に添付しましたのでご確認ください。プロジェクトを開き、PIEをスタートさせると自動的にShowDebug EnhancedInputが有効になり、テストが可能になります。1キーをIA_A、IA_B、IA_Cに、2キーをTrigger_B、Trigger_Cに割り当てています。IA_BおよびIA_CはトリガーにChorded Actionを持ち、それぞれTrigger_BとTrigger_Cを指定しています。
お手元ですべてのアクションが有効になったというケースはまた何か別の条件によるものではないかと思います。再現プロジェクトをご提供いただければ、調査いたします。
なお、IMC追加時に与えるPriorityはあくまでソート上のヒントであって、同じPriorityを付与したIMCがあっても、どちらかが配列内で先に置かれてしまう以上、必ず優劣がつきます。今回の再現プロジェクトでは、IMC_01 (優先度10)、IMC_02 (優先度 0)、IMC_03(優先度0)としましたが、結果的に IMC_01 > IMC_03 > IMC_02 というソート結果となり、IMC_03に優先度5などを与えた場合と同じ処理結果になっております。
// エンジンに実装されたIMCをソートするコード // 優先度が同じ2つのIMCがあっても、1つのIMCにマージはされず、 // どちらかが先にソートされる OrderedInputContexts.ValueSort([](const int32& A, const int32& B) { return A > B; });
> (追加で調査したところ、IMC_01 > IMC_02 > IMC_03の場合についてもすべてのアクションが機能していたため、Chord Actionで指定されたアクション同士はブロックする機構の影響を受けないんでしょうか?)
ブロックが生じるのは、「Corded Actionをトリガーに持つマッピングと、同じキーを持つもの」となります。この条件に当てはまる場合、Chorded Actionで指定されたアクションもブロックの対象となります。
[Image Removed]
誤認識を防ぐために、エンジン内部で用いられている名称を元に、用語として、
・TriggerにChorded Actionを持つマッピングを「Chordedマッピング」
・Chorded Actionトリガーで指定されたアクションを「Chordingアクション」
・Chordingアクションに紐づけられたマッピングを「Chordingマッピング」
と整理したいと思います。UInputTriggerChordBlockerの暗黙的な注入は、Chordedマッピングと同じキーを持つ、後優先のマッピングすべてに対して行われます。今回の場合は、IMC_02の「1 - IA_B」がそれに相当しましたが、仮にIMC_02のマッピングを「1 - Trigger_B」「2 - IA_B」のように入れ替えますと、今度は「Trigger B」が(たとえChorded Actionで指定されたアクション=Chording アクション/マッピングだとしても)ブロックされます。
[Image Removed]参考までに該当処理のエンジンコードを下に引用いたします。ブロッカーの注入がマッピング(アクション)の種類をチェックせずに行っていることがご確認いただけるかと思います。
`// Inject chord blockers into all lower priority action mappings with a shared key
for (int32 MappingIndex : ChordedMappings)
{
FEnhancedActionKeyMapping& ChordMapping = PlayerInput->EnhancedActionMappings[MappingIndex];
for (int32 i = MappingIndex + 1; i < PlayerInput->EnhancedActionMappings.Num(); ++i)
{
FEnhancedActionKeyMapping& Mapping = PlayerInput->EnhancedActionMappings[i];
if (Mapping.Action && Mapping.Key == ChordMapping.Key)
{
// If we have no explicit triggers we can’t inject an implicit as it may cause us to fire when we shouldn’t.
auto AnyExplicit = (const UInputTrigger* Trigger) { return Trigger->GetTriggerType() == ETriggerType::Explicit; };
if (!HasTriggerWith(AnyExplicit, Mapping.Triggers) && !HasTriggerWith(AnyExplicit, Mapping.Action->Triggers))
{
// Insert a down trigger to ensure we have valid rules for triggering when the chord blocker is active.
Mapping.Triggers.Add(NewObject());
Mapping.Triggers.Last()->ActuationThreshold = SMALL_NUMBER; // TODO: “No trigger” actuates on any non-zero value but Down has a threshold so this is a hack to reproduce no trigger behavior!
}
UInputTriggerChordBlocker* ChordBlocker = NewObject(PlayerInput);
ChordBlocker->ChordAction = ChordMapping.Action;
// TODO: If the chording action is bound at a lower priority than the blocked action its trigger state will be evaluated too late, which may produce unintended effects on the first tick.
Mapping.Triggers.Add(ChordBlocker);
}
}
}`一度ご確認ください。
以上、よろしくお願いいたします。