GraphUpdateObject not working at all

Hi,

A paying customer here. I have a pretty puzzling problem using GraphUpdateObject.

I have a pretty basic setup where I use:

  • a Grid Graph, it starts with pretty much everything walkable, plain.

  • The Graph is configured to use Physics Sphere casting to check walkability as well as height testing.

  • Graph update batching is turned on,

  • In this context I try to use GraphUpdateObjects to get the graph updated whenever there are new obstacles.

The GUO is working correctly for making nodes unwalkable. However when I try to revert the changes (once the obstacle disappears) there are no changes or the extent of changes is radically smaller than of the original GUO that I try to revert.

I tried two methods:

  • RevertFromBackup() with trackChangedNodes
  • Setting modifyWalkabilty = true and setWalkability = true

Neither is having the desired effect.

From inital, very preliminary looks of it, it seems like the issue is with batching updates?

Is this feature working at all? After spending a couple of hours testing this extensively, I’m pretty sure the issue is with the library and not my code, however of course I could be mistaken.

How an I best proceed to have this issue fixed.

Best,
Julius

Hi

Usually the best way is to simply use physics for updating the graph, that means that you should not set any parameters like modifyWalkability on the GUOs, when you first instantiate an obstacle you just create a new GraphUpdateObject with the collider bounds and when you destroy it you do exactly the same thing. Make sure that you destroy the object before updating the graph because otherwise the graph update will still think that there is an obstacle there and the nodes will not be changed.

Well normally I’d agree.

However still I have a problem getting it to work at all.

Do GUOs with changing walkability work at all with batch updates? Is that implemented? For instance if I perform GUO update 1, then a couple of lines GUO update 2, etc. etc. and these requests get batched - I’m I guaranteed that the final result will be the same as if I just run them without batching?

I have a bit complex use-case here with many physical units moving one next to the other. If an object is moving fast enough I don’t it to be taken into consideration in the pathfinding map (i.e. I want it to disappear in the map). That’s because it’s very difficult to reason about moving objects and the way they will interact with each other in the future. That’s why I used modifyWalkability.

Best,
Julius

As long as you don’t do any other modifications in the meantime the result should be the same. The graph updates should be executed in the same order and give the same result (though if the graph update uses physics it can obviously depend on if objects have moved in the scene).

I’m not sure why it is not working for you though. Are you sure the bounds object is large enough to contain the nodes (even on the y axis)?
Also, have you disabled the ‘updatePhysics’ field on the GUO (that field and modifyWalkability are mutually exclusive and updatePhysics will take precedence if I remember correctly (it’s in the docs)).

Okay, so I did some more testing.

I extended the bounds by a few units and now there is some effect, though not exactly what I would expect.

  • When I use RevertFromBackup() it works pretty well. However this has an inavoidable issue that if there is a change A, then an overlapping change B, then I revert change A and then revert change B then I will likely get some artifacts from the change A on the map, since the “backup” of B contains some data from the overlapping change A.

  • Therefore I’d really prefer to use modifyWalkability=true, setWalkability=true. This would more likely set some nodes as walkable where they shouldn’t be, but I prefer that compromise to the above one. So I tried with the very same bounding boxes and I get kind of artifacts (see the picture attached).

I don’t really understand why - I would expect that the method that I use would rather have too many nodes set to walkable rather than too few.

Here is a relevant part of the code:

