Support Forum

Whats the best way to check for a path when creating obstacles (maybe a bug?)

Hi,

so basically I am creating a TD where the player can build inside the enemies movement area.
For this I have to prevent them from blocking the path.

Currently my idea is to show them where they can build and where they can not. For this I have an grid system that stores valid build spots.

My problem is now how to calculate this.

My current idea is the following:

  1. The player clicks on the build but
  2. Build mode is activated
  3. cylce through all possible build tiles and do the following
    pseudocode:
    foreach x in positions Create temporary obstacle on x use Pathfinding to scan new graph use AIMove to check if a path exists if path exists then mark as builkdable else mark as invalid repeat for all positions
    I havent implemented this yet but I imagine that it could be very slow. Not to mention that I have to wait for each AIMove to finish calculating before I can continue. For this I have to either lock the UI or show one tile after the other.

What is the best way to handle this?

One more info: my start and end are static and wont move. only the obstacles will.

I found the GraphUpdateUtilities.UpdateGraphsNoBlock method. But I cant get it to work:

        public bool isBlocking(GridPosition gridPosition, TowerData towerDataToBuild)
        {
            var tower = towerDataToBuild.towerPrefab;
            var collider = tower.GetComponent<BoxCollider2D>();

            var guo = new GraphUpdateObject(collider.bounds);

            var center = (Vector3)gridPosition.WorldPosition;
            var size = (Vector3)collider.size;
            var colliderDepth = 100f;
            var sizeScales = new Vector3(size.x * towerDataToBuild.size.x, size.y * towerDataToBuild.size.y, colliderDepth);
            guo.bounds = new Bounds(center, sizeScales);
            // guo.modifyWalkability = true;
            // guo.setWalkability    = false;

            var spawnPointNode = AstarPath.active.GetNearest(spawnerTile.transform.position).node;
            var goalNode = AstarPath.active.GetNearest(destinationTile.transform.position).node;

            var notBlocking = GraphUpdateUtilities.UpdateGraphsNoBlock(guo, spawnPointNode, goalNode, false);
            Debug.Log("");

            return !notBlocking;
        }

With this code it wont return any blocking tiles. If I uncomment the two lines it will return the correct blocking lines but only the first time I execute it.
My guess was that the BoxCollider2Ds bounds are too small in the Z axis. But even with a value of 100/50 it doesnt work.

Any ideas?

If Im not mistaken, this might be a bug.

This method is called to test for blocking:

The IsPathPossible method takes a list of Nodes to determine if there is a path between. The issue is that according to the implementation:

It just checks if every node is walkable. In this case this doesnt make much sense. You only give the method two nodes, the start end the end. Wich means that either they are always walkable or never depending on how it set up.

Am I missing something here or is this simply broken?

I made a short video showcasing the issue: Astar Grid Update Issue - YouTube

  1. As you can see when starting the game the graph and path are generated correctly (see the green line in game view/the green circle moving)
  2. If I click on a tower button the build mode gets activated. The red tiles are the ones on which a new tower can be build. Currently only the blocking logic is used so existing towers dont count for this.
  3. As you can see it successfully identifies the tiles that cant be walked on (the ones without the red outline)
  4. If I cancel the buildmode and start it again, the tiles are also correctly identified.
  5. If I build a tower, the graph and path are updated correctly. graph see scene view and path see play view.
  6. If I now enter build mode again, the tiles are no longer being identified correctly. As you can see the tile in the top left for example is flagged as buildable eventhough its clearly blocking.
  7. On the other hand the tile at position 0,2 is correctly flagged as blocking
  8. Every further time I build a tower in a non blocking tile and activate build mode again, it will show the exact same tiles as buildable/non buildable
    image
  9. If I build a tower on a blocking tile it will show almost everything as blocking
    image

My code currently looks like this:

        public bool isBlocking(GridPosition gridPosition, TowerData towerDataToBuild)
        {
            var tower = towerDataToBuild.towerPrefab;
            var towerCollider = tower.GetComponent<BoxCollider2D>();

            var center = (Vector3)gridPosition.WorldPosition;
            var size = (Vector3)towerCollider.size;
            var colliderDepth = 100f;
            var sizeScales = size.Set(z: colliderDepth);

            var guo = new GraphUpdateObject(towerCollider.bounds) {
                bounds            = new Bounds(center, sizeScales)
              , modifyWalkability = true
              , setWalkability    = false
            };

            var spawnPointNode = AstarPath.active.GetNearest(spawnerTile.transform.position).node;
            var goalNode = AstarPath.active.GetNearest(destinationTile.transform.position).node;

            var notBlocking = GraphUpdateUtilities.UpdateGraphsNoBlock(guo, spawnPointNode, goalNode, true);

            return !notBlocking;
        }

I really dont know where to go from here.
It would be greatly appreciated if you at least could give me a pointer in what direction I should investigate.

Hi

How do you update the graph when you place a tower? Does that differ from the isBlocking method?

Also. You probably want to set the updatePhysics parameter on your GraphUpdateObject to false to prevent the grid graph from recalculating that tile (and possibly adjacent ones) from scratch.

You actually gave me the hint I was missing. I finally found a solution. But I still dont know why it was broken,

After building a tower I was updating the graph by calling “AstarPath.active.Scan();” and waiting for the result. After changing that to “AstarPath.active.UpdateGraphs(new Bounds(position.WorldPosition, Vector3.one * MissionHandler.Instance.TileScale));” it works now.

Could you explain why this doesnt work?
When loading the scene I call scan() because I have to reposition/resize it. After this scan it works like I want it to.
Also how the hell is “GraphUpdateUtilities.UpdateGraphsNoBlock” working? I tried understanding how it works but still have no idea

1 Like

Could you try to place a few towers using UpdateGraphs and then manually press Scan in the inspector. Does the graph change when you do this?

Essentially the idea is:

  1. Update the graph using the graph update object.
  2. Check if the nodes have the same “area”. This means that they are in the same connected component of the graph, and there will be a valid path between them.
  3. Optionally revert all the changes to the graph.