MiddleКодЧастоЕщё не отвечали
Как реализовать конус обзора врага с помощью скалярного произведения?
Верните, видит ли враг цель: цель должна быть внутри конуса обзора врага (полуугол VisionHalfAngle в градусах) и не перекрыта геометрией.
Ограничения:
- Нормализуйте и forward, и направление к цели.
- Сравнивайте скалярное произведение с
cos(HalfAngle), а не с сырым углом. - После прохождения по углу подтвердите прямую видимость трейсом по
ECC_Visibility.
bool AEnemy::CanSeeTarget(const AActor* Target) const
{
// ваш код здесь
}
Допишите реализацию.
Нормализуйте forward врага и направление к цели, возьмите их скалярное произведение и сравните с cos(HalfAngle). Если Dot >= cos(HalfAngle), цель внутри конуса; затем добавьте line trace для проверки прямой видимости.
- ✗Сравнивать скалярное произведение с углом в градусах вместо его косинуса
- ✗Забыть нормализовать оба вектора, из-за чего скалярное произведение не чистый косинус
- ✗Пропустить line trace, из-за чего враг «видит» цель сквозь стену
- →Как добавить максимальную дистанцию обзора к этой проверке?
- →Почему после проверки конуса нужен трейс на прямую видимость?
Конус обзора через скалярное произведение
bool AEnemy::CanSeeTarget(const AActor* Target) const
{
if (!Target)
return false;
const FVector EyeLocation = GetActorLocation();
const FVector Forward = GetActorForwardVector(); // уже нормализован
const FVector ToTarget =
(Target->GetActorLocation() - EyeLocation).GetSafeNormal();
// Скалярное произведение двух единичных векторов = косинус угла
const float Dot = FVector::DotProduct(Forward, ToTarget);
// Полуугол конуса в градусах → косинус для сравнения
const float HalfAngleRad = FMath::DegreesToRadians(VisionHalfAngle);
const float CosHalfAngle = FMath::Cos(HalfAngleRad);
// Чем уже конус, тем БОЛЬШЕ требуемый косинус
if (Dot < CosHalfAngle)
return false; // цель вне угла обзора
// Внутри конуса — теперь проверяем, не закрыта ли цель стеной
FHitResult Hit;
FCollisionQueryParams Params;
Params.AddIgnoredActor(this);
Params.AddIgnoredActor(Target);
const bool bBlocked = GetWorld()->LineTraceSingleByChannel(
Hit, EyeLocation, Target->GetActorLocation(), ECC_Visibility, Params);
return !bBlocked; // видим, если ничего не перекрыло луч
}
Ключевые моменты:
- Оба вектора нормализованы, поэтому
Dot— это именно косинус угла. - Сравниваем с
cos(HalfAngle), а не с самим углом: для конуса 90° порог равенcos(45°). - Узкий конус → косинус ближе к 1 → строже проверка.
- Скалярное произведение не учитывает препятствия, поэтому нужен ещё line trace.