【UE4】今さら、第13回UE4ぷちコン振り返り

[1]:http://historia.co.jp/ue4petitcon13
[2]:https://youtu.be/YMPzInSwadg
[3]:https://youtu.be/E031FMxMJ8Q
[4]:https://sites.google.com/site/seikodevmemo/top/ue4-petitcon13


しばらく更新していませんでした。ぷちコン応募後も、作品をあれこれ直していたので（言い訳）
それも一段落したので、今更ながらですが、UE4ぷちコン応募作品の振り返りを。

- [第13回UE4ぷちコン - 株式会社ヒストリアさん][1]
- [【第13回UE4ぷちコン】審査結果発表会！【拡張版】- Youtube][2]
    - 2:25:30 あたりで私の作品をご紹介いただきました（惜しかった作品枠w）
- [錯乱牧場 - Youtube][3] （私の応募作品の動画）
    - ざっくり言うと、マップのあちこちにいる恐竜たち(＝仲間)を回収して、厩舎に帰してあげるゲーム。
    - 巨大なドラゴン(＝敵)が恐竜を食べに来るので、食べられないように素早く回収する。

# 当初の予定はこうだった。本当はこうしたかった。

現役プロでも締め切りには勝てないのですw

## やりたくて、できなかったこと

### 「錯乱牧場」と言いながら、まったく錯乱できなかった。

- 恐竜たちの捜索
    - 恐竜たちは本当は、あまり画面内に見えないようにしたかった。
    - プレイヤーがボタンを押して「ギャオ！」とか吠えると、それを聞いた仲間の恐竜たちが吠え返したり、なんとなくプレイヤーの方に寄って来てくれる。
    - そうやって、どこにいるかわからない恐竜たち（迷子という設定だった）をうまく見つけ出して、回収してゆく、というゲームにしたかった。
- ドラゴン登場で、ドラゴンの周囲にいる恐竜たちがパニック(＝錯乱)を起こして逃げ惑う。
    - なんなら隊列組んでいる恐竜たちも、隊列から離れて逃げ惑う。
    - 仲間を探そうと吠えれば吠えるほど、ドラゴンにバレやすくなる。
    - 逆にドラゴンが出現したあたりには、必ず仲間の恐竜がいる。慌てて回収に行けば、ギリ間に合う感じに。

これ、ゲーム性のキモだったのだが、まったく間に合わなかった。悔しい。

当時のメモ：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/e4e90899-41f1-276d-14c8-139f4623683b.png)
これをずっと目に付く位置に貼り付けていたのだが、実現ならず…


### ドラゴンとブレスの撃ち合いがしたかった

- ドラゴンは着地前にしばらくエモノの付近で滞空している。着地したらエモノを食う。
- プレイヤーと仲間の恐竜たちが、火球を吐いてドラゴンを迎撃する。
- ドラゴンのブレスを食らうと、仲間がパニックを起こして逃げ惑う。
- 仲間をたくさん連れているほど、ドラゴンの迎撃がしやすい、みたいなゲームにしたかった。
    - その分、移動速度が遅くなるとか、
    - ドラゴンにブレス食らって散り散りになった後、捜索しなおすのが面倒くさいとか、
    - 先に厩舎に帰すか、ドラゴン倒すかを悩むとか、そういうことをやりたかった。

今考えると、夢見てたな～って感じ。（時間が無限にあればいいのにw）


### 結局は…

ドラゴンの実装を始めたあたりで、絶対間に合わないと確信。方針転換をした。
「とにかくドラゴンは絶対作る」「とにかく締め切りまでに何をでっちあげるか？」 みたいな思考に変わった。

- 恐竜を回収して、厩舎に戻す部分。これはできている。では、レベルデザインで誤魔化そう！
    - つまり、恐竜たちを順番に並べて「こっちに向かって進んでくださいね！」って絵面にして誤魔化す。
    - 完全に作業ゲームになるが、一定の楽しさはある。（＝ 一定の楽しさしかない）
