株式会社ヒストリアさん主催の第13回UE4ぷちコンの作業進捗。
グラボが死んでからずいぶん間をあけてしまった。
あの後、1週間後に(※)PCのサポートセンターから交換用のグラボが届いて、そこから作業を再開したのだが、結構な時間を浪費したので、かなりテンパり気味に作業した結果、進捗記事を書くのをさぼってしまった。
※最近のご時世のアレで、メーカーさんもグラボの調達に予想外に時間がかかったようである。
さて、現状はこんな感じ
ここしばらくは、恐竜の仲間たちが障害物を避けられるようにアレコレ実験していた。
水色の柱が目的地、白いのが壁。
ここまで作ってきたぷちコン本体のプロジェクトを汚したくなかったので、別のプロジェクトで実験している。
- ご存じ NavMesh を使用している。
- もともと、恐竜たちは物理で動いているので、pathfinding の結果(=経路情報:
TArray<FVector>
)を愚直にたどる方法との親和性が低い。 - 現在位置と pathfinding で得られた移動経路から恐竜たちに与える force をなんとなく求め、最終的には物理として処理するようにした。(ここが難しかった!)
NavMesh でハマったこと
コリジョン設定
私は通常、UE4 標準のコリジョンプロファイル(BlockAllやOverlapAllなど)は使っていない。基本的に関係ないものはすべて Ignore にしたいからだ。
地面のコリジョンプロファイルも、自作の Ground というものを使っている。そうすると、地形を作って、壁などを配置した後、Landscape の Collision Preset (=Collision Profile※)を自作の Ground に切り替えたとたん、NavMesh がなくなってしまった。
※UE4 内でも Collision Profile と Collision Preset が混同して使われている様子。とりあえず私は Collision Profile と言うことにしている。
色々試行錯誤した結果、どうやら Pawn を Block する設定をした地面でないと NavMesh は生成されない…ではないか、と思われる。
RecastNavMesh-Default とプロジェクト設定
NavMesh のビルド後に自動生成される「RecastNavMesh-Default」について。
RecastNavMesh-Default のパラメータをいじると NavMesh が更新されるが、レベルをオープンしなおしたり、次回 uproject を起動したときなどにデフォルト値に戻っている。
調べた結果、Project Settings > Engine > Navigation Mesh の設定をいじるのが正解のようだ。
設定のテスト自体は RecastNavMesh-Default で行い、最終的には Project Settings にその値を書く、という感じでやればよかろう。
ところが。
主に設定した値は Agent Radius, Agent Height, Agent Max Slope なのだが、結局 Agent Max Slope しか反映されていない様子。何かほかに設定しなくてはいけないものがあるのだろうか?
これについては現在放置中。最悪このままでいく。
Pathfinding は重い
※pathfinding = 障害物を避けて目的地に至るまでの経路を検索する方法
当たり前といえば当たり前なのだが、個々の Pawn が毎フレーム pathfinding を呼び出すと、テキメンにフレーム落ちする。なので今回は:
- pathfinding のマネージャ的なものを用意する。
- 各々の Pawn は、そのマネージャに「リクエスト」を投げる。
- マネージャは1フレーム当たり1回しかリクエストを処理しない。(この回数は変更可能)
- 各々の Pawn は、マネージャから返ってきたパス(
TArray<FVector>
)の最終点に到達するまで、リクエストは投げない。
という形でやってみた。
結果は良好。50体を動かして、冒頭の .gif アニメのように、一応 120fps を(ギリギリ)保っている。
注意:ゲーミングPCなので、CPUはまあまあ強い。
だが、ファンは回りっぱなしだった。
おまけ: FindPathAsync()
Blueprint に Find Path to Location Synchronously というノードがある。
これが pathfinding をやってくれるノードである。
単なる好奇心で C++ の実装を覗いてみたのだが、そのついでに FindPathAsync() なる関数を発見した。非同期で pathfinding をやってくれるのはありがたい。今回はこちらの関数を使っている。
UNavigationSystemV1::FindPathAsync() - Unreal Engine 4 Documentation
困ったことに、Web検索をしても、エンジンソース内を覗いても、この FindPathAsync() を使っている例が見つけられなかったが、最終的には上記 Blueprint ノードの元関数、UNavigationSystemV1::FindPathToLocationSynchronously() を参照して意図通り動作するように使うことができた。
なお、いくら非同期とはいえ、多数のリクエストを同時に、かつ高フレームレートを維持したまま処理できるわけではないので、ご注意ください。
では、作業に戻ります。