I’ve been messing around with means of randomly spawning an object on Navmesh. In my use case I don’t want to spawn something as close as possible to a certain spot on a navmesh. Rather I want to spawn something within a predefined radius.
This is what I could come up with. I was worried it was going to be extremely inefficient but spawning 5 objects a random distance of up to 30 meters away took less than 0.0008 seconds (13th gen i9 laptop running in Quiet Mode). A 13th gen i9 is fast but I think even the target device was 10 times slower it should work fine.
Does this pass the sniff test?
void RandomSpawn()
{
for (int i = 0; i < MAX_ATTEMPTS_TO_SPAWN_SINGLE_OBJECT; i++)
{
Vector2 randomCirclePoint = Random.insideUnitCircle * scatterDistance;
Vector3 randomPoint = transform.position +
new Vector3(randomCirclePoint.x, 0, randomCirclePoint.y);
NavMeshHit hit;
if (NavMesh.SamplePosition(randomPoint, out hit, navMeshSamplingRange, NavMesh.AllAreas))
{
if (CanMoveTo(hit.position)) {
dynamicSavingEntity.CreateDynamicEntity(config, hit.position, new Vector3(0, 0, 0));
return;
}
else
{
continue;
}
}
}
Debug.LogWarning("Gave up");
}
private bool CanMoveTo(Vector3 destination)
{
NavMeshPath path = new NavMeshPath();
bool hasPath = NavMesh.CalculatePath(transform.position, destination, NavMesh.AllAreas, path);
if (!hasPath) return false;
if (path.status != NavMeshPathStatus.PathComplete) return false;
if ((GetPathLength(path) > maxWalkableDistance)) return false;
return true;
}
private float GetPathLength(NavMeshPath path)
{
float total = 0;
if (path.corners.Length < 2) return total;
for (int i = 0; i < path.corners.Length - 1; i++)
{
// this can be optimized but it's probably not the most expensive computation
total += Vector3.Distance(path.corners[i], path.corners[i + 1]);
}
return total;
}