🙄

【UE4】敵AI(NPC)にドアを開けさせる方法や、その際のNavMesh周りの問題点

2022/03/27に公開

前置き

ドア自体にコリジョンをくっつけて、そのコリジョンとの当たり判定時に、ヒットしたのがNPCだったらドアを自動で開けさせるという処理が前提になっています。
※ドアを開けるブループリントの処理自体は省略しています。
この記事では主に設定面について触れていきます。その際のNavmeshのくり抜き等、問題点等を説明していけたらと思います。
こちらの環境では、Navmeshを使い、ビヘイビアツリーのMove To タスクノードでNPCを移動させています。

ドア自体の設定

ドア専用のブループリントを用意し、コリジョンコンポーネントを追加

ドアにコリジョンをくっつけます。NPCとの当たり判定が取れれば形状は何でもいいと思います。
NPCがドアと接触したら、ドア側で用意したOn Component Begin Overlap イベント経由で、ドアを開ける処理を呼びます。
ドアの開閉アニメーションはTimelineで行っております。

コリジョンコンポーネント はNPCにつけてもいいかも?

一本の廊下があり、左右にドアがついていた場合、NPCがドアの前を通り過ぎるだけでドアが開いてしまったり制御が難しいです。
それよりはNPCの前方にコリジョンコンポーネントをくっつけていれば、NPCの進行方向に対し、コリジョンがヒットするので、ヒットしたアクターがドアの場合開けるという流れになります。
これならドアの前を通り過ぎただけで、ドアが勝手に開くという現象を避けられます。

ドアのStaticMeshの設定

ドアのStatic Mesh のコリジョン項目の Can Ever Affect Navigation のチェックを外します。
こうするとNavmeshの緑色の地面がドアで分断されることがなくなり、
NPCがドアを開けた際にも通過できるようになります。

Can Ever Affect Navigation が有効の状態

Can Ever Affect Navigation が無効の状態


これでNPCはドアを開ける力を手に入れました!
ただ、このままではまだ問題が起きる可能性があります。

問題が起きる可能性とは

可能性1:ドアが内開きの時、NPCがドアと壁にはさまる

対処法1:NPCをドアが開くまでの間、待機させる

StopMovementImmediatelyノードなど使えばNPCの移動を停止させることが可能です。もちろん、停止しているので再度移動させる処理を実装する必要があります。
ビヘイビアツリーのMoveToタスクノードで移動中に StopMovementImmediatelyノード を使うとNPCは移動をやめ、タスクは失敗扱いになります。

それでもドアにはじかれる

ドアを開ける位置によっては、NPCはドアにはじかれてしまいます。
で、そのままドアの回転に巻き込まれ、ドアと壁の隙間に挟まってしまうことがあります。

これを避けたい場合に、 "NavModifierVolume" を使うことで、回避することが可能です。
壁がないのに緑色の地面がくり抜かれていますが、"NavModifierVolume"の"Area Class"をNavArea_Nullに設定します。
そうすると、くり抜かれたエリアには侵入しないので、ドアの回転に巻き込まれそうなエリアには入らないようになります。このように、NavModifierVolume の配置によっては、NPCをある程度誘導することができます。
けど、力技感がすごいような...

対処法2: ドアが開くときだけ、ドアの当たり判定を解除する

ドアに当たり判定がないので、ドアの回転に巻き込まれることもありません。
多少すり抜けてもいいなら、この方法でも良いかもしれません。

対処法3: ドアを両開きにする

ゲームでよく見かけるので便利な手法なのかなと思ったり。
これならNPCがドアと壁の隙間に挟まる心配はないですし、いちいちNPCをその場に待機させなくても大丈夫になります。
ただ、プレイヤーがドアを開けることで起きうるトラブルは考慮されていません。
プレイヤーが内側、NPCが外側に同時にドアを開けようとした場合など。
NPCがドアを開けてる最中は、プレイヤーはドアを操作できない等細かな調整が必要になると思います。

