敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応

敵が決まったルートを巡回し、プレイヤーを見つけたり音を聞くと反応するAIです。

自分で見返す用のメモ程度ですから、参考元である
Smart Enemy AI | (Part 1: Behavior Trees) | Tutorial in Unreal Engine 5 (UE5) | Youtube
のPart 1~3を視聴した方が良いです。

列挙型(Enum)

E_AISense
BP: ブループリント > 列挙型
名前: E_AISense
エニュメレーター
None
Sight
Hearing
Damage
E_AIState
BP: ブループリント > 列挙型
名前: E_AIState
エニュメレーター
Passive
Attacking
Stun
Investigating
Dead
Seeking
E_MovementSpeed
BP: ブループリント > 列挙型
名前: E_MovementSpeed
エニュメレーター
Idle
Walking
Jogging
Sprinting

パトロールルートのブループリント

BP: ブループリント クラス
親クラス: Actor
名前: BP_PatrolRoute
配置するとスプラインになるブループリントです。このルート上を敵が巡回します。
Splineの追加
コンポーネントにSplineを追加し、名前をPatrolRouteにしました。
関数: GetSplinePointAsWorldPosition
ノードを組む

【アウトプット】Get Spline Point As World Position
└Location – Vector
【変数】
PatrolIndex – Integer
└新規作成。デフォルト値は0にします。
Patrol Routeはコンポーネントに追加したSplineです。
イベントグラフ
ノードを組む

【変数】DirectionInteger
新規作成。詳細の「値の範囲」を「-1」と「1」にします。デフォルト値は0です。

ブループリントインターフェース

BP: ブループリント > ブループリントインターフェース
名前: BPI_EnemyAI
関数を作成します。
関数: GetPatrolRoute
【アウトプット】PatrolRouteBP_PatrolRoute
関数: SetMovementSpeed
【インプット】SpeedE_MovementSpeed
【アウトプット】SpeedValueFloat
関数: CombatStance

入力はありません。

関数: CombatStanceClear

入力はありません。

関数: EnemyAttack
【インプット】AttackTargetActor

ブラックボード

BP: AI > ブラックボード
名前: BB_EnemyBase
新規キーを追加します。
AttackTargetObject – BaseClass:Actor
StateEnum – EnumType:E_AIState
PointOfInterestVector

AIコントローラー

BP: ブループリント クラス > AIController
名前: AIC_EnemyBase
AIPerceptionの追加

コンポーネントにAIPerceprionを+追加。

詳細のAI パーセプション > Senses Configを+して3配列エレメントにする。
それぞれ「AI Sight config」「AI Hearing config」「AI Damage sense config」を設定。
Dominant Senseに「AISense_Sight」を設定。

「AI Sight config」「AI Hearing config」のインデックス[*] > Sense > Detection Affiliation以下のDetect *****にチェックを入れる。

AI Sight configではSight Radius(視界半径)を800、Lose Sight Radius(見失う半径)1200、PeripheralVisionHalfAngleDegrees(片目視野)を60(前方120度)、Max Ageを10にしました。Max Ageは敵がプレイヤーを見失ってから覚えているまでの秒数です。0にしてしまうと、プレイヤーが一瞬でも視界から外れた瞬間に敵が素に戻ってしまうので不自然になります。

AI Hearing configではHearing Range(聴力範囲)を800、Max Ageを3にしました。
ちなみに敵が感知する音はMake NoiseなどのNoiseノードで作成された音のみです。

AI Damade sense configではMax Ageを5にしました。
こちらもReport Damage Eventのみ敵が感知します。

継承した変数を表示

マイブループリントのギアアイコンをクリックして「継承した変数を表示」にチェックを入れます。

関数: SetStateAsPassive
ノードを組む

【変数】
Blackboard – Blackboard Component
└継承した変数の「AI」の中にあります。
StateKeyName – Name
Set Value as EnumのKey Nameから変数へ昇格。コンパイルしてデフォルト値をStateにします。これはブラックボードに追加したキーと同じ名前です。
関数: SetStateAsAttacking
ノードを組む

【インプット】Set State as Attacking
├AttackTarget – Actor
└UseLastKnownAttackTarget – Boolean
【変数】
AttackTargetKeyName – Name
Set Value as ObjectKey Nameから変数へ昇格。コンパイルしてデフォルト値をAttackTargetにします。これはブラックボードに追加したキーと同じ名前。
AttackTarget – Actor
└新規作成
【ローカル変数】
NewAttackTarget – Actor
└新規作成。
・その他の変数は作成済。
関数: SetStateAsInvestigating
ノードを組む

