そうだ、ゲームを作ろう

現状や学んだことなど記録するブログ。間違ってたらごめんね

AIで色々悩んでみた:AI知覚編

AIの知覚とそれに伴う様々な要素のお話。

f:id:wvigler:20191114111324p:plain

 当然のことですが、AIはAIにとっての敵(プレイヤー)やその他障害物を知覚する要素というものが備わっています。BehaviorTreeでもそれらの要素によって状況判断をしたり、Blackboardに記憶してそれに応じたアクションを起こしたりします。

「極め本」ではLineTraceを使ってこの情報を取得していました。これはこれで一つの道ではありますが、普通にやると直線でしか情報を取得できないですし、じゃあこれを発展させて"視界"のようなものを作ろうとなるとかなり専門的な知識が必要になります。(最初期にそうしようとして色々調べてみたらQuaternionが出てきて諦めた)

そこでUE4にはこれらの知覚をサポートするコンポーネントがいくつか備わっています。それらを一つずつ見ていきましょう。

 

・PawnSensing

まずはこれです。やや拡張性に欠け、ちょっと使いづらい面もありますが、スタンダードな視覚と聴覚をサポートしてくれます。

f:id:wvigler:20191123143124p:plain

Characterにアタッチしたところです。見やすいようにパラメーターは少しいじっています。緑色のコーン型のガイドが視覚、青のSphere型が聴覚、黄色が「間に何も障害物がない場合の」聴覚範囲(LOSHearingThreshold)です。

f:id:wvigler:20191123161410p:plain

感知にはIntervalがあるので注意しましょう。まあHearingMaxSoundAgeと一緒に調整すればそんなに気にならないでしょうが。

名前の通り視覚では基本的にPawnを感知します。OnlySensePlayersにチェックを入れておけばプレイヤーであるPawnだけを感知します。聴覚の方はちょっとだけ特殊で感知される側にPawnNoiseEmitterというコンポーネントが必要です。

f:id:wvigler:20191123225330p:plain

f:id:wvigler:20191123225449p:plain

このコンポーネントからMakeNoise関数を呼び出して音を出します。ちなみにAIカテゴリに"普通の"MakeNoise関数もありますがこちらでは駄目です。

f:id:wvigler:20191123225820p:plain

上の画像だと一番右のノードだけがPawnSensingで知覚できる音を発生させられます。

さて、PawnSensingが視覚から情報を感知した場合OnSeePawnEventが、聴覚の場合はOnHearNoiseEventが呼び出されます。

f:id:wvigler:20191123231139p:plain

PawnSensingの利点は実装が比較的簡単なことと、最も重要なのはViewportにおいてガイドが出るので視界などのイメージがとても分かりやすい、ということです。なので単純なAIでしたらこちらでも問題無いと思います。

 

・AIPerception

さて、こちらはガイドがありません。それどころか初期状態では何も感知できません。その代わり拡張が可能なコンポーネントです。そしてこちらは情報が"入った時"以外にも"失った時"も検知することができます。

f:id:wvigler:20191123233251p:plain

f:id:wvigler:20191123233425p:plain

いきなり注意なのですが、このコンポーネントは基本的にはAIControllerに付けます。実はPawn自体に付けても動くは動くのですが、一部の機能が使えなくなるようです。

qiita.com

AIPerceptionの各感知は配列になっており、SensesConfigパラメーターから感知を追加していく形で実装します。こういった形なので例えば一つのキャラクターが複数の視野の異なる視覚を持ったり、などといった動作が容易に実現できます。

f:id:wvigler:20191123235235p:plain

さて色々知覚の種類が並んでいますね。これについては後で説明するとして、知覚した場合、OnTargetPerceptionUpdatedEventまたはOnPerceptionUpdatedEventが呼び出されます。

f:id:wvigler:20191124004251p:plain

情報の受け取りはAIStimulus型というStructureで行います。ノードのOutputはこのようになっています。

f:id:wvigler:20191124004829p:plain

ちょっと注意すべきこととしてAIStimulusの情報の受け取り方にはクセがあります。例としてOnPerceptionUpdatedEventからのスタンダードなノードの組み方を載せておきます。

f:id:wvigler:20191124010233p:plain

このようにすることで知覚された各TargetのSensesConfig配列の0~2までに入っている知覚に関する各情報を取り出すことができます。

さて次はそれぞれの知覚について紹介します。

 

・AI Sight config

まずは視覚から。

f:id:wvigler:20191123235752p:plain

一覧からAI Sight configを選択すると、上のようなパラメーターが現れます。PawnSensingの視覚と違う部分を少し説明します。

LoseSightRadiusはSightRadiusに対象が入った後に、補足していた対象を見失う距離です。

DetectionByAffiliationは敵味方の区別を付ける働きがあるのですが、どうにもこの区別は現状C++からしか設定できないようです。なのでそれが分からなかったら基本全部チェックで問題ないかと。一応設定の仕方はここに載っています。

denisrizov.com