- ドラゴン。もう、飛んできて、食って、飛び去る、でいいや！それしかできない！ 地対空戦闘とか絶対無理。

応募した作品は、まさにそういう作品になっている。
あ、このでっちあげ能力こそが、プロということか。

> 「やるべきことが分かりやすくて、たまに邪魔が入る」で、それなりにゲームになります。
> ただし、それなりなゲームにしかなりません。（反省）

## 土壇場で誤魔化したこと

### 意外と好評だったつぶやき

- 当初は残り何匹だとか、厩舎に戻したのは何匹だとか、死んだのは何匹だとか、そういう統計的な数字を（デバッグも兼ねて）画面の片隅に出していた。
- だが、土壇場で「そもそも、こんな単純なゲームに数字が必要か？」と思い至った。
- もともとは、プレイヤーの恐竜じゃなくて、仲間の恐竜が「どらごん こわい」「きゃー」とか小さい文字でつぶやく予定だった。

最終的に、本当に必要な数字だけに絞って、プレイヤーキャラがつぶやくようにした。（Widget名も WBP_Tweet であるw）
プレイヤーキャラ自体が画面の真ん中にいるので、プレイヤーの目線を（通常、画面の端にある）2D 表示に動かす必要がなくなり、一石二鳥である。今後も、隙あらばこの手を使おうと思う。

![20200427_1110.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/ebe9a277-aaeb-5737-16dd-d208b246c0e8.gif)

見ての通り、突貫工事でサクっと作ったものではあるが、実は「ひき」「びき」「ぴき」はちゃんと使い分けていたりするw

> プロの現場でも、「ここは分かりづらいから2D表示を足そう」と言ってしまうことが多い。
> だが、多くの場合、ゲームそのものが分かりづらいのであって、2Dを足したら解決するものではない。ゲーム本体を見直すべきである。
> だが、多くの場合、ゲーム本体を見直す時間なんて残っていない。2D屋さんにしわ寄せがくる仕組みになっている。困ったものである。

流石に突貫工事が過ぎたので、ここは応募直後にそれなりにデザインされた別のものに差し替えた。つまり、つぶやくシステムをやめたのだが、UE4ぷちコン審査結果発表会では思いのほか好評。困ってしまった。
結局は、デザインだけ変えて、当時と同じような挙動になるように、さらに作り替えた。

![20200427_1130.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/d4cf78b2-2bb0-5af5-4960-177b6471772c.gif)

> 後日、修正版のプレイ動画はUPしようと思います。


### その他の突貫工事

- どうしてもライトビルドのエラー(お馴染みのLIGHTING NEEDS TO BE REBUILT)が消せず、コンソールコマンド「DisableAllScreenMessages」で強引に隠した。（応募後に原因を見つけて解決済み）
    - 原因は、スプライン＋Instance Static Meshで作っている柵。
    - Construction Scriptで毎回作っている上に、Mobility (=Static/Stationary/Movable) を Static にしていたので、レベルロードの度に Static オブジェクトが新規作成される状態になっていた。
    - Construction Scriptで作るのをやめて、Call in Editor 関数で作るようにして対策。要するに、ボタンを押さないと柵が作られないようにした。

## できたこと

### Blueprint と C++ の適材適所

とはいえ、Blueprint 信者をやめるつもりはないので、いかに Blueprint を楽に組むかに注力。

- Actor など派生クラスが多くなりそうなものは、C++ 製基底クラスを用意した。
    - PanicFarmObjectBase, PanicFarmActorBase, PanicFarmPawnBase など。
    - 一方で、実装が空っぽで終わった C++ 基底クラスもある。PanicFarmGameInstanceBase, PanicFarmGameStateBase, PanicFarmGameModeBase, PanicFarmPlayerStateBase など。
