Clean way to automatically set correct radius for objects

I first spawn the actor far away outside of the level tile. Then I can get the bounds (size of the actor) and use it to check for empty space to place it. If an empty space is found I move the actor to the location just found.

bool ATile::FindEmptyLocation(FVector& OutLocation, float Radius)
{
	FBox SpawnBox;
	SpawnBox.Min = { 400, 1600, -165 };
	SpawnBox.Max = { 3600, -1600, -165 };

	FVector SpawnPoint;
	const int MAX_ATTEMPTS = 100;
	int Counter = 0;

	do 
	{
		Counter++;
		OutLocation = FMath::RandPointInBox(SpawnBox) + GetActorLocation();
	} while (IsLocationBlocked(OutLocation, Radius) && Counter <= MAX_ATTEMPTS);

	return Counter <= MAX_ATTEMPTS;
}

bool ATile::IsLocationBlocked(FVector Location, float Radius)
{
	FHitResult HitResult;

	bool bHit = GetWorld()->SweepSingleByChannel(HitResult, Location, Location, FQuat::Identity, ECollisionChannel::ECC_GameTraceChannel2, FCollisionShape::MakeSphere(Radius));

	return bHit;
}

void ATile::PlaceActors(TSubclassOf<AActor> ToSpawn, int MinSpawn, int MaxSpawn)
{
	int NumberToSpawn = FMath::RandRange(MinSpawn, MaxSpawn);

	for (size_t i = 0; i < NumberToSpawn; i++)
	{
		// Spawn actor outside of the Tile
		FRotator Rotation = FRotator::ZeroRotator;
		Rotation.Yaw = FMath::RandRange(0.0f, 360.0f);
		AActor* Spawned = GetWorld()->SpawnActor<AActor>(ToSpawn, FVector(0, 5000, 0), Rotation);

		// Get Radius for Sphere sweep
		FVector Origin;
		FVector BoxExtent;
		Spawned->GetActorBounds(true, Origin, BoxExtent);

		// Find empty place and move actor there, destroy actor if no solution found in MAX_ATTEMPTS
		FVector SpawnPoint;
		if (FindEmptyLocation(SpawnPoint, BoxExtent.Size()))
		{
			Spawned->SetActorLocation(SpawnPoint);
			Spawned->AttachToActor(this, FAttachmentTransformRules(EAttachmentRule::KeepWorld, false));
		}
		else
		{
			Spawned->Destroy();
		}
	}
}

Privacy & Terms