AutoSuccessRangeFromLastSeenLocation(長い!)は対象を見失った地点から指定した距離内に対象が入った場合、強制的に知覚を成功させる、という機能なのですが…うーん。恐らくですが、コーン型の視界を持っていると補足した対象に頭を飛び越えられたりした場合、すぐに見失ったりしてしまうことに対する対策としてのパラメーターなんですよね…でも見失った位置を"いつまでも"覚えているので、普通に振り切った場合でも、見失った位置に近づくと成功になって全く関係ない位置から知覚されてしまったりして…ということで上手い使い方が見つからないです。知ってる人教えて下さい。

MaxAgeは知覚したものを覚えている時間です。これを過ぎると自動的に知覚情報のSuccessfullySensedがFalseで更新されます。

 

・AI Hearing config

続いて聴覚です。

f:id:wvigler:20191124012218p:plain

これに関してはPawnSesingの聴覚とそれほど変わりません。DetectionByAffiliationとMaxAgeが付いたのと、LOSが選択制になったぐらいでしょうか?ただ"音"の立て方についてはPawnNoiseEmitterを用いた方法とは少し違います。それについては後で説明します。

 

・AI Damage sense config

Damageを受けた相手を知覚します。あえて言うなら痛覚でしょうか?

f:id:wvigler:20191124020051p:plain

 「普通にAnyDamageで情報を受け取れば?」などと思ってはいけません。

 

・AI Touch

触った相手を知覚します。触覚です。

f:id:wvigler:20191124020411p:plain

 「普通にCollision判定から受け取っては駄目なの?」とか言ってはいけません。(というか検証したら普通に動かない。情報求む)

 

・AI Prediction sense config

相手の位置を予測します。第六感です。(嘘)

f:id:wvigler:20191124032642p:plain

パラメーターは少ないですが、情報発信の仕方は少し特殊です。後述します。

 

・AI Team sense config

一応ドキュメントによると仲間が近くにいる場合にその仲間を知覚する、らしいんですが…

f:id:wvigler:20191125053913p:plain

設定方法が全然分からない…そもそも仲間の設定もC++通じてしかできないんだし…英語ですら資料が少ない…というわけで今後の誰かの研究に期待したいです。

 

・AIPerceptionStimuliSource

さてさて今度はいよいよ情報の発信側です。

まず発信側はAIPerceptionStimuliSourceというコンポーネントを追加しま…ん?ちょっと待って。

qiita.com

AIPerceptionStimuliSourceが無くても動く?ははは、そんな馬鹿な…

 

<検証中…>

 

動くよ!

じゃあこのAIPerceptionStimuliSourceってコンポーネントは一体何なんだよ!

 

はい、というわけでAIPerceptionStimuliSourceは必要ありません。でも一応付けといたほうがいいと思います。

 

・Report

気を取り直して次です。AI Sight config以外のSenseConfigでは特定タイミングで情報を"発生"させる必要があります。これは送信側でノードを実行することで行います。それがReportノードです。

まずはAI Hearing configです。"音"を発生させるのはReportNoiseEventというノードです。

f:id:wvigler:20191125060005p:plain

次にAI Damage configです。これは普通のApplyDamageなどでは駄目で専用のReportDamageEventノードを実行することになります。

f:id:wvigler:20191125060500p:plain

 …そしてなぜかパラメーターに何も繋げられない謎のノードがありますが、もうあんまり気にしないことにします。なにか用途があるんだろうか?

f:id:wvigler:20191125060654p:plain

 

・AI Prediction configの情報受け取り

AI Prediction configは他とは違って"予測"を扱うものなので、情報の受け取り方もちょっと変わっています。まずAIController側にRequestPawnPredictionEventまたはRequestControllerPredictionEventを用意します。

f:id:wvigler:20191125062040p:plain

先程説明したAIStimulusからの情報の受け取りにこれらのノードを追加します。RequestorはAIControlerを持っているPawn、PredictedActorは知りたいActor、PredictionTimeは何秒後の位置を予測するか、です。

f:id:wvigler:20191125224656p:plain

f:id:wvigler:20191125224735p:plain

実装の一例です。これでSenseConfigの配列0番目にAI Prediction configを指定していた場合、BlackboardのPredictedLocationに対象の1秒後の予測位置が書き込まれます。(まあ普通はCastして対象を指定するとは思いますが…)上ではRequestPawnPredictionEventを使っていますが、RequestControllerPredictionEventの場合はGetControlledPawnをSelfノードにするだけです。Location以外の情報には意味がないことも注意しましょう。

 

さて、AI知覚の話はこれで終わりです。え?AI Team configやAI Touchはどうなってるんだって?

知らんよ。

そもそもExperimentalな機能過ぎて、現状正常に動くのかすらよく分からないし…というかAI知覚の大部分は普通にLineTraceやCollisionでやろうと思えば実装できるものばかりなんですよね(多分内部的にも同じだろうし)。そういう知識がどうしても足りない人のために用意されたものなんですが、AI知覚自体の設定が面倒なので、視野角の設定が難しい視覚やPredictionなど変則的なもの以外は利用価値が微妙なことになっています。

なのでTouchやらTeamやらそういう機能をつけたい場合は他のアプローチから探しましょう。ぶっちゃけそれで充分です。

それにしてもやっぱり一番長くなったなあ、でもあとはEQSとDebuggerだけだ。

 

何かご指摘、ご質問等ありましたらぜひお願いいたします。