【UE5】 WidgetのNavigationを両方のスティックで移動できるようにする

UEの標準の機能であるNavigationを使用してWidgetの選択しているボタンを移動する実装を行った際に対応したことのメモ

症状

Navigation機能を使用してWidgetの移動を実装している際
GamePadを使用したときに特にconfigを設定しないと左スティックのみでしか動かない状態になっているかと思います。

まずは他のキーでも移動ができるように
ヒストリア様のこちらの記事を参考に実装しました。

記事を参考に追加したキーでの移動はできるようになったのですが
以下のようにスティックを追加しても片方のスティックの入力しか動作しないままでした。

KeyEventRules.Emplace(EKeys::Gamepad_LeftStick_Up, EUINavigation::Up);
KeyEventRules.Emplace(EKeys::Gamepad_LeftStick_Down, EUINavigation::Down);
KeyEventRules.Emplace(EKeys::Gamepad_LeftStick_Left, EUINavigation::Left);
KeyEventRules.Emplace(EKeys::Gamepad_LeftStick_Right, EUINavigation::Right);

調査

FNavigationConfig.cppのコンストラクタで以下のようにデフォルト値が定義されています。

FNavigationConfig::FNavigationConfig()
	: bTabNavigation(true)
	, bKeyNavigation(true)
	, bAnalogNavigation(true)
	, AnalogNavigationHorizontalThreshold(0.50f)
	, AnalogNavigationVerticalThreshold(0.50f)
{
	AnalogHorizontalKey = EKeys::Gamepad_LeftX;
	AnalogVerticalKey = EKeys::Gamepad_LeftY;

	KeyEventRules.Emplace(EKeys::Left, EUINavigation::Left);
	KeyEventRules.Emplace(EKeys::Gamepad_DPad_Left, EUINavigation::Left);

	KeyEventRules.Emplace(EKeys::Right, EUINavigation::Right);
	KeyEventRules.Emplace(EKeys::Gamepad_DPad_Right, EUINavigation::Right);

	KeyEventRules.Emplace(EKeys::Up, EUINavigation::Up);
	KeyEventRules.Emplace(EKeys::Gamepad_DPad_Up, EUINavigation::Up);

	KeyEventRules.Emplace(EKeys::Down, EUINavigation::Down);
	KeyEventRules.Emplace(EKeys::Gamepad_DPad_Down, EUINavigation::Down);
}

ここでどのスティックを使用するかを設定しているようでした。

AnalogHorizontalKey = EKeys::Gamepad_LeftX;
AnalogVerticalKey = EKeys::Gamepad_LeftY;

つまり右スティックを使用したい場合には派生先で以下のように書き換えることになります。

AnalogHorizontalKey = EKeys::Gamepad_RightX;
AnalogVerticalKey = EKeys::Gamepad_RightY;

しかし今回実現したいのは両方のスティックなので少し違います。

FNavigationConfig.hに以下のようなクラスが用意されています。

/** A Navigation config that supports UI Navigation with both analog sticks + D-Pad. */
class FTwinStickNavigationConfig : public FNavigationConfig
{
public:
	SLATE_API FTwinStickNavigationConfig();
	
protected:
	SLATE_API virtual bool IsAnalogHorizontalKey(const FKey& InKey) const override;
	SLATE_API virtual bool IsAnalogVerticalKey(const FKey& InKey) const override;
};

つまり、FNavigationConfigではなくFTwinStickNavigationConfigを継承したクラスを作成して
そちらを使用することで両方のスティックを動作させる事が可能です。

対応方法

最終的には以下のようなクラスを作成して、GameInstanceで設定することで両方のスティックでの移動が実現できました。

class YOUR_GAME_API FMyCustomTwinStickNavigationConfig : public FTwinStickNavigationConfig
{
public:
	FMYCustomTwinStickNavigationConfig();
};

inline FMYCustomTwinStickNavigationConfig::FMYCustomTwinStickNavigationConfig()
{
        //WASDキーでNavigation移動できるように
	KeyEventRules.Emplace(EKeys::A, EUINavigation::Left);
	KeyEventRules.Emplace(EKeys::D, EUINavigation::Right);
	KeyEventRules.Emplace(EKeys::W, EUINavigation::Up);
	KeyEventRules.Emplace(EKeys::S, EUINavigation::Down);
}