【UE5 初心者】球を転がして迷路を攻略するTPSゲームを作る(2) -WASDキーでプレイヤーを移動させる-

# はじめに
以下の点に注意して頂ければ幸いです。
・初心者による初心者のための記事です。文章に誤りのある場合がありますので注意ください。
・UE(Unreal Engine)のバージョンは5.5.3-39772772+++UE5+Release-5.5、OSはWindows10です。
・UE5のインストールについては完了している想定とします。
・本記事ではスクリプト(C++)は使用せず、UE5で使用されるビジュアルスクリプティングであるブループリントのみを使用します。
# 概要
本記事ではEnhancedInputプラグインに含まれるアクションアセット作成からアクションマップ設定、移動アクション実装までの手順を解説します。
# もくじ
- [1.アクションアセットの作成](#1.アクションアセットの作成)
- [2.アクションマップ(InputMappingContext)の設定](#アクションマップ(InputMappingContext)の設定)
  - [2-a.アクションマップ(InputMappingContext)の作成](#2-a.アクションマップ(InputMappingContext)の作成)
  - [2-b.アクションの追加](#2-b.アクションの追加)
  - [2-c.アクションのキー設定](#2-c.キー設定)
- [3.移動アクションの実装](#3.移動アクションの実装)
  - [3-a.アクションマップの有効化](#3-a.アクションマップの有効化)
  - [3-b.移動の実装](#3-b.移動の実装)

# 参考
公式ドキュメント
<a href=https://dev.epicgames.com/documentation/ja-jp/unreal-engine/enhanced-input-in-unreal-engine>Enhanced Input</a>
<a href=https://dev.epicgames.com/documentation/ja-jp/unreal-engine/blueprints-visual-scripting-in-unreal-engine>ブループリント ビジュアル スクリプティング</a>

# 1.アクションアセットの作成
まずコンテンツドロワーを開き、「コンテンツ」フォルダ内に「Input」フォルダとさらに内部に「Action」フォルダを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/e92570ac-63f6-4b85-adc6-1575a1eb24eb.png)

Actionフォルダ内の空白部分を右クリックし、入力>入力アクションを選択し、「IA_Move」入力アセットを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/02b9ea73-94ae-4906-ad30-bac6c9877123.png)

IA_Moveをダブルクリックして開きます。
Value Typeの項目をAxis2D(Vector2)に変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/33479711-f5ff-4696-84b4-99eb9f2d1a4c.png)

この項目は入力の種類によって変更します。移動は前後・左右の２次元の方向に行うためにAxis2Dを使用します。
以下は公式ドキュメントより引用

:::note info
たとえば、「アイテムを拾う」アクションでは、ユーザーがキャラクターに何かを拾わせるかどうかを表すオンとオフの状態のみが必要であり、「歩行」アクションでは、ユーザーがキャラクターを歩かせる方向と速度を表現する 2 D 軸が必要です。
:::

設定したらCTRL+Sで保存し、閉じてください。

# 2.アクションマップ(InputMappingContext)の設定
アクションマップ(InputMappingContext)は各アクションをまとめるのに便利なアセットです。アクションを例えば「水中」「ポーズ画面」など用途に分けてまとめたり、切り替えを容易にすることができます。

## 2-a.アクションマップ(InputMappingContext)の作成
フォルダをActionに移動して、入力>入力マッピングコンテキストを選択して、入力マッピングコンテキストアセットを作成してください。名称はIMC_Playerとしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/13c9ef0f-34d3-4449-9c3a-2154a173f617.png)

## 2-b.アクションの追加
IMC_Playerをダブルクリックして開いてください。
Mapingsの横の+ボタンをクリックして、先ほど作成したIA_Moveを追加してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/4d591f60-1bff-4149-9e92-e8824d5f136e.png)

## 2-c.アクションのキー設定
次に、アクションに対応するキーを設定します。IA_Moveの左部分を押して展開してください。
Noneのところから対応するキーを探すか、左のキーボードマークを押したのちに対応させたいキーを押すことで設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/7a9b9025-6cf3-48d1-8073-554cdeec8eb8.png)

IA_MoveにWSADそれぞれのキーを設定してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/92b2246d-0f73-4be5-91d5-60ec8343ae50.png)

現在、IA_Moveには四つのキーが設定されています。しかし、どのキーが押された場合も同じレスポンスを返すため一方向にしか進めません。
ここで、キー毎にモディファイアを追加することでキー毎のレスポンスを変更します。
今回は前後/左右方向を切り替えるために、入力のXとYを切り替えを行うスイズル入力軸値と、値を反転させるNegateのモディファイアを各キーに設定します。
各キーを展開してModifiersの+ボタンからモディファイアの追加ができます。
以下のように、SキーとAキーにNegateを、AキーとDキーにスイズル入力軸を設定してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/fa6294ab-8ea6-4496-9d19-9956715ca753.png)

設定が完了したらCTRL+Sで保存し、閉じてください。

# 3.移動アクションの実装
次に、アクションマップを利用してプレイヤーが操作できるようにします。
まず、前回作成したBP_Characterを開いて、イベントグラフを表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/bfe00e08-8ccd-49ec-b188-e64eb8318cfa.png)

