【UE4】建物にNPC(人物)をランダムに徘徊させる~大量発生&階をまたいだ移動編~
さてさて。今回は何気にシリーズ化している『UE4でNPCをランダムに動かすシリーズ』の続きです。前回でNPCくんが1人動き回るようになったところまで出来ましたが、実際はわちゃわちゃと数がいっぱいいて、各自がランダムに動いてほしいですよね。ということで今回は、
●特定位置に数秒ごとにスポーンして賑やかな状態を作ってみましょう。
●さらに建築ビジュアライゼーション向けを意識して、階をまたいで移動させてみましょう。
説明する手順はあまりなくて、追加でブループリントを2つ作るだけです。
前回の記事
![]()
作り方
動画版
1.大量発生元を作る
ひとまず最初はスポーン位置を作りましょう。[新規作成]→[ブループリントクラス]を選択。[Actor]を選んで確定。
名前は[NPCSpawnActor]としましょうか。
ブループリント編集画面を開きます。
[コンポーネントの追加]で[Arrow]を追加しておくといいと思います。配置したときに向きがわかるようになります。
さて本題。内容はシンプルで、
①タイマーイベントを作り。
②イベント先で指定したCharacterをスポーンする
ってだけです。
イベントノードの説明をしますと、
[Time]は、何秒ごとにイベントを実行するか。
[Looping]は、trueにすると何回もイベントを実行します。
[SpawnActor]を置いて、[Class]で生成したいCharacterを指定します。ひとまずマネキンさんにしておきましょうか。
[SpawnTransform]は位置を指定しますが、自分のアクターの位置でいいので[GetActorLocation]の返り値をセットすればよいです。
以上。NPCの発生源の作成は終わり。[NPCSpawnActor]アクターを好きな場所にを置きましょう。ここからNPCが湧いて出てきます。
2.移動ロジックを改善して階をまたいで移動できるように
前回作ったビヘイビアツリーのロジックのままだと同階しか移動できなくなります。そしてよくわかりませんが1階には移動できたりします。不安定です。
ということで階移動ができるビヘイビアツリーのタスクをもう1個作りましょう。
[新規作成]→[ブループリントクラス]を選択。[BTTask]を選びます。
名前は[NPCWander]としましょうか
ひとまず必須の関数を置きまして。
さらに追加でVector型の[CurrentPosition]変数を追加します。
[CurrentPosition]初期値を割り当てます。[GetActorLocation]でOK。
何が正解? 仕様?
本当は都度[GetActorLocation]すれば最新の現在位置がとれると思うのですが、どういうわけかイベントで[SpawnActor]すると、何度[GetActorLocation]してもスポーンした生成元(NPC3SpawnActor)の座標しか取れまません。これが仕様なのかは不明です。
自分の座標を手動で覚えておく
ということで代替手段をとります。現在位置の座標を自分で覚えておきます。
階移動の考慮を加えたいので[RandomPointInBoundingBox]を置きます。このノードに期待する結果は「この階に留まるか、階を移動するかを決定すること」です。
例では1回の移動につき最大1フロア分までの移動としたいと考えています。
この建物は1フロア400cmですので、Z=500~600cm程度にします。例えば2フロア分だったらZ=900cmくらいですね。行き先が完全ランダムであればビル高さと同じ値にすればまあいいでしょう。
このノードで求まったランダム座標を基に[GetRandomPointNavigatableRadius]を置き、行けそうな場所を決定します。
inputの[Radius]は最大移動距離です。前回覚えたノードですね。
どうしてこんな2段仕込みにするかというと、[GetRandomPointNavigatableRadius]ノードはXY平面しか考慮していないからです。エンジンソースのRecastNavMesh.cppを見るとわかります。
目的地検索が失敗した場合の考慮
それでですね。この階またぎ、結構失敗率が高いんです。そこで対策として「失敗したら数秒待ってもう1回目的地を検索させる」ことにします。やることは2つ。
・[Delay]を置いて、待ち時間を指定。
・[Delay]のoutputから、もう1回[Branch]を呼びます。
これで再び[GetRandomPointNavigatableRadius]してくれます。
あと、最悪、永久ループする可能性はゼロではないので、5回リトライしたら諦めるみたいな考慮があったほうが安全だと思います。
最後に目的地が見つかった場合の処理を作ります。[CurrentPosition]変数を更新します。
BTTaskをビヘイビアツリーに割り当てる
最後に作ったBTTask[NPCWander]を既存のビヘイビアツリーの[Wonder]と差し替えます。
3.その他
NPCの上限数ですが、[NPCSpawnActor]に対してカウンターとかをつけて、最大数未満だったらスポーンするみたいな考慮すればよいでしょう。
完成
さて、今回の課題はクリアできましたね。Playをするとわちゃわちゃとマネキンさんがスポーンされていき、各自がランダムな位置に好き勝手に移動しだします。
UE4のマネキンさんって結構ポリゴン数があるかなと思いますが、私のPCでですが300人くらいスポーンしてもは余裕で動いていました。
課題
これがですね、NPC数が多くなるにつれていくつか問題が出てきます。
ぶつかるんですねー。大渋滞!
コロナ禍にこの画はまずいですよ! みたいな事態になります。
単純に回避するのであれば、CharacterのCollisionをOFFにすればいいんですが。あえてそれはやらずNPC同士が近づいたら避けたりするような何かしらの別のアクションを加えたいですね。
ということで次回はNPC同士が近づいたら特定のアクションを行うようにしたいと思います。
参考サイト
・