Good way to dynamically and randomly spawn on navmesh?

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;
        }

This looks sound. Well done.

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms