UE4でOculusQuest2を動かす３

# 初めに
　本記事は[前回](https://qiita.com/HnniTns/items/5ef4e3cc56a7ca0af4ff)の続きですので、できれば前回をご覧ください。また、この記事を書いている人は、VR開発については全くの初心者で、普通に間違っている可能性も十分にあるので、その点に関してはご了承ください。

# ゲーム部分
　ゲーム部分については簡単に記述します。というのも、中身自体がとてつもなく簡単なゲームのようなものなので、~~記述する内容があまりな~~...ではなくVR自体にはあまり関係ないからですね。
　ゲームを一言で言うなら「敵UFOを打ち落とす360°シューティング」です。詳細は[前回](https://qiita.com/HnniTns/items/5ef4e3cc56a7ca0af4ff)の記事をご覧ください。
![サンプルゲーム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/a2efdeae-1807-f296-8743-b8cca99b798a.png)
　自機は中心・敵は周囲に沸いて打ち落とそうとしている図 ↑

## 自機/敵UFOの作成・スポーン
### ・作成
　自機には前回作成した方法で作成します。下図の``SkeletalMeshL/R``に関しては、色々やろうとして結局やめた残骸なので気にしないで下さい。それと、``WidgetInteractionL/R``と``LaserL/R``は後述するUIに使用します。
![自機 コンポーネント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/b1edf1f7-f471-323c-d92d-386431f67724.png)
　次に、自機から弾を発射する為に砲台アクターを作成します。イメージとしては砲台を遠隔操作するイメージです。アクターは半透明のメッシュを使用して、レーザーサイト的なものをしておくと、撃つ方向がかなり分かりやすくなると思います。
![自機 砲台.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/9554ed98-b995-b930-635f-d83550e30022.png)
　実は、砲台の回転に「実際の手の動き」を適用するか迷ったりしたのですが、~~せっかく実装した~~VRっぽい動きなので実装する事にしました。
![自機 砲台 動き.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/dbbff178-55ad-db3b-9520-ace88d5711af.gif)

---

　敵に関しては``Static Mesh``と``Sphere Collision``を追加しただけのシンプルなアクターです。簡易的な軽量化の為ですね。といっても、ガチガチに軽量化するならばインスタンシング描画を使ったり、当たり判定をメインスレッドから切り離したりするといった手段を考えられますね。
![敵機.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/6928684f-0fb3-108a-5c85-260b38b1a3ce.png)

### ・スポーン
　``Player Start``は適当な部分に設置して、ワールドセッティングで作成した自機を設定します。そして、敵UFOに関してはプレイヤーを中心にスポーンさせます。
　スポーンさせる時は``Random Rotator``を使ってランダムな角度を取得、``Clamp Angle``でピッチ方向に制限をかけ、自機を中心にランダムな距離を設定するだけの簡単なお仕事です。以上、``Random Rotator``を紹介したかっただけでした[^0]。
![敵スポーン１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/96a1597d-02e0-1704-e18a-d9383c9b44c8.png)
　ピッチ方向に制限をかけているのは、真下/上方向に出現するのは流石に狙いずらいからです。それと、``Enm Asset``に関しては「データアセット」を使用したものになっています。「データアセット」に関しては今回は紹介しませんが、次の記事ぐらいに詳細を紹介したいと思います。

[^0]: 引数の``Roll``は「ロール・ピッチ・ヨー」の内、ロールを有効にする設定みたいです。[What does ‘roll’ mean in the Random Rotator?](https://forums.unrealengine.com/t/what-does-roll-mean-in-the-random-rotator/355677/7)より。

## ゲームシステム
　後は簡単でプレイヤーのHPが０になるまで永遠に続きます。今回は簡易的な実装なので、敵は一定間隔でスポーンするようにしていますが、徐々に間隔を短くしていったり、敵UFOの速度を上げたりするなど色々考えられます。

### もっとゲームらしくするなら？
　敵の種類を増やしたり、自機の発射システムを変更したり（追跡弾・レーザーなど）、「頑張れば」もっと面白く出来ますね。今回は実装しませんが...。

# VRのUI
　VRの難しい部分「UI」についてです。下記サイトによると、通常のゲームで使用するUIは使えないみたいですね。

> VR上ではその仕組み上、2DのUIを扱うことはできません。常に正面に配置するためには3D UIを配置し、カメラの向きに合わせて正面を向かせる必要がありますが、これはVR上で酔いを発生させる要因となりやすいので、オススメできません。
https://forums.unrealengine.com/t/vr-ui/456821

　つまり、VRになるとUIがとてつもなく難易度が上がるという事ですね...。例えば、「酔わないように」かつ「分かりやすいように」かつ「VRでの世界観に合うように」など色々考えないといけない事に。
　プレイヤーの体力表示に関しては、自機のガラスにひびが入るといった演出も考えたのですが、今回は画面端に数値とアイコンを常時表示しておきます。他に、敵UFOの位置表示は表示しておくべきかとは思ったのですが、どうしたらいいのか考えものですね...。といっても、実装はしませんでしたが、実装するとなるとどうするべきでしょうか...。UIデザイナーに構想を放り投げたい気分です。

## UIの作成
　VRのUIはブループリントウィジェットを一つのアクターとして独立させます。つまり、UIを板ポリとして表示する「3Dウィジェット」として扱います。その為、ブループリントウィジェットは通常通りに作成します。といっても、ウィジェットの中身をどうするのか問題はありますが...。

1. ブループリントウィジェットとBPアクター（3Dウィジェット）の両方を作成
1. 作成したアクターに対して``Widget Component``を追加
1. 「``Widget Component`` ＞ 詳細 ＞ ユーザーインターフェース ＞ ``Widget Class``」に作成したブループリントウィジェットを設定
1. 「詳細 ＞ ユーザーインターフェース ＞ Draw Size」のサイズをビューポートを見ながら調整（デフォルトでは一部分しか表示されないからです）
![UI ユーザーインターフェース.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/0d1c0dfe-61a6-a4b7-77c8-3714e0e5ae8e.png)

　作成したアクターをスポーン・配置するだけでとりあえず表示されるようになります。勿論、値の変更などは通常通り可能です。

## UIの操作

　UIの「ボタン・スライダー」などはどうやって判定をするのかというと、プレイヤー側に設定する事で判定が可能になります。それが、前述した``WidgetInteractionL/R``になります。

1. プレイヤー側で``Widget Interaction Component``を追加
1. 上記で左右用に追加した場合（複数個）は「``Widget Interaction Component`` ＞ 詳細 ＞ インタラクション ＞ ``Pointer Index``」を変更（値が同じだと判定が同じになってしまいます）
1. 同じく「詳細 ＞ インタラクション ＞ ``Interaction Distance``」の値を大きくしておく（割と距離が短いので数値を大きめに調整しておいた方がいいです）
![UI インタラクション.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/54827df4-852e-186c-c4b3-5dfe68f97975.png)
1. ``Widget Interaction Component``の変数を取得
1. インプットアクションと``Press Pointer Key`` / ``Release Pointer Key``関数を召喚
1. 上記関数の引数に設定
    1. ターゲット：コンポーネントの変数
    1. Key：「マウスの左ボタン」
![自機 UI インプット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/cbe8b55d-bf25-9af0-3ff8-9d04d64cd223.png)

　後は、通常通りに「ボタン ＞ 詳細 ＞ イベント ＞ ``On Clicked``」でクリックイベントを追加して処理を記入します。スライダーなども同じ感じで、値の変更なら変数の``Set Value``関数になります。
　といった感じで、凄く簡単に判定が可能になりますね。そして、前述した``LaserL/R``に関してはUIへの指し示す先を表すための表示です。実は「デバッグ ＞ ``Show Debug``」をONにする事で、とりあえずライン表示が可能です。

## UIを微調整＆結果
　Widget側で更に調整するならば、「ボタン ＞ 詳細 ＞ アピアランス ＞ ``Style`` ＞ ``Hovered`` / ``Pressed`` ＞ ``Image Size``」で指している / 押された時にボタンの大きさが変わります。更に、「詳細 ＞ アピアランス ＞ ``Style`` ＞ ``Hovered`` / ``Pressed`` ＞ ``Tint``」を変更すれば色を変更可能です。VRになるとUIを指せているのか分かりにくいので、少しでも変化を加えます。
![UI アピアランス.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/caf02324-8f43-7aff-aae4-38b98402c223.png)
　これで簡易的な操作付きのUIは完了で、実装した結果が下図になります。
![UI.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/06741e13-81db-0770-9e66-5c66214de7f0.gif)
　ですが、単純なUIですし、ゲーム中に使用できるかというと微妙ですね...。どうなんでしょう。タイトル画面やポーズ画面ならまだありですね。
　確か、ビートセイバーの曲セレクト画面は下図のUIだったはずです[^1]。結局は使い方しだいですね[^2]。
![UI 例.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540257/321645cc-65f7-59d5-1085-137c225d5539.png)
　詳しい使い方は下記サイトを覗いてみて下さい。

https://docs.unrealengine.com/4.26/ja/InteractiveExperiences/UMG/HowTo/InWorldWidgetInteraction/

[^1]: Windows10のロゴに見えてきたのは私だけでしょうか？
[^2]: それを言ってしまったら終わり

## 作成したゲーム
　素早く見渡したりするので、<font color="red">**画面酔い注意**</font>です。

<iframe width="560" height="370" src="https://www.youtube.com/embed/Vt_B6i-PQeU?autoplay=1&mute=1&playsinline=1&loop=1&playlist=Vt_B6i-PQeU&controls=0&disablekb=1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

　こんな感じで極々シンプルなゲームのようなものです。ですが、初めてのVRゲーム制作なので手探り状態で始めていましたが、ある程度のクオリティはあるのかな？と思います。こんなゲームですが、VRになると「わぁ、ゲームだぁ～」に思えてしまうのは、目が肥えていないからでしょうか？
　UI（体力表示）の位置がかなり真ん中よりに表示されていますが、VR上では画面端に見えています。ここもVRじゃないと理解できない点なのかもしれません。

# 最適化
　完成したぞーと思い「実行」を押してみると、結構重い事が判明したりするかもしれません。やはり、PCと比べるとどうしても性能は落ちてしまうので仕方ないです。
　その為、色々OculusQuest2用に調整しないといけません。例えば、全体の描画解像度を落としたり、テクスチャ解像度を落としたり、レンダリング設定をいじったりするなど、色々と調整可能です。詳細は下記サイトを覗いて見て下さい。

https://unlimited-games.hatenablog.com/entry/2020/12/11/085533

# 最後に
　計３回に渡ってOculusQuest2を使った簡易VRゲームを作成しました。こんなに書くことになるとは思ってもいなかったのですが、色々と良い経験にはなったと思います。今度作るならガチガチのゲームを作ってみたいですね[^3]。
　全ての記事を見れば、UE4でVRゲームを作れる基礎知識を手に入れられるはずです。といっても、この記事だけではなく他の記事も参考にしながら、楽しいVRゲーム制作をしていきましょー。

[^3]: ※ 作るとは言っていない

--- 

　次回は学校での卒業制作にあたって、入手・使用した知識・技術をまとめた記事を上げる予定です。その後、待望？のユウナマ制作の続きに取り掛かります。長い間、記事を全く上げられずホントに申し訳ないです。
　卒業制作や引っ越しなどリアルイベントも色々ありましたし、モチベーションを保つのがホント難しいですね。つまり、今までは色々忙しくてなかなか記事を上げられませんでした。ですが、２・３月中は特に何もないので、１～２週間に１回のペースで上げるようにします。４月以降は分かりませんが...。

# 参考サイト

https://forums.unrealengine.com/t/what-does-roll-mean-in-the-random-rotator/355677

https://forums.unrealengine.com/t/vr-ui/456821

https://www.tachfirst.com/2021/06/14

https://www.slideshare.net/historia_Inc/vrui-78798570

https://docs.unrealengine.com/4.26/ja/InteractiveExperiences/UMG/HowTo/InWorldWidgetInteraction/

https://note.com/fujisunflower/n/n0a7f28f7f4b1

https://pafuhana1213.hatenablog.com/entry/2016/01/06/232858

https://developer.oculus.com/documentation/unreal/unreal-quick-start-guide-quest/?locale=ja_JP

https://shiratori1221.hatenablog.com/entry/2020/06/19/001201

https://unlimited-games.hatenablog.com/entry/2020/12/11/085533