UNITY: Getting random point on `NavMesh`

52 views Asked by At

The Problem

My goal is to write a static method that gets an evenly distributed random point on a NavMesh.

I expect for everytime I call this method to get a random Vector3 that is a point on the mesh, which is currently working, however, the distribution leaves much to be desired.

Logistics

Unity 2022.3.19f1.

Some information about the floor object

Here is the parent transform Image of Parent Transforms

Here is the child, aka the actual mesh

Child Components

To summarize textually when i get localScale it's 1,1,1 and lossyScale is 200,200,200

Code

using System;
using UnityEngine;
using UnityEngine.AI;


public static class SpawnUtils
{
    //Offset to ensure GameObjects aren't spawned near edge
    private const int NAV_MESH_OFFSET = 20;
    private const int MAX_ATTEMPTS = 5;
    private static GameObject floor;

    public static Vector3 GetRandomSpawnPosition()
    {
        GameObject floor = GetFloor();

        NavMeshHit hit = new();
        int attempts = 0;
        bool foundPoint = false;
        
        float maxX = floor.transform.position.x + floor.transform.lossyScale.x / 2 - NAV_MESH_OFFSET;
        float maxZ = floor.transform.position.z + floor.transform.lossyScale.z / 2 - NAV_MESH_OFFSET;
        float minX = floor.transform.position.x - floor.transform.lossyScale.x / 2 + NAV_MESH_OFFSET;
        float minZ = floor.transform.position.z - floor.transform.lossyScale.z / 2 + NAV_MESH_OFFSET;

       // see my note on this variable 
        float maxDistance = 100;


        while (!foundPoint && attempts < MAX_ATTEMPTS)
        {
            float x = UnityEngine.Random.Range(minX, maxX);
            float z = UnityEngine.Random.Range(minZ, maxZ);
            float y = floor.transform.position.y + floor.transform.lossyScale.y / 2;
            Vector3 randomPoint = new(x, y, z);
            foundPoint = NavMesh.SamplePosition(randomPoint, out hit, maxDistance, NavMesh.AllAreas);
            attempts++;
        }

        if (!foundPoint)
        {
            Debug.LogError($"Failed to find a spawnable area within the maximum number, {MAX_ATTEMPTS} attempts.");
            return floor.transform.position;
        }

        return hit.position;
    }


    public static GameObject Floor
    {
       ...
    }


    public static GameObject GetFloor()
    {
       ...
    }

    public static Vector3 GetSpawnableArea(Vector3 origin, float maxDistance)
    {

       ...
    }

}

Regarding float maxDistance, this variable appears the be most influential and the cause of most of my misunderstanding, I imagined that it just tells the SamplePosition method how far of a search range to go from randomPoint and stop once the minimum distance required is found.

However, there seems to be a discrepancy here, adjusting the variable in increments of 50 leads to everything spawning either at the edge or in the dead center.

Examples

maxDistance = 1000 Example with maxDistance = 1000 GameObjects` are distributed towards the edges

maxDistance = 500 Example with maxDistance = 500, GameObjects are distributed towards the edges

Now here it begins to get sensitive

maxDistance = 200 maxDistance = 200, still a edges

maxDistance = 150 maxDistance = 150, still at edges

Now once, I'm at this 100 mark, I encounter this strange distribution where objects are spawned at the center AND edges

macDistance = 100

I'll spare the last image since from 80 downwards, it's almost consistently at the origin Vector3(0,0,0)

0

There are 0 answers