対処法4: ドアの内側、外側にポイントを設置し、ドアを通過するためのルートを作る

ドアの前で停止させる際、StopMovementImmediately を使わず、
1...ドアの内側、外側にポイントを設置しドアを通過するためのルート作成
2...ドアに近づいたNPCは手前のポイントまで移動
3...手前のポイント到着後ドアを開ける(この間は待機)
4...ドアが開いたら、NPCは手前のポイントからドアの通過先のポイントまで移動
5...NPCは無事、ドアを通り抜ける
って具合にドアを通過させる方法。
これなら StopMovementImmediately 使わずともドアの手前でNPCを停止させることも可能です。
(ドアの手間が目的地になっていますし)
MoveTo(PointA)->DoorOpen->Wait-> MoveTo(PointB)
みたいな感じです。
試してないので具体的な説明ができないですが、以下の動画が参考になるかと思います。
https://youtu.be/b6_Dbsa1QA0

可能性2: Navmeshくり抜き問題

入口が狭い場合、両壁のStaticMeshでNavmeshがくり抜かれてしまうことがあります。
そうなると、NPCは入り口から部屋に入ることができなくなってしまいます。

ドア自体のCan Ever Affect Navigationが無効でもこの状態...
グレイマンが通れる幅のドアでもこのような現象が起こりがちです。
なので、以下に対応策を載せておきます。

入り口が狭くてNavmeshが途切れたりくり抜かれたりする場合の対処

※個人的に方法2の方が手軽でオススメ。

方法1.NavLinkProxy を使う

https://www.hakobuneworks.com/posts/navlinkproxyusage/
こちらの記事でとてもわかりやすく解説されているので、簡単な説明だけにとどめます。
要は分断されたNavMesh同士をリンクさせる機能のことです。
これで入り口のNavMeshが分断されていても、通れるようになります。

余談:そういえば、NavMesh1つしか使ってなかった...

そもそも、今までは部屋と廊下を1つの NavMeshBoundsVolume で済ませていたため、くり抜き等の問題に頭を悩まされることになりました。
部屋と廊下があったら、部屋の NavMeshBoundsVolume 、廊下の NavMeshBoundsVolume と二つ用意してみるのもアリかも、とふと浮かびました。
その際は、NavLinkProxy を使って、移動できるようにする想定です。

追記:NavLinkProxy 使ってみた時の挙動とか感想とか

NavLinkProxy を使った際の挙動です。
これを見たら NavLinkProxy の特徴が伝わるかと思います。

矢印が NavLinkProxy の始点と終点です。
何があろうと、矢印の先端へ移動してしまいます。たとえそれが遠回りであろうと。
この辺の動きがちょっとクセがあるというか、強制力すごいなぁという印象でした。

自分の例ですと、NPC(プレイヤーを見つけたら追いかけてくる)が部屋の中へ向かう際、 NavLinkProxy の上を移動中にプレイヤーを発見したことで、NavLinkProxy をもう一度始点から渡りなおすという、よくわからない挙動をしていました。
おそらくプレイヤーを発見したことで、Move To タスクノード(部屋の中へ)がキャンセルされ、 NavLinkProxy 上での移動もキャンセルされたためだと思われます。

方法2. RecastNavMeshを編集する

NavMeshBoundsVolumeをレベル上に配置した際に、RecastNavMesh-Defaultというアクタも自動で置かれます。
RecastNavMesh-Default というアクタを確認してみると、以下のように様々なパラメーターがのっています。

半径42
”エージェントの半径”という項目を小さくすると、壁際まで緑色のエリアが拡大します。

半径0

※エージェント半径という項目が、壁際からの距離や通れる隙間を定義するものとのご指摘をいただき、気づくことができました!ありがとうございますm(_ _)m
これで、Navmeshのくり抜き問題は解消されます。
エージェント半径についてはこちらの記事でも触れられております。
他にも エージェントの高さ等、詳細な説明が載っており、参考になります。
https://ken26u.blog/ue4/2020-07-12-225740/2020/07/12/#toc23

Discussion