【インプット】Set State as Investigating
└Location – Vector
【変数】
PointOfInterestKeyName – Name
└Set Value as VectorのKey Nameから変数へ昇格。コンパイルしてデフォルト値をPointOfInterestにします。
関数: SetStateAsSeeking
ノードを組む

SetStateAsInvestigatingを複製してEnumを変更するだけです。
関数: GetCurrentState
ノードを組む

【アウトプット】Get Current State
└State – E_AIState
関数: HandleSensedSight
ノードを組む

【インプット】Handle Sensed Sight
└Actor – Actor
【変数】
KnownSeenActors – Actor  – 配列
└新規作成。
関数: HandleSensedSound
ノードを組む

【インプット】Handle Sensed Sound
└Location – Vector
関数: HandleSensedDamage
ノードを組む

【インプット】Handle Sensed Damage
└Actor – Actor
関数: CanSenseActor
ノードを組む

【インプット】Can Sense Actor
ActorActor
SenseE_AISense
【アウトプット】Can Sense Actor
└SensedBoolean
StimulusAIStimulus
└For Each LoopArray Elementからリターンノードへ。
イベントグラフ
ノードを組む

On Perception Update (AIPerception)はコンポーネントのAIPerceptionの詳細から出せます。
Run Behavior TreeのBTAssetには、この後BT_EnemyBaseを作成してから選択。

敵キャラクターのスケルトン

敵キャラクターのメッシュのスケルトンに武器を持つSocketを追加しましょう。
ここではhand_r_weaponにしました。

敵キャラクターのAnimMontage

敵キャラクターが戦闘態勢に入るモーションと戦闘態勢を解除するモーションを作ります。

ここでは武器を抜くアニメーションシーケンスを用意しました。
Withdrawing A Sword | Mixamo

まずAnimMontageを作成。これが戦闘態勢に入るモーション。
武器を手に取るタイミングにMontage Notifyを追加。名前をHoldWeaponにしました。

そしてもう1つAnimMontageを作成。
DefaultGroupe.DefaultSlotを選択して詳細 > Play Rateを-1にすると逆再生になります。これで武器を納めるモーションになります。
武器を納めたタイミングにMontage Notifyを追加。名前をDropWeaponにしました。

武器のブループリント

敵の武器を簡単に作成します。

BP: ブループリント クラス
親クラス: Actor
名前: BP_Axe
コンポーネントにStatic Meshを追加し、Axe(斧)のメッシュをセットしました。
注意点はStatic Meshのコリジョンです。敵の体のメッシュと衝突しないようにコリジョンプリセットをNoCollisionにしておきましょう。

敵キャラクターブループリント

BP: ブループリント クラス > Character
名前: BP_EnemyBase
BP_ThirdPersonCharacterを複製して名前変更するのが楽です。
コンポーネントのカメラは削除して構いません。
コンポーネントの詳細設定
BP_EnemyBaseを開き、コンポーネントのBP_EnemyBase (Self)を選択し、詳細の
コリジョン > Mesh > コリジョンプリセットのCameraの「無視する」にチェックを入れる。※これはCapsule Componentも同じようにする。
これをやっておかないとカメラが敵に接触すると画面がカクカクします。
キャラクタ移動(回転設定) > Use Controller Desired Rotationにチェックを入れる。その下のOrient Rotation to Movementのチェックは外す。

ポーン > Use Controller Rotation Yawのチェックを外す。
ポーン > Auto Possess AIをPlaced in World or Spawnedにする。
ポーン > AI Controller ClassをAIC_EnemyBaseに変更。

コンポーネントのCharacter Movementを選択し、詳細の
ナビゲーションムーブメント > Use Fixed Braking Distance for Pathsのチェックを外す。敵がパトロールルートの停止ポイントの直前で減速するのを防止します。
クラス設定
インターフェース > 実装インターフェースにBPI_EnemyAIを追加する。
イベントグラフ
ノードを組む
イベント Enemy AttackはインターフェースのEnemy Attackから呼び出します。カスタムイベントではありません。

【イベントディスパッチャー】
OnAttackEnd
【変数】