- Blueprint が苦手だろう部分は C++ に逃がして、カプセル化／ブラックボックス化した。
    - ループをたくさん回して計算したり、検索したりするもの。
    - 配列などで複数のオブジェクトを管理するもの。（恐竜の隊列など）
    - 数式が主体で、Blueprint だとノードや分岐が増えてしまいそうなもの。
    - 自動ドアの開閉管理などの小規模なものも、C++ にしているものもある。
- NavMesh の FindPathAsync() 周りは C++ で ActorComponent を作って扱いやすくできた。
    - 個々の恐竜たちが NavPathRequestObject (UObject) を託すと、マネージャ側で１フレに n 回だけ PathFinding (非同期=async) を行う周り。
    - 取得した path (=FVectorの配列) を x メートルずつイテレーションして次の位置を求めるユーティリティ。
- Blueprint では、できる限り Event Graph を見渡せば全体の処理の流れが分かるように組んだ。
- 好みの問題かとは思うが、Component の Tick は基本的に OFF。その Component をもっている Actor が明示的にその Component の関数を呼び出す形にした。
- 関数に処理を逃がす場合でも、関数内でメンバ変数は直接いじらないようにした。
    - 関数の引数にメンバ変数を渡し、返り値で返ってきた結果を、Event Graph 側でメンバ変数にセットしなおす。
    - メンバ変数の値が変化するのは、必ず Event Graph 上になるようにした。
    - プログラムの全体像の把握や、デバッグがかなりやりやすくなった。

### 隊列

![20200427_1540.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/3be5e3b7-6987-03b2-d597-576c58fcfe78.gif)

ここは最初から難しい予感がしていたので、初期に時間をかけて作った。（逆に、時間をとられすぎた感もある）
細かいところに不満は残るが、おおむね満足のいく出来。

- プレイヤーキャラに「引きずられて動く」、m × n のマーカーが本体。
    - プレイヤーキャラの背にぴったり張り付くのではなく、なんとなくええ感じについてくる。
    - イメージ的には、ロープで台車を引っ張る感じだが、内部的にロープを実装しているわけではない。
    - マーカー本体の Forward = (1,0,0) および Backward = (-1,0,0) ベクトルのうち、プレイヤーキャラの Forward ベクトルに近い側を前方とする、ような仕組みなども入っている。
- 恐竜たちは、自分に割り当てられたマーカーをひたすら追いかけるだけ。恐竜側の実装は比較的シンプル。

### ドラゴン

![20200427_1545.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/b9751a20-fa5b-3b92-b0ba-c0f9b07024a7.gif)

- 納得のいくクオリティが出せたわりに、かかった時間は短かったと感じた。（といっても、ドラゴンだけで１週間くらい使っているが）
- アニメーション自体を編集してキーを打てる機能(Additive Layer Track)は重宝した。
    - 特に、DCC ツール上のオリジナルデータが入手できない Marketplace アセットなどは、自分の都合に合わせた改変がしやすく、便利。
- Anim Curve も多用した。とにかく、State Machine と Event Graph を駆使してフラグを立てるやり方が大嫌いなので、できる限り Anim Curve を直接 Anim Graph に取り込むようにした。

あと、せっかく格好よく作ったのに、ゲーム画面ではほとんど映らないかったのが残念。
以下は（何度か載せているが）テスト時のキャプチャ。

![20200320_1929.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/4a80c76a-d9d2-046a-cdc5-f5bfe82a76ca.gif)
![20200322_2017.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/c1a1a520-92f5-e651-3dff-9a683d30d238.gif)

# おまけ？

なんと、全作品にレビューを書いてくださった方がいる。
[[第13回UE4ぷちコン]振り返り：まとめ - seiko_dev_memo][4]

ありがとうございます！

> ２日で作ったわけではないですよ？　お題が出て締め切りまでフルに作業してました。


毎日何をやったかと何をやるべきかを書き綴った紙の束。分厚い…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/d69864d6-6e26-e4f6-9a5f-43a4acc6c706.png)