// Copyright Epic Games, Inc. All Rights Reserved. #include "AIHelpers.h" #include "GameFramework/Actor.h" namespace FAISystem { FVector FindClosestLocation(const FVector& Origin, const TArray& Locations) { FVector BestLocation = FAISystem::InvalidLocation; FVector::FReal BestDistanceSq = TNumericLimits::Max(); for (const FVector& Candidate : Locations) { const FVector::FReal CurrentDistanceSq = FVector::DistSquared(Origin, Candidate); if (CurrentDistanceSq < BestDistanceSq) { BestDistanceSq = CurrentDistanceSq; BestLocation = Candidate; } } return BestLocation; } //----------------------------------------------------------------------// // CheckIsTargetInSightCone // F // ***** // * * // * * // * * // * * // * * // \ / // \ / // \ / // \ X / // \ / // \ *** / // \ * N * / // \ * * / // N N // // // // // // // B // // X = StartLocation // B = Backward offset // N = Near Clipping Radius (from the StartLocation adjusted by Backward offset) // F = Far Clipping Radius (from the StartLocation adjusted by Backward offset) //----------------------------------------------------------------------// bool CheckIsTargetInSightCone(const FVector& StartLocation, const FVector& ConeDirectionNormal, float PeripheralVisionAngleCos, float ConeDirectionBackwardOffset, float NearClippingRadiusSq, float const FarClippingRadiusSq, const FVector& TargetLocation) { const FVector BaseLocation = FMath::IsNearlyZero(ConeDirectionBackwardOffset) ? StartLocation : StartLocation - ConeDirectionNormal * ConeDirectionBackwardOffset; const FVector ActorToTarget = TargetLocation - BaseLocation; const FVector::FReal DistToTargetSq = ActorToTarget.SizeSquared(); if (DistToTargetSq <= FarClippingRadiusSq && DistToTargetSq >= NearClippingRadiusSq) { // Will return true if squared distance to Target is smaller than SMALL_NUMBER if (DistToTargetSq < SMALL_NUMBER) { return true; } // Calculate the normal here instead of calling GetUnsafeNormal as we already have the DistToTargetSq (optim) const FVector DirectionToTargetNormal = ActorToTarget * FMath::InvSqrt(DistToTargetSq); return FVector::DotProduct(DirectionToTargetNormal, ConeDirectionNormal) > PeripheralVisionAngleCos; } return false; } } namespace UE::AI { TOptional GetYawFromVector(const FVector& Vector) { const FVector2D Vector2D(Vector); const FVector::FReal SizeSquared = Vector2D.SizeSquared(); if (SizeSquared <= SMALL_NUMBER) { return TOptional(); } const FVector2D ForwardVector(1., 0.); const FVector2D NormVector2D = Vector2D * FMath::InvSqrt(SizeSquared); const FVector::FReal DotVal = ForwardVector | NormVector2D; const FVector::FReal ClampedDot = FMath::Clamp(DotVal, -1., 1.); const FVector::FReal Direction = ForwardVector ^ NormVector2D; const FVector::FReal Sign = Direction < 0. ? -1. : 1.; const FVector::FReal Yaw = Sign * FMath::Acos(ClampedDot); return static_cast(Yaw); } TOptional GetYawFromRotator(const FRotator& Rotator) { PRAGMA_DISABLE_DEPRECATION_WARNINGS return GetYawFromVector(Rotator.Vector()); PRAGMA_ENABLE_DEPRECATION_WARNINGS } TOptional GetYawFromQuaternion(const FQuat& Quaternion) { PRAGMA_DISABLE_DEPRECATION_WARNINGS return GetYawFromVector(Quaternion.Vector()); PRAGMA_ENABLE_DEPRECATION_WARNINGS } void GetActorClassDefaultComponents(const TSubclassOf& ActorClass, TArray& OutComponents, const TSubclassOf& InComponentClass) { OutComponents.Reset(); AActor::ForEachComponentOfActorClassDefault(ActorClass, InComponentClass, [&OutComponents](const UActorComponent* TemplateComponent) { OutComponents.Add(const_cast(TemplateComponent)); return true; }); } } // UE::AI