视觉感知
2023年10月26日 2024年1月11日
说明
AI Perception Component
允许NPC游戏角色感知给定范围内的世界中的其他Actor, 通过视觉和听觉感知敌人, 对伤害作出反应
本节为NPC添加视觉感知, 寻找与之最近的敌人, 使NPC面向该敌人
创建C++类
- | |
---|---|
基类 | AIPerceptionComponent |
Components | |
Public | |
STUAIPerceptionComponent |
为AIController添加感知组件
- 添加构造函数
ShootThemUp: AI/STUAIController.h
public
1ASTUAIController();
- 添加组件
ShootThemUp: AI/STUAIController.h
protected
1class USTUAIPerceptionComponent; 2 3UPROPERTY(VisibleAnywhere, BlueprintReadWrite) 4USTUAIPerceptionComponent *STUAIPerceptionComponent;
- 初始化组件
ShootThemUp: AI/STUAIController.cpp
1#include "Components/STUAIPerceptionComponent.h" 2 3ASTUAIController::ASTUAIController() 4{ 5 STUAIPerceptionComponent = CreateDefaultSubobject<USTUAIPerceptionComponent>("STUPerceptionComponent"); 6 SetPerceptionComponent(*STUAIPerceptionComponent); 7}
设置感知组件
BP_STUAIController > STUAIPerceptionComponent > Details
AI Perception > Senses Config
: 对游戏角色的感官进行配置, 可以感知的有伤害, 听觉, 视觉等
添加AI视觉
选择 AI Sight config
设置捕捉可视半径为1000 Sense > Sight Radius
设置监控释放半径为1500 Sense > Lose Sight Radius
设置可视半角为60 Sense > PeripheralVisionHalfAngleDegrees
设置调试颜色为蓝色 Sense > Debug Color
Sense > Detection by Affiliation
, 勾选 Detect Enemies
, Detect Neutrals
, Detect Friendlies
; 当前没有分队别
设置MaxAge为1: Actor从视野中消失多久后不再保存相关信息
设置感官优先级
可以将 Sense > DominantSense
设置为None或 AISense_Sight
查看
-
关闭行为树
BP_STUCharactr
按下
Option
, 左键点击箭头UE4.27: 移除Root到Sequence的箭头即可
UE5.1: 必须移除Sequence到子任务的箭头
-
在新窗口运行游戏
-
按下
'
打开AI调试信息; 在小写键盘按下数字4, 使能Perception
信息 -
绿色圆柱体表示捕捉可视边界; 粉色圆柱体表示监控释放边界
-
进入到捕捉可视区域, 游戏角色所处位置出现蓝色调试球体, 表明游戏角色被NPC捕捉到; 绿色可视角
-
蓝色调试球体的活动范围由可视角和监控释放边界组成
进入到捕捉可视区域, 被NPC捕捉, 之后只要在活动范围内, 其移动就会被NPC捕捉到
活动范围内, 位于障碍物之后, MaxAge时间后, 蓝色调试球消失
移动到活动范围外, MaxAge时间后, 蓝色调试球消失 -
在场景中添加另一个NPC
场景中有多个游戏角色: NPC靠近和他距离最近的游戏角色
获取组件
GetComponentByClass也是AActor的成员函数: 修改传参类型
public
ShootThemUp: STUUtils.h
1// #include "GameFramework/Pawn.h" 2#include "GameFramework/Actor.h" 3 4static T *GetSTUPlayerComponent(AActor *PlayerPawn) 5{ 6 // ... 7}
AActor提供成员函数FindComponentByClass
返回最近的Actor
ShootThemUp: Components/STUAIPerceptionComponent.h
public
1AActor *GetClosestEnemy() const;
获取所有捕捉的Actor
1TArray<AActor*> PercieveActors; 2GetCurrentlyPerceivedActors(UAISense_Sight::StaticClass(), PercieveActors); 3if (!PercieveActors.Num()) return nullptr;
计算最近Actor
1const auto Controller = Cast<AAIController>(GetOwner()); 2if (!Controller) return nullptr; 3 4const auto Pawn = Controller->GetPawn(); 5if (!Pawn) return nullptr; 6const auto LocalPos = Pawn->GetActorLocation(); 7 8float BestDistance = MAX_FLT; 9AActor *BestPawn = nullptr; 10for (const auto PercieveActor: PercieveActors) 11{ 12 const auto HealthComponent = STUUtils::GetSTUPlayerComponent<USTUHealthComponent>(PercieveActor); 13 if (HealthComponent && !HealthComponent->IsDead()) // TODO: check if enemies or not 14 { 15 const auto CurrentDistance = (PercieveActor->GetActorLocation() - LocalPos).Size(); 16 17 if (CurrentDistance < BestDistance) 18 { 19 BestDistance = CurrentDistance; 20 BestPawn = PercieveActor; 21 } 22 } 23}
完整实现
ShootThemUp: Components/STUAIPerceptionComponent.cpp
1#include "AIController.h" 2#include "STUUtils.h" 3#include "Components/STUHealthComponent.h" 4#include "Perception/AISense_Sight.h" 5 6AActor *USTUAIPerceptionComponent::GetClosestEnemy() const 7{ 8 TArray<AActor*> PercieveActors; 9 GetCurrentlyPerceivedActors(UAISense_Sight::StaticClass(), PercieveActors); 10 if (!PercieveActors.Num()) return nullptr; 11 12 const auto Controller = Cast<AAIController>(GetOwner()); 13 if (!Controller) return nullptr; 14 15 const auto Pawn = Controller->GetPawn(); 16 if (!Pawn) return nullptr; 17 const auto LocalPos = Pawn->GetActorLocation(); 18 19 float BestDistance = MAX_FLT; 20 AActor *BestPawn = nullptr; 21 for (const auto PercieveActor: PercieveActors) 22 { 23 const auto HealthComponent = STUUtils::GetSTUPlayerComponent<USTUHealthComponent>(PercieveActor); 24 if (HealthComponent && !HealthComponent->IsDead()) // TODO: check if enemies or not 25 { 26 const auto CurrentDistance = (PercieveActor->GetActorLocation() - LocalPos).Size(); 27 if (CurrentDistance < BestDistance) 28 { 29 BestDistance = CurrentDistance; 30 BestPawn = PercieveActor; 31 } 32 } 33 } 34 return BestPawn; 35}
添加Tick函数: 每秒计算一次最近Actor, 旋转NPC朝向被捕捉对象
暂时不检查STUAIPerceptionComponent是否有效
ShootThemUp: AI/STUAIController.h
protected
1virtual void Tick(float DeltaTime) override;
ShootThemUp: AI/STUAIController.cpp
1void ASTUAIController::Tick(float DeltaTime) 2{ 3 Super::Tick(DeltaTime); 4 const auto AimActor = STUAIPerceptionComponent->GetClosestEnemy(); 5 SetFocus(AimActor); 6}
SetFocus函数
设置控制器旋转, 使之前进向量朝向给定Actor
查看
打开AI调试信息, 使能Perception
在监控释放半径限定的圆内, 除非躲在障碍物之后, 不会脱离NPC捕捉