in Ambit/Source/Ambit/Utils/AmbitWorldHelpers.cpp [156:231]
TArray<FTransform> AmbitWorldHelpers::GenerateRandomLocationsFromBox(UBoxComponent* Box,
const TArray<AActor*>& ActorsToHit,
int32 RandomSeed, bool bSnapToSurfaceBelow,
float DensityMin, float DensityMax,
float RotationMin, float RotationMax)
{
TArray<FTransform> Transforms;
if (!IsValid(Box))
{
UE_LOG(LogAmbit, Warning, TEXT("Invalid box component."));
return Transforms;
}
if (DensityMin > DensityMax)
{
UE_LOG(LogAmbit, Warning, TEXT("DensityMin is greater than DensityMax. No actors spawned."));
return Transforms;
}
if (RotationMin > RotationMax)
{
UE_LOG(LogAmbit, Warning, TEXT("RotationMin is greater than RotationMax. No actors spawned."));
return Transforms;
}
FRandomStream Random;
Random.Initialize(RandomSeed);
FTransform BoxTransform = Box->GetComponentTransform();
FBox Bounds = Box->Bounds.GetBox();
float BoxYaw = BoxTransform.Rotator().Yaw;
float BoxYawMod = UKismetMathLibrary::GenericPercent_FloatFloat(BoxYaw, 90.f);
if (!FMath::IsNearlyEqual(BoxYawMod, 0.f))
{
// If BoxComponent is a rotated box, create a rectangle
// with the same area as a temporary bounding box
Bounds = FBox(FVector(-Box->GetScaledBoxExtent().X, -Box->GetScaledBoxExtent().Y, 0.0),
FVector(Box->GetScaledBoxExtent().X, Box->GetScaledBoxExtent().Y, 0.0));
}
// Calculate the surface area of the bounding box to determine how many items to spawn.
const FVector SizeMeters = Bounds.GetSize() / 100.f;
const float AreaMeters = SizeMeters.X * SizeMeters.Y;
int SpawnCount = AreaMeters * Random.FRandRange(DensityMin, DensityMax);
FVector Location(0, 0, Bounds.Max.Z);
while (SpawnCount > 0)
{
Location.X = Random.FRandRange(Bounds.Min.X, Bounds.Max.X);
Location.Y = Random.FRandRange(Bounds.Min.Y, Bounds.Max.Y);
FVector NewLocation = Location;
if (!FMath::IsNearlyEqual(BoxYawMod, 0.f))
{
// If BoxComponent is a rotated box, iterate through transforms
// and transform each location to match the rotated box area
NewLocation = BoxTransform.TransformPosition(Location);
}
FTransform Transform(FRotator(0), NewLocation);
if (CheckAndSnapToSurface(Transform, ActorsToHit, bSnapToSurfaceBelow))
{
FRotator Rotation(0, Random.FRandRange(RotationMin, RotationMax), 0);
// Combine "local" Yaw rotation generated from user inputted restrictions
// with the adjusted rotation axis
Transform.SetRotation(Transform.GetRotation() * Rotation.Quaternion());
Transforms.Push(Transform);
}
// No matter hit or not, reduce spawn count
SpawnCount--;
}
return Transforms;
}