第16回UE4ぷちコン参加振り返り

# 第16回 UE4ぷちコンに初参加してみました
約１年前からUE4に興味を持ち始めて、今年の春あたりから色々なイベントに参加しながら勉強していたのですが、遂に念願のUE4ぷちコンに挑んでみましたので、その振り返り記事になります。
なお、今回のお題は「みち」ということで、「道」か「未知」が王道って感じですが、車好きとしては車を走らせる為の「道」を使ったゲームを作ることにしました。
そして、参加にあたって次の目標を決めました。

* 新しい事への挑戦としてNiagara ビジュアル エフェクト システムを使う
* カットシーンを効果的に使う
* 作品の提出方法は動画形式の為作りこむ必要が無いかもしれないが、一つのゲームとしてオープニングからエンディングまで完成されたものを作る
* データテーブルを使う(データテーブルから文字を読み込んでRPGの会話システムのようなものを作れるように練習する)

普段はPCでゲームをしないうえに、仕事で業務系のWEBシステムを作っているPC(簡単に言えばオンボードGPU)での参加となる為、UE5やUE5の新機能(NaniteやLumenなど)を使うことができませんでした。本格的にやっていくなら、GPU買わないとな・・・

# まずは作品紹介
提出した作品は「Cubic Drive」というゲームで、３Ｄの道ブロックを転がしながら道を繋いでいき、車をゴールまで導くという内容です。
提出した動画はこんな感じです。

<iframe width="560" height="315" src="https://www.youtube.com/embed/fPLlg6eJjTo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


また、このゲーム用のHPも作りましたので、こちらもご覧ください。
こちらから、ゲームの実行ファイルもダウンロードできます。

https://ue4petitcon.futuresoftware.dev/


# 何を作ろうか・・・
車と「道」ということで、色々考えた末に思いついたのが、スライドパズルで車を誘導していくゲームでした。
過去に所有していたFM-TOWNSに「パニックボール２」というゲームが入っていたのですが、基本ルールはこれと同じにする予定でした。

パニックボール２については、Youtubeに動画が上がっていたのでリンクしておきます。

https://www.youtube.com/watch?v=BE3Im1tN_hE

# まずはパズルゲームのサンプルを眺める
しかし、ここで重大な事に気が付きます。
今までThirdPersonテンプレートを元にしたプロジェクトしか作った事がなく、パズルゲームのブロック等はどのように表示させるのが一般的なのか分かりませんでした。
そこで、UE4に含まれるパズルゲームのサンプルプロジェクトを眺めてみる事にしました。

![qiita001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142507/3e2db545-50ee-3659-3b59-092c8c1c5aea.png)

PuzzleBlockGridのBeginPlayを眺めると、パズルで使うブロックは、座標を計算しながらSpawnしていることが分かり、これを参考に道のブロックを並べていくことにしました。

# 道ブロックをSpawnしながら配置
道ブロックを動的にSpawnするには、道データを保持していく必要がある為、データテーブルを使って２次元の道データを持ち、それを元にブロックを表示していきました。
ここで苦労したのは、道ブロックは「曲がり角」「直線」「T字路」など様々な種類があり、しかも0度・90度・180度・270度の回転の初期値もデータテーブルに持たせなければならないということでした。１つのブロック情報を連想配列(Map)で定義し、そこにブロック種類・回転等の情報を持たせ、それを２次元配列で管理するという方法を採用しましたが、いざステージデータを作ろうとしたら、「このブロックは直線で、90度回転していて・・」「これはT字路で、180度回転していて・・・」「あれ、これじゃ道が繋がっていない！」という感じで、パラメータを眺めながらのステージ作成に苦戦した為、動的にブロックをSpawnする方法を諦め、UE4のレベル上に直接「道ブロック」を配置していく方法にしました。(これが最終的には間違った判断になるとも知らずに・・・)

# 最初の難関
元々はスライドパズル的な動きを想定して作っていたのですが、３Ｄでステージを作ってるのだから、ブロックも３Ｄで作れば良いのでは？と思い、３Ｄで作った道ブロックがゴロゴロと回転して道を繋いでくゲームに方向転換しました。

ブロックが転がりながら移動するということで、プロトタイプを作ってみたのですが、これが苦戦する結果に・・・

メッシュ自体を回転・移動する関数はUE4に用意されているので簡単に実装できたのですが、例えば"１秒掛けて90度回転しながら隣のブロックの位置に移動する"を正確に実装しようとした場合にどうしてもズレが発生してしまいます。
具体的には、道ブロックのActorにRotatingMovementコンポーネントを追加し、回転イベントに応じてRotationRateのZ軸に90を入れてSetTimerで１秒後に0に戻すという処理を入れた場合、キッチリ90度回転することはマレで、85度だったり95度だったりと結果が安定しませんでした。アクションゲームなどでは大した問題ではなくても、ブロックの位置や角度が重要となるゲームでは致命的な問題となります。

そこで、BPでロジックを組んで自分で回転・移動を実現する事にしました。

![qiita002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142507/0bfe331c-66cb-b237-0a3f-e91465d6ea8d.png)

TickのDeltaSecondsを元に今のフレームではブロックをどれだけ回転・移動させれば良いかを求め、回転・移動量をフレーム毎に加算していきます。
理論的にはこれで指定した秒数後に正しい回転・位置に移動しているはずですが、もし回転・移動しすぎてしまった場合は補正を入れています。
そして、最終的には目的とする回転・位置になったらブロックの移動を完了させるという仕組みです。

果たしてこれが正解なのか！？と思いましたが、フレームレートに左右されずに同じ秒数掛けてブロックが移動することを確認できたので、今回はこれで完成としました。

# 次なる試練
次に苦戦したのは、曲がり角を曲がっていく車の移動方法です。

このゲームに登場する全ての車は、能動的に曲がることはなく、曲がり角を設置することで初めて車が向きを変えることができます。
直進する車の移動ロジックはとても簡単ですが、曲がり角では車が方向転換しながら、X軸への移動量を減算しながら、Y軸への移動量を加算していく必要があります。
最初は三角関数を使ってX軸・Y軸の移動量を変化させようとしましたが、よくよく考えてみたらUE4のスプライン機能が使えそうな事に気が付きました。

![qiita003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142507/e4ed54ec-087a-2ffb-219e-635407094a5b.png)

ということで、完成品がこちら。
道の上にBoxCollisionを設置して、車がBoxCollisionにオーバーラップしたら車の移動をスプラインに沿わせるようにしています。
(この世界は左側通行なので、BoxCollisionは左車線しか監視していません)

スプラインについては、アンリアルクエストというイベントでターザンロープの実装経験があった為、容易に実装することができました。

ただし、この実装方法には一つ問題があります。(今回は作品完成までに解決できなかったので、今回は仕様で逃げましたが。。。)
BoxCollisionとオーバーラップした時点で車の移動をスプラインに沿わせると言いましたが、この場合BoxCollisionの設置場所とスプラインのスタート位置がとても重要になってきます。
今回は車両の大きさを統一するという仕様で逃げた為、問題は発生しませんが、乗用車・バス・トラック等の全長が異なる車両を登場させた場合、車両側にも曲がり角に入ったという判定を行う為のCollisionを設置してあげないと、車の位置がワープするような挙動になってしまいます。

![qiita010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142507/061e82aa-998d-04d0-4b3b-ac8bcfcd4d36.png)


バスやトラックが登場すれば、もっと複雑なルールになって楽しみが増したと思うのですが、実装できなかった点はとても残念でした。

# 演出って大事
ある程度ゲームとして動くようになった時に気づいた事は「演出って大事」ということでした。
例えば、道のブロックが移動するのだから重量感を表す為に画面を揺らすとか、車が道路からはみ出してしまった場合に印象に残る映像で表現するとか・・・
普段は業務系のソフトばかり作っているので演出という考えがなく、この発見は大きいものでした。
ということで、今回のゲームの制作時間の半分は演出を作る時間だったと思えるくらいに演出の制作を頑張りました。