NormalAttackAnim – Anim Montage
モンタージュを再生(上)MontagePlayから変数へ昇格。
HeavyAttackAnim – Anim Montage
モンタージュを再生(下)MontagePlayから変数へ昇格。
後で子ブループリント クラスを作成しますから、Anim Montageは変数化しています。目玉アイコンを開けておくと良いでしょう。それぞれの子ブループリントから攻撃アニメーションを設定できます。
Random Integer(Max99)により、ランダムで0~99の値が決められます。100面体のサイコロを振ったのと同じ。値が69以下(70%)ならノーマルアタック、70以上(30%)ならヘビーアタック。
ノードを組む
敵の戦闘態勢と戦闘態勢の解除です。
イベント Combat Stanceイベント Combat Stance Clearはインターフェースから呼び出します。

【イベントディスパッチャー】
OnCombatStance
OnCombatStanceClear
【変数】
IsCombatStance? – Boolean
└新規作成。
・作成したAnimMontage2種とMontage Notify、スケルトンのSocket、BP_Axeをここで使います。
インターフェース: Set Movement Speed
ノードを組む

・敵の移動スピードの値はここで決めています。
子ブループリントで編集しやすくするなら、Idle~Sprintingまでを変数へ昇格させて、デフォルト値を入力。
インターフェース: Get Patrol Route

ノードを組む

【変数】
PatrolRoute – BP_PatrolRoute
└リターンノードのPatrol Routeから変数へ昇格。詳細の「インスタンス編集可能」にチェックを入れておく(目玉アイコンを開ける)。カテゴリをAIにしました。
目玉アイコンを開けておくことで、レベルに設置したBP_EnemyBaseをクリックして、その詳細からパトロールルートを選択できるようになります。

ビヘイビアツリー

BP: AI > ビヘイビアツリー
名前: BT_EnemyBase
・新規作成。
BT_EnemyBaseを作成したら、AIコントローラーのイベントグラフのRun Behavior Treeにセットしましょう。
ブラックボードとの紐づけを確認

BT_EnemyBaseを開く。
詳細のBehaviorTree > Blackboard AssetがBB_EnemyBaseになっているのを確認。なっていなければ手動で設定。

タスク: BTTask_ClearFocus
基底クラス: BTTask_BlueprintBase
名前: BTTask_CrearFocus
ノードを組む

・Focusを解除するだけのタスクです。
タスク: BTTask_CombatStance
基底クラス: BTTask_BlueprintBase
名前: BTTask_CombatStance
ノードを組む

・敵が戦闘態勢になるタスクです。
Combat StanceのターゲットはBP Enemy Baseではなく、BPI_EnemyAIです。
・As BP Enemy Baseから「assign on combatstance」でカスタムイベントまで一気に繋がります。
タスク: BTTask_CombatStanceClear
基底クラス: BTTask_BlueprintBase
名前: BTTask_CombatStanceClear
ノードを組む

・敵の戦闘態勢を解除するタスクです。
Combat Stance ClearのターゲットはBP Enemy Baseではなく、BPI_EnemyAIです。
タスク: BTTask_DefaultAttack
基底クラス: BTTask_BlueprintBase
名前: BTTask_DefaultAttack
ノードを組む

【変数】
AttackTargetKey – Blackboard Key Selector
└新規作成。目玉アイコンを開ける。
・イベントディスパッチャーのOnAttackEndを使うことにより、AnimMontageが再生し終わってからFinish Executeに繋げられます。As BP Enemy Baseから「assign on attackend」でカスタムイベントまで一気に繋がります。
タスク: BTTask_FocusTarget
基底クラス: BTTask_BlueprintBase
名前: BTTask_FocusTarget
ノードを組む

【変数】
AttackTargetkey – Blackboard Key Selector
└新規作成。目玉アイコンを開けておきます。詳細のカテゴリをKeysにしておきます。エディタが日本語の場合、Keysと入力するとキーと翻訳されて表示されます。
・現時点でここまで複雑に組む必要はありませんが、今後の拡張に合わせてちょっと複雑になっています。
タスク: BTTask_MoveAlongPatrolRoute
基底クラス: BTTask_BlueprintBase
名前: BTTask_MoveAlongPatrolRoute
ノードを組む

AI Move ToRadiusの値が小さいと目的地に到達したと認識されにくくなり、数秒間立ち止まる場合があります。そういう場合はRadiusを50.0くらいにしてみましょう。
タスク: BTTask_SetMovementSpeed
基底クラス: BTTask_BlueprintBase
名前: BTTask_SetMovementSpeed
ノードを組む

