#はじめに
この記事は以下の記事に自分なりの補足を加えたものになります。
AI Sight Perception to Custom Points WRITTEN BY Carlos Pardo
https://blog.gamedev.tv/ai-sight-perception-to-custom-points/
まずはリンク先の記事を読んでいただいてこちらを読むと理解しやすいと思います。
#AISense_Sightの問題点
AISense_SightではAIが視認できているか否か(視線チェック)をLineTraceを用いてチェックしています。
しかし、この方法では少し問題が有り以下のような状況ではAIがプレイヤーを視認することが出来ません。
両者はそれぞれ胸から上までさらけ出しているにも関わらずAIが視認出来ない理由はLineTraceの終了位置がRootComponentの位置となってしまっているからです。
最初の方に張った引用元記事ではこの問題を解決するためにAISightTargetInterfaceを継承しCanBeSeenFrom関数をオーバーライドしています。
#CanBeSeenFromを更に改良してみる
引用元記事ではオーバーライドしたCanBeSeenFrom関数で
auto sockets = GetMesh()->GetAllSocketNames();
とすることでスケルタルメッシュが持つソケットを取得する様に書いていますがGetAllSocketNames関数はソケットに加えボーンまで取得されてしまいます。
C++ GetAllSocketNames returns bones along with sockets
https://answers.unrealengine.com/questions/726464/c-getallsocketnames-returns-some-bones-and-sockets.html
GetAllSocketNamesではIKボーンまで取得してしまいますので例えプレイヤーがしゃがんでいたとしても赤丸のIKボーンが見えていればAIには「見つけた」と判定されます。
この問題を解決するために上記の引用リンクにあるように
GetActiveSocketList()
を利用します。
修正場所は2箇所あります。
//TArray<FName> sockets = GetMesh()->GetAllSocketNames();
TArray<USkeletalMeshSocket*> sockets = GetMesh()->SkeletalMesh->GetActiveSocketList();
for (int i = 0; i < sockets.Num(); i++)
{
FVector socketLocation = GetMesh()->GetSocketLocation(sockets[i]->SocketName);
このようにGetAllSocketNames()をGetActiveSocketList()に置き換えます。
次にGetSocketLocation関数の引数部分を sockets[i]->SocketName に変更します。
GetActiveSocketList()ではUSkeletalMeshSocketを返しますから
#include "Engine/SkeletalMeshSocket.h"
このヘッダをインクルードすることを忘れないでください。
##スケルタルメッシュにソケットを追加する
GetActiveSocketList関数を利用したことでゲーム中に使用するスケルタルメッシュにソケットを追加する必要があります。
自分は以下のように頭、腰、両肘、両手、両膝、両足首にソケットを追加しました。
#改良の結果
結果1 | 結果2 | 結果3 | 結果4 |
---|---|---|---|
良い感じの結果が出ていますね。結果3や4は少しやり過ぎな気がしますが...
しかしこの方法のいいところはソケットの位置や追加場所を変更することでAIの視線チェックの位置を操作出来る所でしょう。
結果4のような結果が「理不尽だなぁ」と思われたのなら両足首のソケットを削除してしまえばOKです。
#おわりに
引用元記事を書いてくださったCarlos Pardo氏には感謝です。色々と勉強になりました。