![cdss4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142507/f6fed3be-a0ce-19c4-2b31-057505650052.png)

![CubicDrive02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142507/35fd2d16-ed55-6b15-6701-a7cd090bc733.png)

![CubicDrive05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142507/0375d7cf-bfa6-fe40-09e8-1dbdf72540f4.png)

# カットシーン
アンリアルクエストというイベントで、「スーパー〇リオもどき」を作った時にボスと対峙するプレイヤーのカットシーンを入れたのですが、あの時はカットシーンを作る事に必死で、単純にカメラを横に移動させるだけで終わってしまいました。

今回はそれを超える為に、車がクラッシュした時にカメラが切替わるという仕組みを用意しました。
クラッシュを検知するとプレイヤーカメラからクラッシュした車両の実況カメラに切り替わり、カメラにはポストプロセスによる集中線が表示されます。
カメラの切り替えは瞬間的に切り替えるのではなく、プレイヤーカメラから実況カメラに移動するように切り替わる為、ステージのどこでクラッシュしたのかをプレイヤーが理解できるようにしてみました。

# ライブカメラ
このゲームを作っている最中にブロックを並べて車を走らせた時の第一印象が「"シムシティ"や"A列車で行こう"みたいだな」でした。
ミニチュア感・箱庭感があるデザインになったので、そのような印象だったと思うのですが、この時に思いついたのが、車の視点・車の背後の視点を表示する機能でした。
ただ、リアルタイムで動くパズルゲームと、視点切り替えの機能は相性が悪く、視点を切り替えている間にミスをしてしまう可能性があります。
それを解決する為に、ステージサイドにスタジアム等にあるような映像表示エリアを作って、車視点のカメラからの映像を投影するようにしています。
メイン画面で表示すれば、もっと迫力のある映像になったと思いますが、これはこれでアリかな？と思います。

![CubicDrive04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142507/23b7fcc6-e2ab-35f7-c0cc-dc0d3d9754cb.png)


# ステージエディタ
ユーザーが自由にステージを作るパズルゲームって、パズルゲームの理想だと思っている私にとって、ステージエディタを公開することは目標の一つです。
ステージエディタがあれば、ステージ数は無限に増えていき、遊ぶ方も、ステージを作る方もいつまでも楽しむことができます。

ということで、ステージエディタをvue.jsで作ってみました。
(まだ、未完成ですが・・・)

https://ue4petitcon.futuresoftware.dev/editor

![qiita006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142507/5ca66b8d-657e-8935-ebcf-ae2641974b76.png)

しかし、今回はステージのブロック配置をレベル上に直接置いてしまった為に、ステージデータを読み込んでブロックを配置するという仕組みになっていません。。。。
とは言っても、ステージ生成部分のロジックのみを変更すれば実現は可能な為、時間を見つけてはプログラムを改修しているところです。
最初から考慮しておけばよかった・・・

# FPS
完成した作品は15FPSで動作するものになっていました。しかも、ライブカメラを使うと7FPSという悲惨な結果に・・・
オンボードのGPUで動作させているので仕方ないのか？と思いながらも、試行錯誤した結果、レベル上のライティング系(AtmosphericFog/DirectionalLight)の設定をスタティックにすることで、通常時は60FPS、ライブカメラを使っても40FPS以上で動くようになりました。
今回のゲームはローポリ系の素材を使っていた事から、ここらへんの効果を無くしても違和感が無いのは運がよかったと言えます。

# 最後に
UE4初めて触った時から参加することが目標だった「UE4ぷちコン」でしたが、何とか作品を作り上げて提出するところまでたどり着きました。
作品を作る期間も１カ月程度あるので、社会人でもスキマ時間を使って参加できる良いイベントだと思います。
次回はもっと実力をつけて、皆さんが楽しめる作品を作っていけたらと思います。

あと、まともなGPUが欲しい・・・