【変数】
Speed – E_MovementSpeed
Set Movement SpeedSpeedから変数へ昇格。目玉アイコンを開けておきます。
タスク: BTTask_SetStateAsPassive
基底クラス: BTTask_BlueprintBase
名前: BTTask_SetStateAsPassive
ノードを組む
デコレーター: BTDecorator_HasPatrolRoute
基底クラス: BTDecorator_BlueprintBase
名前: BTDecorator_HasPatrolRoute
ノードを組む
デコレーター: BTDecorator_IsCombatStance
基底クラス: BTDecorator_BlueprintBase
名前: BTDecorator_IsCombatStance
ノードを組む

・敵が戦闘態勢ならTrueを返すデコレーター。
ビヘイビアツリーを組む

Blackboard Based Conditionは右クリックしてデコレーターを追加 > Blackboardで追加します。
左のツリー
・CombatStateBlackboard Based Condition
UE5.2.1だとIs Equal Toが表示されないバグがあるようです。とりあえずGreater Than Or Equal(大きいか等しいか)でも機能するかと思います。

BTTask_FocusTarget
Attack Target KeyをAttackTargetにする。
BTD_IsCombatStance
Inverse Conditionにチェックを入れる。反転させるという意味です。IsCombatStanceがFalseの場合、このノードが成功となり、BTTask_CombatStanceに繋がる。
BTTask_SetMovementSpeed
SpeedをSprinteingにする。
MoveToTarget

BTTask_FocusTarget
Attack Target KeyをAttackTargetにする。
BTTask_DefaultAttack
Attack Target KeyをAttackTargetにする。
中央のツリー
InvestigatingStateBlackboard Based Condition

BTTask_SetMovementSpeed
SpeedをJoggingにする。
Move To
右のツリー
PassiveStateBlackboard Based Condition

BTTask_SetMovementSpeed
SpeedをWalkingにする。

ナビメッシュ バウンズ ボリュームを配置する

レベルを開いた状態で、上メニューの■+をクリックしてボリューム > ナビメッシュ バウンズ ボリュームを選択。

このNavMeshBoundsVolume内が敵が移動できる範囲です。
位置とスケールを調整して、レベル全体を包み込むように配置しましょう。視点をパースペクティブではなく、左右や上に変えてやるとわかりやすいです。
Pキーを押して緑色になっていれば、そこは敵が移動できる範囲です。

パトロールルートのブループリントの配置

BP_PatrolRouteをレベルに配置します。
スプラインになっており、移動モードにして点のところを移動させて伸ばせます。
線で右クリックしてスプラインポイントの追加も可能。
このスプライン上を敵が巡回するようになります。

敵キャラクターのブループリントを配置

BP_EnemyBaseをレベルに配置します。
レベルに配置したBP_EnemyBaseをクリックして選択状態にし、詳細を見る。
AI > Patrol Routeのところでスポイトアイコンをクリックし、レベル上のBP_PatrolRouteをクリックすると設定できます。

BP_PatrolRouteとBP_EnemyBaseの距離が離れていても、自動でBP_PatrolRouteに向かって巡回します。

参考元

Smart Enemy AI | (Part 1: Behavior Trees) | Tutorial in Unreal Engine 5 (UE5) | Youtube
Smart Enemy AI | (Part 2: Patrolling & States) | Tutorial in Unreal Engine 5 (UE5) | Youtube
Smart Enemy AI | (Part 3: Perception) | Tutorial in Unreal Engine 5 (UE5) | Youtube

実際にゲームで使えるAI

参考元であるAli Elzoheiry氏のチュートリアルが非常に良かったです。AIのチュートリアルは多いですが、実際にゲームで使うとなると細かいところに問題があるものがほとんどです。Ali Elzoheiry氏のチュートリアルは細かい部分も修正していてクオリティが高いと感じました。その分、動画も長時間になりますけど、これぐらい力の入ったものでないと実際のゲームで使うのは難しいというところでもあります。

自分でやり直す時のためにブログにまとめていますが、メモ程度のものですから参考にはなりにくいでしょう。Ali Elzoheiry氏のチュートリアルを見ることをオススメします。

コメント

  1. […] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]

  2. […] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]

  3. […] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]

  4. […] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]

  5. […] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]

  6. […] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]

  7. […] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]

  8. […] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]

タイトルとURLをコピーしました