Object bounds causing neighbor tiles to be walkable/unwalkable

Hello,
I have a layered grid with each node the size 1x1. I have an object I place above a grid node, of the size 1x1. The object is perfectly aligned with the node edges so it fits directly inside.

When I do the following:

    Bounds bounds = newObj.GetComponent<Collider>().bounds;
    GraphUpdateObject guo = new GraphUpdateObject();
    AstarPath.active.UpdateGraphs(guo);
    if (_updateGraphImmediately) {
        AstarPath.active.FlushGraphUpdates();
    }

It will affect nodes neighboring the one node the object is directly on top of. I have sort of fixed this, by setting the Collision Testing diameter to be 0.95. This resulted in only making the node the object was placed upon, be unwalkable.

However, I am now seeing issues where the above code will actually set neighboring tiles to walkable, if they were unwalkable beforehand

Update: Was able to fix neighboring nodes becoming walkable when placing an object, by having it check Renderer bounds, rather than collider bounds.

However, I am now seeing the issue of neighboring tiles becoming walkable, when removing an object from one tile.

P.S. Not sure if this is relevant, but before any of this happens, I am also looping through all nodes and setting them to walkable/unwalkable, using the loop suggested on https://arongranberg.com/astar/documentation/dev_4_1_6_17dee0ac/graph-updates.php#direct Please note that this loop is long done before any item is placed or removed.

That is very relevant. The GraphUpdateObject will tell the system “recalculate any nodes that could possibly be affected if a collider was removed or added within the bounding box as if the collider was there/not there when the graph was scanned”. This means that it will override any changes you have made manually using that loop.

Maybe you want to set the GraphUpdateObject to just make all nodes inside it walkable/unwalkable instead of recalculating the graph as mentioned above:

Bounds bounds = newObj.GetComponent<Collider>().bounds;
GraphUpdateObject guo = new GraphUpdateObject();
guo.updatePhysics = false;
guo.setWalkability = true; // Makes GUO set the nodes' walkability value to the value of 'modifyWalkability'
guo.modifyWalkability = true/false; // Depending on if you want to add or remove an obstacle
AstarPath.active.UpdateGraphs(guo);
1 Like

Thank you for the reply! I’m definitely not doing something correct when deleting. Nonetheless, I am now finally harnessing the power of seeker tags, as opposed to only using a graph’s collision testing mask attribute, to flag blocking objects. Now I can actually set what seeker types can go on what surface! Love it!

That being said, if I am doing this when adding an object:

Bounds bounds = newObj.GetComponent<Collider>().bounds;
GraphUpdateObject guo = new GraphUpdateObject(bounds);
guo.setTag = 5;   /// tag has been set up in both Unity and graph tag settings
guo.modifyTag = true;
AstarPath.active.UpdateGraphs(guo);
if (_updateGraphImmediately) {
    AstarPath.active.FlushGraphUpdates();
}
  1. Then do I also need to pass tags when deleting an object?
  2. If I use tags, I don’t need to worry about setting walkability explicitly anymore, right? Seekers will avoid any objects not listed in the valid tag section.

My current problem is that after deleting an object, the seeker will still avoid the nodes the object used to be on. When the object was there though, it correctly avoided the object with just the tag settings mentioned above.

Just to reiterate, I am no longer using the graph’s mask section, and there are no more red cubes on grids, denoting an unwalkable node, when looking at the Scene window. It seems like the seeker is taking care of that behind the scenes based on it’s tags settings, without a gizmo.

Am going to try and put together a sample scene to demonstrate this and other issues I may have in the future.

Yes. You will need to specify which tag you want the nodes to have, otherwise the tag will be left unchanged.
So if you are deleting an object you need to set the tag to the default tag (i.e tag 0).

Yes. If you really do not want to recalculate that part of the graph I also recommend that you set guo.updatePhysics = false to avoid those calculations.

You can visualize the tags of the nodes by changing the Graph Coloring option.

1 Like

That’s what I was doing wrong, thank you! I was setting the tag to the one of the object to be deleted.

Setting guo.updatePhysics = false helped solve another bug I was having, where deleting an object when a seeker character was nearby, would place a random colored tile at character’s height. However, adding this setting has surfaced a new issue where deleting objects, leaves colored tiles at the height of where the objects used to be.

To repro, add this to the UpdatePathfinderRemoveObject function in the example I sent you:

    guo.setTag = 0;
    guo.modifyTag = true;
    guo.updatePhysics = false;

Then you will see this after pressing ‘2’ to delete walls:

Those walls look like they were there from the start of the game when the graph was first calculated.
This means that 1: they will not have tags below them and 2: the graph will have detected them as ground and placed the nodes on top of them. When you remove them and use updatePhysics=false the positions of those nodes will not be calculated and so they will stay up in the air.

I recommend that you create all walls using the same system, i.e using GraphUpdateObjects with updatePhysics=false after the graph has been scanned.

Those walls look like they were there from the start of the game

Sorry, but they are actually placed at the time of your choosing after the scene has started. If you check out the example I emailed you, all the walls are added when you press 1 on your keyboard. You then press 2 to have the middle walls removed. At the start of the scene, you only have a plane object, which represents the ground. Each wall is added using:

private void UpdatePathfinderAddObject(GameObject newObj)
{
    Bounds bounds = newObj.GetComponent<Collider>().bounds;
    GraphUpdateObject guo = new GraphUpdateObject(bounds);
    guo.setTag = 1;
    guo.modifyTag = true;
    AstarPath.active.UpdateGraphs(guo);
    if (_updateGraphImmediately) {
        AstarPath.active.FlushGraphUpdates();
    }
}

Some walls are then removed using:

private void UpdatePathfinderRemoveObject(GameObject objToDelete)
{
    Bounds bounds = objToDelete.GetComponent<Collider>().bounds;
    GraphUpdateObject guo = new GraphUpdateObject(bounds);

    guo.setTag = 0;
    guo.modifyTag = true;
    guo.updatePhysics = false;
    Destroy(objToDelete);

    AstarPath.active.UpdateGraphs(guo);
}

Ok. I suggest you also add the updatePhysics = false line when you add the obstacle.

1 Like

Ah, my bad, I should have tried that earlier. Worked like a charm.

Thank you for the help, and I hope you feel better soon!

1 Like

Hello,

I wanted to revive this thread, in order to ask if the solution above, is also the recommended way to have seekers avoid running into each other and getting stuck, when only using tags. To give some context, I have recoded my seekers, to use a similar setup as you have with the MineBotAI, both in terms of attached components, and animation control, minus the funnel modifier.

I have tagged all my seekers as ‘human’, and set their seeker settings, for humans to not be traversable. I was then planning on applying the code above for UpdatePathfinderAddObject() when they reach their destination and stop, and UpdatePathfinderRemoveObject() when they start moving again.

Is this the right approach? Would the funnel modifier fix this instead? If I do use this approach, would it also work if the blocking person stops, after the person that is about to run into them, has already started their path?