Search code examples
unity-game-enginenavmesh

In unity, baking a nav mesh at runtime for a second time causes the navmesh to only partially build


I am currently designing a maze game in unity and have some enemy AI which chases players around the maze. If the player gets to a certain tile on the maze it'll generate a new maze with slightly larger dimensions.

I've been using the unity AI NavMeshSurface class to achieve this and calling surface.BuildNavMesh() to generate the nav mesh once the level has been generated.

The current level's maze game object(s) get destroyed each time the level is regenerated:


    public void GenerateNewMaze(int rows, int columns)
    {
        mazeData = dataGenerator.FromDimensions(rows, columns);
        DisplayMaze();
    
        surface.BuildNavMesh();
    }
    
    public void DisposeOldMaze()
    {
        GameObject[] mazeObjects = GameObject.FindGameObjectsWithTag("Generated");
    
        foreach (GameObject mazeObject in mazeObjects)
        {
            Destroy(mazeObject);
        }
    }

The first time I run this it works perfectly:

First generation

However from the second onwards I start getting some strange gaps:

enter image description here

I thought maybe the surface somehow still had the old data after doing some googling and I tried a couple of solutions such as surface.RemoveData() and NavMesh.RemoveAllNavMeshData() before building the navmesh again but I seem to get the exact same results.

Currently I can only think to create a new NavMeshSurface per maze generation but that seems overkill and unnecessary.

The tutorial I followed to do this was: https://www.youtube.com/watch?v=FkLJ45Pt-mY


Solution

  • Turned out to be something strange I'd done. For those interested, it was my misunderstanding that calling Destroy on my maze objects is not finished until the frame has ended. So the NavMesh was generating for both the new and the old maze

    Therefore I needed to dispose of the current maze objects in the current frame and update the NavMesh in the following. I did this with the following code by calling FlagLevelForProgression instead of GenerateNewMaze:

    public void FlagLevelForProgression()
    {
        mazeConstructor.DisposeOldMaze();
    
        // Load any stuff we need to...
    
        canProgressToNextLevel = true;
    }
    
    void FixedUpdate()
    {
        if(canProgressToNextLevel)
        {
            GenerateNewMaze();
            canProgressToNextLevel = false;
        }
    }