Как заставить ИИ преследовать игрока в Unreal Engine?
Управляемый ИИ враг должен непрерывно преследовать игрока, обходя препятствия и перестраивая путь по мере движения игрока. Сделайте это «по-Behavior-Tree-ски»: система perception кладёт игрока в ключ Blackboard, а задача MoveTo ведёт навигацию к тому, на что этот ключ сейчас ссылается.
Требования:
позицию — MoveTo должен читать текущую локацию игрока каждый тик.
каждый кадр.
- Храните живую ссылку на actor игрока (
Object-ключ), а не скопированную - Стройте путь по NavMesh; не телепортируйте и не задавайте локацию напрямую
- Ветка погони должна корректно останавливаться, как только ключ очищен (игрок потерян).
Допишите callback perception на контроллере ИИ, который записывает цель:
void AEnemyAIController::OnSeen(AActor* Actor, FAIStimulus Stimulus)
{
// ваш код здесь: запишите воспринятого игрока в ключ Blackboard
// "TargetActor" как живую Object-ссылку
}
Допишите реализацию.
Сохраните игрока в Object-ключ Blackboard (через perception), затем Sequence в Behavior Tree запускает задачу MoveTo с целью на этот ключ. MoveTo каждый тик строит путь по NavMesh, а Decorator прерывает ветку, когда ключ очищается.
- ✗Телепортировать через
SetActorLocationвместо движения черезMoveTo - ✗Кэшировать позицию игрока один раз вместо чтения живого ключа
- ✗Забыть NavMesh, из-за чего
MoveToмолча не двигает pawn
- →Как
AcceptanceRadiusуMoveToвлияет на момент успеха задачи погони? - →Как заставить ИИ предсказывать и перехватывать движение игрока?
Идея
Преследование = «двигаться к ключу Blackboard, в котором лежит игрок». Perception кладёт игрока в ключ TargetActor, а MoveTo каждый тик перестраивает путь по NavMesh.
Шаг 1. Контроллер кладёт цель в Blackboard
// EnemyAIController.cpp
void AEnemyAIController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
RunBehaviorTree(ChaseTree);
// подписка на восприятие
PerceptionComponent->OnTargetPerceptionUpdated.AddDynamic(
this, &AEnemyAIController::OnSeen);
}
void AEnemyAIController::OnSeen(AActor* Actor, FAIStimulus Stimulus)
{
if (Stimulus.WasSuccessfullySensed() && Actor->IsA(APlayerCharacter::StaticClass()))
{
// живой указатель на игрока — НЕ копия позиции
GetBlackboardComponent()->SetValueAsObject(TEXT("TargetActor"), Actor);
}
}
Шаг 2. Behavior Tree
Selector
├─ Sequence [Decorator: Blackboard "TargetActor" IS Set]
│ └─ Task: MoveTo (Blackboard Key = TargetActor, AcceptanceRadius = 100)
└─ Task: BTTask_Patrol // fallback, когда цели нет
MoveTo по умолчанию перестраивает путь, пока цель движется. Decorator с Observer Aborts = Self мгновенно прерывает ветку, когда TargetActor очищается.
Почему ключ Object, а не Vector
Ключ Object хранит ссылку на actor, поэтому MoveTo читает текущую позицию игрока каждый тик. Ключ Vector заморозил бы позицию на момент записи.