## 3-a.アクションマップの有効化
まず先ほど作成したIMC_Playerをプレイヤーキャラクターに読み込ませる必要があるため、ブループリントでそのメソッドを作成します。
ブループリントで実装を行う場合は、「ノード」を繋ぎ合わせることで行います。
まず、最初からあるEvent BeginPlayノードの近くにイベントグラフの空白部分を右クリックして検索してGetControllerノードを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/24e6859a-a3c7-469f-88af-f3771a9f4059.png)

同様に、「CastToPlayerControllerノード」と「AddMappingContextノード」「EnhancedInputLocalPlayerSubSystemノード(PlayerControllerの方)」も作成します。
検索できない場合は「状況に合わせた表示」のチェックを外してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/36c85115-2724-4cd5-91e1-3a06e9fa219e.png)

そうしたら、各ノードを接続していきます。ノードの端のマークをドラッグして他のノードの同じマークに重ねてボタンを離すと接続ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/b9f641d0-9138-48a4-bd8c-e1ab5b3f8ee5.png)

今回、これらのノードを接続することでプレイヤー操作を管理するPlayerControllerにIMC_Playerを追加させる処理を行うことで操作ができるようにします。
まず、GetControllerとCast To PlayerControllerを接続します。GetControllerではTarget(今回は自身)のコントローラーを取得し、それをCastToPlayerControllerノードで変換(及び,チェック)を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/f2498211-9677-4747-b0a2-8fe7ab3f656d.png)

他のノードを以下のように接続することでAdd Mapping ContextノードのTargetにPlayerControllerを指定させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/e95b41c6-5934-41e5-8b48-9f769ce7e25c.png)

EnhancedInputLocalPlayerSubsystemノードはAdd Mapping ContextノードがPlayerControllerをTargetに指定できないため、噛ませています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/f50ef17d-89fe-4c47-9e01-0c965ab07d00.png)

次に、AddMappingContextノードのMappingContextにIMC_PlayerアセットをアタッチすることでIMC_PlayerをPlayerControllerに追加するように指示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/2ef5caec-ac61-4603-ae65-a1accb3232ca.png)

最後に、EventBeginPlayとCastToPlayerController・AddMappingContextノードを接続します。この接続により、EventBeginPlayを起点として順々に処理が実行されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/b9e5d71f-9adc-460d-9c4a-15fe21b890db.png)


ここまで行ったらミスがないか確認するため、一度コンパイルを行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/714a68e4-b703-47c4-9d9c-f35aee89e3b2.png)
チェックマークになればエラーが無いということなのでOKです。

次に、今作成した一連の内容を折りたたんで整理します。
EventBeginPlayノードを除くノードをドラッグして囲うか、ノード毎にCTRLを押しながらクリックして全て選択してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/2a1f1000-760a-4352-aa42-b6f1fc8b19c8.png)

その後、選択しているいずれのノードを右クリックすると折りたたむ項目が選択できます。
今回はマクロに折りたたむを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/964bf515-e88f-48d3-a959-f229954c48d7.png)

マクロの名前は「AddPlayerMappingContext」とします。
ついでに、マクロを右クリックしてノードコメントにマクロの説明を追加します。ちなみに、コメントの折り返しはSHIFT+ENTERで行えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/55447df0-4f3a-4505-8862-121204351fc0.png)

折りたたみを行うと見た目もスッキリしますし、逐一ロジックを確認せずとも結果がわかるようになるため、多用するといいと思います。(今回は単純な実装なのでやる機会はありませんが再利用もできます)

これでIMC_Playerで設定したプレイヤーの入力が有効になりました。ので、次は各入力時の動作を実装します。
## 3-b.移動の実装
次に、移動の実装を行います。これも作ってから折りたたんでもいいのですが、散らかったりするのが面倒なので今回は予め折りたたんだ状態で作成します。
今回は「プレイヤーの入力に応じてプレイヤーキャラクターを移動させる」実装を行います。プレイヤーの入力を受け取る必要があるため、今回はマクロではなく関数を用います。
左下のマイブループリントのところを右クリックすると関数を追加できます。関数の名前は「MovePlayer」としてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/abf9c3cc-70a4-49cf-bf14-343aa17cf7cd.png)


まずは、MovePlayerを選択して詳細タブから引数(関数に必要なパラメータのこと)を追加します。今回はプレイヤーの入力が欲しいので、インプットの右上の+から引数を追加して、型をVector 2Dに、名称をMovementに変更してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/f809e569-8ebe-405f-bbfb-cc8d35cfb7f6.png)

まず、移動させるTargetとなるSphereを取得します。マイブループリント内のコンポーネントからSphereをドラッグして「Get Sphere」でコンポーネントを取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/2987d1ce-48e6-4da0-bbb2-46725f7a6a37.png)

次に、物体に力を加えて移動させるAdd Forceノードを追加するのですが、検索すると複数あるのが確認できると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/ad492a97-d593-4750-894f-ecbc809b3b98.png)

