Unreal Engine 4におけるAI行動制御の実装手法

Unreal Engine 4におけるAIシステムの構成

UE4でのAIは主に「ビヘイビアツリー(Behavior Tree)」と「ブラックボード(Blackboard)」を用いて構築される。AIの意思決定ロジックはAIControllerによって管理され、その結果がブラックボードのキーに書き込まれる。ビヘイビアツリーはこの値を参照し、ノード構造に基づいて適切なアクションを実行する。

ビヘイビアツリーの基本ノード構造

  • Selector(選択ノード): 左から順に子ノードを評価し、最初に成功したノードで停止する。失敗した場合は次のノードへ進む。条件分岐的な振る舞いに使用される。
  • Sequence(順次ノード): 子ノードを左から順に実行し、すべて成功しなければ全体として失敗となる。途中で一つでも失敗すれば以降のノードは実行されない。

タスクノード

タスクはAIが実行する具体的な行動であり、UE4にはMoveToやWaitなどの標準タスクが用意されている。カスタムタスクを作成する場合、C++ではUBTTaskNodeを継承し、ExecuteTaskメソッドをオーバーライドすることで実装できる。パラメータはブラックボード経由で渡すことが一般的である。

デコレータ(Decorator)

デコレータはノードの実行条件を判定する役割を持つ。例えば、PerformConditionCheckAIまたはCalculateRawConditionValueをオーバーライドすることで、特定の条件(例:プレイヤーが視界内か)に基づいてノードの実行可否を制御できる。条件がfalseになると、対応するタスクはスキップされる。

AI感知システム(AIPerception)

AIに「視覚」「聴覚」などの知覚能力を持たせるために、AIControllerにUAIPerceptionComponentを追加する。代表的なモジュールにSightがあり、視認距離や角度、障害物の有無などを設定可能である。

感知情報の取得と処理

感知されたアクターの情報を取得するには、以下のように記述する。

const FAIStimulus* Stimulus = &AIPerception->GetActorStimulus(TargetActor);
if (Stimulus->WasSuccessfullySensed())
{
    Blackboard->SetValueAsObject(FName("TargetActor"), TargetActor);
}

これにより、ブラックボードの値が更新され、ビヘイビアツリー内で敵の追跡や回避などの行動を切り替えられる。

C++によるカスタムタスクの実装

アニメーション再生中にタスクを進行中状態に保ちたい場合、非同期処理が必要になる。特に攻撃アニメーション(Montage)の終了を待つケースでは、以下のパターンが有効である。

遅延完了タスクの実装

まずExecuteTaskでEBTNodeResult::InProgressを返し、アニメーション終了時にFinishLatentTaskを呼び出して完了を通知する。

// タスククラス内
FSimpleMulticastDelegate OnFinish;

virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) override
{
    AXAI_Character* Character = Cast<AXAI_Character>(OwnerComp.GetAIOwner()->GetPawn());
    if (Character)
    {
        Character->OnAttackMontageEnded.AddDynamic(this, &UXBTTask_Attack::OnAnimationFinished);
        Character->PlayAttackMontage();
        return EBTNodeResult::InProgress;
    }
    return EBTNodeResult::Failed;
}

void OnAnimationFinished()
{
    UBehaviorTreeComponent* BTComp = Cast<UBehaviorTreeComponent>(GetOuter());
    FinishLatentTask(*BTComp, EBTNodeResult::Succeeded);
}

アニメーション終了通知の実装

キャラクター側では、アニメーションインスタンスのOnMontageEndedデリゲートを使用して終了を検出する。

void AXAI_Character::PlayAttackMontage()
{
    UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
    if (AnimInstance && AttackMontage)
    {
        AnimInstance->OnMontageEnded.Clear();
        AnimInstance->OnMontageEnded.AddDynamic(this, &AXAI_Character::OnMontageComplete);
        AnimInstance->Montage_Play(AttackMontage);
    }
}

void AXAI_Character::OnMontageComplete(UAnimMontage* Montage, bool bInterrupted)
{
    if (Montage == AttackMontage)
    {
        OnAttackMontageEnded.Broadcast();
    }
}

環境クエリシステム(EQS)の活用

EQSはAI周囲の環境から条件に合致する位置を動的に抽出する機能である。例えば、「敵の周囲5m以内で障害物のない移動可能な位置」などを取得できる。

C++でのコンテキスト定義

カスタムコンテキストクラスを生成し、ProvideContextをオーバーライドして基準点を設定する。

void UEQS_Context_EnemyCenter::ProvideContext(FEnvQueryInstance& QueryInstance, FEnvQueryContextData& ContextData) const
{
    UObject* Querier = QueryInstance.Owner.Get();
    AAIController* AIController = Cast<AAIController>(Querier);
    if (AIController)
    {
        AXAI_Character* Pawn = Cast<AXAI_Character>(AIController->GetPawn());
        AActor* Target = Pawn ? Pawn->GetCurrentTarget() : nullptr;
        UEnvQueryItemType_Actor::SetContextHelper(ContextData, Target);
    }
}

UEエディタ上でEQSクエリを作成し、サンプリング範囲やフィルタ(例:Distance Test)を設定することで、円環状のポイント群を生成できる。これにより、AIが敵の周囲を自然に旋回するような行動が実現できる。

サービスタスク(Service)

サービスはビヘイビアツリーの各ノードに周期的に実行される補助処理を提供する。例えば、一定間隔で敵の存在を確認したり、ステータスを監視したりする用途に使う。Tick間隔を設定でき、条件変化の検出に適している。

タグ: Unreal Engine 4 AI Behavior Tree blackboard EQS

10月17日 02:34 投稿