var newWalkability = <something>;
var oldWalkability = <something>;
if (<some condition expressing essentially that it is necessary to update the graph based on whether newWalkability and old walkability differ>)
{
    if (OldGUO != null)
    {
        Debug.Log("Revert: " + OldGUO.bounds.center);
        AstarPath.active.UpdateGraphs(OldGUO);
        OldGUO = null;
    }
    GUO = new GraphUpdateObject();
    if (newWalkability)
    {
        GUO.modifyWalkability = true;
        GUO.setWalkability = true;
        GUO.updatePhysics = false;
    }
    else
    {
        GUO.modifyWalkability = false;
        GUO.updatePhysics = true;
    }
    var bounds = gameObject.GetComponent<Collider>().bounds;
    // Extend the bounds so they overlap y-axis
    bounds.size = new Vector3(bounds.size.x, bounds.size.y + 2f, bounds.size.z);
    bounds.center = new Vector3(bounds.center.x, bounds.center.y - 1f, bounds.center.z);
    GUO.bounds = bounds;
    if (!newWalkability)
    {
        Debug.Log("Unwalkable: " + GUO.bounds.center);
    }
    if (!newWalkability)
    {
        OldGUO = new GraphUpdateObject();
        OldGUO.modifyWalkability = true;
        OldGUO.setWalkability = true;
        OldGUO.updatePhysics = false;
        OldGUO.bounds = GUO.bounds;
    }
    else
    {
        OldGUO = null;
    }
    AstarPath.active.UpdateGraphs(GUO);

I verified though logging that any “Unwalkable” line has it’s appropriate “Revert” line, so it’s not the issue with that.

So if I understand you correctly you are confused as to why the GUO with modifyWalkability=true does not always set the nodes that the GUO with updatePhysics=true affected to be walkable?

First off, your object might have moved between those two graph updates (I presume), so they might not be updated the same region of the graph.

Secondly when using physics, the actual region that is affected depends on Grid Graph Settings -> Collision Testing -> Diameter as well as Grid Graph Settings -> Erosion (though you seem to have that set to 0, so that shouldn’t matter). I would suggest that you use either update physics for both calls or modifyWalkability for both calls to make sure they match.

Another option could be to use tags instead of walkability which has the positive effect of not messing up the rest of the worlds walkability values when your agents move around.

“So if I understand you correctly you are confused as to why the GUO with modifyWalkability=true does not always set the nodes that the GUO with updatePhysics=true affected to be walkable?”

Yes, exactly.

“First off, your object might have moved between those two graph updates (I presume), so they might not be updated the same region of the graph.”

Hmm, but the only thing that I assign to GUO that has anything to do with gameObject is bounds. However bounds is a struct and as far as I can see contains no references to gameObject.transform or anything like that. For reverting I especially put aside a copy of the GUO to revert under OldGUO. So I believe the object moving around in between the calls shouldn’t affect anything. As the thing to be reverted will be OldGUO that has the same bounds as GUO.

“Secondly when using physics, the actual region that is affected depends on Grid Graph Settings -> Collision Testing -> Diameter as well as Grid Graph Settings -> Erosion (though you seem to have that set to 0, so that shouldn’t matter). I would suggest that you use either update physics for both calls or modifyWalkability for both calls to make sure they match.”

That’s a valid point. I could test it out. So should I extend the bounds.size by the value of Sphere cast diameter to fix that? Indeed, erosion is at 0.

“Another option could be to use tags instead of walkability which has the positive effect of not messing up the rest of the worlds walkability values when your agents move around.”

Yes, I like that idea. Will test it out as well.

Thanks for prompt responses.

Ah, sorry, I missed that.

Alright, indeed when I use modifyWalkability in both calls it works as expected. Seems the usePhysics call does some additional stuff, I’m not aware of like looking around the bounding box for some additional changes, etc.

I like the tag idea, probably will go with that.

Out of curiosity - is the GUO using modifyWalkability / modifying tags cheaper than the one using physics? I understand the usePhysics actually performs some raycasting / spherecasting under the wraps which may be costly?

Thanks for all the feedback. Really appreciated.

Hi

Yes, modifyWalkability is cheaper since it does not need to run a bunch of physics calls. Usually physics is surprisingly fast though.

Yeah, in the game that i’m writing the physics is a bottleneck actually. There are as many as 100 units searching for paths and performing some physics computation at once.

Anyways, the issue is resolved. Cheers.

1 Like