敵が決まったルートを巡回し、プレイヤーを見つけたり音を聞くと反応するAIです。
自分で見返す用のメモ程度ですから、参考元である
Smart Enemy AI | (Part 1: Behavior Trees) | Tutorial in Unreal Engine 5 (UE5) | Youtube
のPart 1~3を視聴した方が良いです。
列挙型(Enum)
E_AISense
名前: E_AISense
None
Sight
Hearing
Damage
E_AIState
名前: E_AIState
Passive
Attacking
Stun
Investigating
Dead
Seeking
E_MovementSpeed
名前: E_MovementSpeed
Idle
Walking
Jogging
Sprinting
パトロールルートのブループリント
親クラス: Actor
名前: BP_PatrolRoute
配置するとスプラインになるブループリントです。このルート上を敵が巡回します。
Splineの追加
関数: GetSplinePointAsWorldPosition
【アウトプット】Get Spline Point As World Position
└Location – Vector
【変数】
PatrolIndex – Integer
└新規作成。デフォルト値は0にします。
・Patrol Routeはコンポーネントに追加したSplineです。
イベントグラフ
ブループリントインターフェース
名前: BPI_EnemyAI
関数: GetPatrolRoute
関数: SetMovementSpeed
【アウトプット】SpeedValue – Float
関数: CombatStance
入力はありません。
関数: CombatStanceClear
入力はありません。
関数: EnemyAttack
ブラックボード
名前: BB_EnemyBase
AttackTarget – Object – BaseClass:Actor
State – Enum – EnumType:E_AIState
PointOfInterest – Vector
AIコントローラー
名前: 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 ObjectのKey Nameから変数へ昇格。コンパイルしてデフォルト値をAttackTargetにします。これはブラックボードに追加したキーと同じ名前。
AttackTarget – Actor
└新規作成
【ローカル変数】
NewAttackTarget – Actor
└新規作成。
・その他の変数は作成済。
関数: SetStateAsInvestigating
【インプット】Set State as Investigating
└Location – Vector
【変数】
PointOfInterestKeyName – Name
└Set Value as VectorのKey Nameから変数へ昇格。コンパイルしてデフォルト値をPointOfInterestにします。
関数: SetStateAsSeeking
関数: HandleSensedSight
関数: HandleSensedSound
関数: HandleSensedDamage
関数: CanSenseActor
【インプット】Can Sense Actor
├Actor – Actor
└Sense – E_AISense
【アウトプット】Can Sense Actor
└Sensed – Boolean
Stimulus – AIStimulus
└For Each LoopのArray 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にしました。
武器のブループリント
敵の武器を簡単に作成します。
親クラス: Actor
名前: BP_Axe
敵キャラクターブループリント
名前: BP_EnemyBase
コンポーネントのカメラは削除して構いません。
コンポーネントの詳細設定
コリジョン > Mesh > コリジョンプリセットのCameraの「無視する」にチェックを入れる。※これはCapsule Componentも同じようにする。
これをやっておかないとカメラが敵に接触すると画面がカクカクします。
ポーン > 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のチェックを外す。敵がパトロールルートの停止ポイントの直前で減速するのを防止します。
クラス設定
イベントグラフ
イベント 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
インターフェース: Get Patrol Route
ビヘイビアツリー
名前: BT_EnemyBase
・新規作成。
ブラックボードとの紐づけを確認
BT_EnemyBaseを開く。
詳細のBehaviorTree > Blackboard AssetがBB_EnemyBaseになっているのを確認。なっていなければ手動で設定。
タスク: BTTask_ClearFocus
名前: BTTask_CrearFocus
タスク: BTTask_CombatStance
名前: BTTask_CombatStance
・敵が戦闘態勢になるタスクです。
・Combat StanceのターゲットはBP Enemy Baseではなく、BPI_EnemyAIです。
・As BP Enemy Baseから「assign on combatstance」でカスタムイベントまで一気に繋がります。
タスク: BTTask_CombatStanceClear
名前: BTTask_CombatStanceClear
タスク: BTTask_DefaultAttack
名前: BTTask_DefaultAttack
【変数】
AttackTargetKey – Blackboard Key Selector
└新規作成。目玉アイコンを開ける。
・イベントディスパッチャーのOnAttackEndを使うことにより、AnimMontageが再生し終わってからFinish Executeに繋げられます。As BP Enemy Baseから「assign on attackend」でカスタムイベントまで一気に繋がります。
タスク: BTTask_FocusTarget
名前: BTTask_FocusTarget
タスク: BTTask_MoveAlongPatrolRoute
名前: BTTask_MoveAlongPatrolRoute
タスク: BTTask_SetMovementSpeed
名前: BTTask_SetMovementSpeed
タスク: BTTask_SetStateAsPassive
名前: BTTask_SetStateAsPassive
デコレーター: BTDecorator_HasPatrolRoute
名前: BTDecorator_HasPatrolRoute
デコレーター: BTDecorator_IsCombatStance
名前: BTDecorator_IsCombatStance
ビヘイビアツリーを組む
左のツリー
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にする。
中央のツリー
右のツリー
ナビメッシュ バウンズ ボリュームを配置する
レベルを開いた状態で、上メニューの■+をクリックしてボリューム > ナビメッシュ バウンズ ボリュームを選択。
この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氏のチュートリアルを見ることをオススメします。
コメント
[…] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]
[…] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]
[…] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]
[…] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]
[…] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]
[…] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]
[…] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]
[…] 敵AI:敵がルートを巡回しプレイヤーや音に気付くと反応 敵AI 2:敵が間合いを取りながら攻撃してくる 敵AI […]