Updating Portions of Recast Navmesh During Runtime

Hi Everyone,

I have an RTS game where you can place buildings down on the terrain during runtime. I also have a script that flattens the terrain under the buildings when they are placed to help get rid of any dips or unevenness in the terrain. That works fine but the navmesh does not update, so the builders will either float or walk under the visible terrain when going to start construction. How can I have it update the navmesh in just the area around a building after it is placed and the terrain has been deformed?

I’ve tried using the RecastTIleUpdate and GraphUpdateScene components but they have not helped yet. It is likely that these are what I’m supposed to be using and I’m just doing something incorrectly but I’m not sure.

Can someone point me in the right direction?

navmeshes aren’t supposed to be altered much at runtime as it takes large amounts of processing power to recalculate the shape, perhaps a grid graph would work well here?
also GraphUpdateScene only applies changes to existing tiles such as making them unwalkable or giving them a tag, not altering their shape

Thank you for the information, but I’m stuck with recast graphs I’m afraid. Grid graphs are not giving enough accuracy around the many small objects I have placed on the map even at the most detailed settings.

Is there really no way to update a small portion of the recast navmesh at runtime? That would essentially render this asset unusable for my particular project as I need to be able to deform the terrain and keep the units level with it.

Updating a recast graph can be done using AstarPath.active.UpdateGraphs(bounding box).
You can also use a GraphUpdateScene component to do it, but in your case I think it will be more convenient to use the API directly.

Btw, if performance becomes a problem, you can try out the beta. Recast graph updates are a lot faster in the beta.

Thank you for the reply. So I’ve tried making this work for several hours now and have been unsuccessful in updating the recast graph to match the new terrain height. Here is my current script.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;

public class RHNavMeshTerrainUpdater : MonoBehaviour
{

[SerializeField]
Collider boxCollider;

// Start is called before the first frame update
void Start()
{
    StartCoroutine(UpdateNavmesh());
}

// Update is called once per frame
IEnumerator UpdateNavmesh()
{
    yield return new WaitForSeconds(5);

    Debug.Log("Updating Navmesh");

    // As an example, use the bounding box from the attached collider
    Bounds bounds = boxCollider.bounds;
    var guo = new GraphUpdateObject(bounds);

    // Set some settings
    guo.updatePhysics = true;
    AstarPath.active.UpdateGraphs(guo);
}

}

Very simple. I have this placed on my building and I’ve set the collider to a collider that is much larger than the building to ensure that it encompasses the terrain changes. It waits 5 second to make sure the terrain has had time to update. Then it run the AstarPath.active.UpdateGraphs(Collider Bounds); as you mentioned earlier. The units still use the original recast graph shape however when walking near the buildings, so it’s acting like it never updates. I also noticed that when this script fires off it freezes all of my units in place until I give them another order, even if they are very far away from the building.

What am I doing wrong here?

Hi

If you click “Scan” manually in the A* Inspector, does the graph update correctly in the scene view?

Do you use a custom movement script? Or have you otherwise disabled path recalculations?

Hi,

I just tested whether manually scanning makes a difference and it does not. My units, once frozen after the 5 second wait ends, remain frozen and walking in place even after I manually update. I also gave them a second move command to get them to walk over to the flattened area around the terrain and the navmesh was still using the original uneven terrain height.

I mentioned this in my other thread but the unit freeze also occurs when anything with a navmesh cut component is disabled or deleted. It’s very likely that the root cause is the same for both the freeze when removing a navmesh cut and for trying to update the graph after the terrain has been deformed.

As an FYI, I am using the “RTS Engine” asset from the Unity store to control the units. It has an integration package available for it for the A* Pathfinding project which is how I’m doing all of this. I’ve asked the RTS Engine dev if he knows anything about why the units would freeze in place after any sort of navmesh update occurs but he has not yet replied. It’s likely he won’t reply at all or within the next few weeks as he often disappears for several weeks.

I decided to test my units against a simple sphere object and gave it a Seeker, RichAI, and Destination setter component and then told it to go to a location near one of my buildings as it was placed. It did not have any issues continuing on its way to its destination. So this is likely a problem specific to the RTS Engine asset. However, it did not follow the height of the flattened terrain even after manually running the scan.

With that said, it sounds like I may have to dive into the RTS Engine’s core files and see what he has going on that might cause the freezing. I wanted to avoid that but I may have to. I’m still not sure what to do about the navmesh refusing to update for the adjusted terrain. The script that flattens the terrain was made by someone on the RTS Engine discord and given to me as they had a need to make it as well. I wonder if somehow it is doing something strange like only doing visual changes to the terrain and not actually changing the terrain data. I’m not even sure if that’s possible though.

Any ideas? Do you know if it’s possible that the script is not changing the data that the navmesh reads but still giving the correct visual results?

It sounds very much like this asset does not recalculate paths that have become invalid. When a recast graph tile is recalculated all nodes in it will be recreated. So units with paths inside that tile will have to recalculate their paths. The built-in movement scripts do this automatically (RichAI has special code for detecting this), but it seems the RTS Engine does not.

Do you have Show Graphs enabled so that you can visualize the graph in the scene view? It might be easier to see what’s going on there instead of just sending the units to walk over that region.