これらはTargetが異なったり、そもそも別物の可能性もあるため、どれでもいいというわけではありません。
そういったことがあるたびに全て試すのは面倒なのでノードから直接伸ばして関連したノードを作成する方法を用います。
ノードの接続を空白部分に伸ばして離すとノードを追加するときと同じウインドウが表れるので、「状況に合わせた表示」にチェックを入れて調べると関連したノードのみを表示してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/1c64d614-5a6b-4f3b-b163-11c5c8b2c0aa.png)

Add Forceノードが追加出来たら、ForceとMovementを繋いで、出力を繋ぎます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/bc470acf-6df2-4920-ba9f-6323416c934d.png)

Movement(Vector2D)とForce(Vector)は違う型でありますが、互換性があるため自動的に変換ノードが出現して接続ができます。
これで関数は完成です。コンパイルしてエラーが無いことを確認したのち、イベントグラフに戻ってください。

次に、キー入力時にこの関数を呼び出したいので、キー入力時に発生するイベントノードを追加します。イベントグラフ内の空白部分を右クリックして「IA_Move」を検索し、Enhanced Input EventsのIA_Moveを選択してイベントノードを追加します。
さらに、マイブループリントからMovePlayer関数をドラッグしてイベントグラフに追加し、これを繋げます。
コメントもつけておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/a5f0faa9-7ec3-438c-9cf5-66e277a68c1c.png)

コンパイルとCTRL+Sで保存を行ったらゲーム画面を開始して、WASDキーを押してみてください。
何も変化がないように感じられると思います。しかし、実際にはすこーしだけ動いています。
起動中にSHIFT+F1でカーソルを出して右上のアウトライナーからプレイヤーキャラクターであるBP_Character0を探して、そのSphereコンポーネントのトランスフォームを確認して貰うと、変化しているのがわかると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/9dc631a3-9bc7-4028-9fa1-d657eda49505.png)


現状だと動く量が少なすぎるため、これを修正します。
BP_Characterを再度開いて、マイブループリントから変数を追加します。名称はSpeedで型はFloatに設定します。
追加したらコンパイルを行ってください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/b1eef168-5f4b-43fd-a8c7-e00c44fac4bd.png)

詳細タブからSpeedの説明とデフォルト値を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/36b0eafc-cdfd-4e7c-a7e8-d085478a313c.png)


MovePlayerを開いてMultiplyノードを追加し、Speed変数を追加して速度を上昇させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/f4f862e9-fda9-4ca6-b23d-888b91c8e785.png)

コンパイルして保存したのち、もう一度確認してみましょう。
動きはすると思います。が、移動方向が期待するものと異なる方向であったり、カメラがめちゃくちゃに回る現象が発生します。

とりあえず、カメラの方から修正を行います。
原因はカメラが球と親子関係にあるため、球が回転時にカメラも一緒に回っているためです。ので、親子関係を解除する必要があります。
これは、共通の親を新たに追加して並列させることで解決します。
BP_Characterを開いて「シーンコンポーネント」を追加します。これは位置情報(transform)だけを持つコンポーネントであり、今回のように共通の親として扱うのに利用できます。(<a href=https://dev.epicgames.com/documentation/ja-jp/unreal-engine/components-in-unreal-engine#scene%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88>公式ドキュメント コンポーネント</a>)
名称はSceneのままで大丈夫です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/54704066-88a2-48ac-83b7-d16b3b7dd593.png)

そして、Sceneコンポーネントをドラッグしてルートコンポーネントに設定します。その後、CameraコンポーネントをSceneコンポーネントにドラッグして親子付けすることでCameraとSphereを並列させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/7198d194-5eb4-4f99-a877-7f05854dfd01.png)

コンパイルして保存したのち、ゲームを開始して確認してみてください。画面が動かなくなったと思います。

続いて移動方向について修正を行います。これはプレイヤーの向いている方向と進行方向の相違が原因です。
プレイヤーの向いている方向を修正するためには、プレイヤーの出現位置である「PlayerStartアクタ」を修正します。
アウトライナーウインドウからPlayerStartを探して選択します。
すると画面中央にPlayerStartアクタが表示されます。この時、赤青緑の矢印は各XYZ軸を、水色の矢印はプレイヤー出現時の向きを示しています。
現在はX軸のマイナス方向を向いているため前後が反転してしまっています。
そのため、トランスフォームのZの値を180から0に変更して、水色の矢印を赤矢印と同じ方向になるように変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3992369/06e895e0-ee4b-4184-84a1-3f2448d868e2.png)

そうしたらゲームを開始してみてください。方向が治ったと思います。

カメラと球の親子関係を解除したためカメラが球を追尾しないようになっていますが、これについては次回視点移動を実装する際に修正しようと思います。

# おわりに
今回は移動の実装を行いました。やはり、プレイヤーの入力がキャラクターに反映されると少しですがゲームをプレイしてる感が出てきます。
次回では視点移動を実装させることで今回のプレイヤーの操作の実装を完了させる予定です。
以上で本記事を終わらせていただきます。お役に立てれば光栄です