UpdateGraphsNoBlock Potential false positives

Potential Bug with GraphUpdateUtilities.UpdateGraphsNoBlock()

Unity Project (Standard “2D” Unity Project Template)
Unity Version - 2019.4.28f1 Personal
Astar Pathfinding Project Version - 4.2.17 (Free Version)

Hi Aron, first of all thanks a bunch for this project, has definitely helped in the development of my game!!

However after using it for a couple of months now during the development of my tower defense game i think i may have stumbled across a bug with GraphUpdateUtilities.UpdateGraphsNoBlock. If im using it incorrectly then i hope we can get to the bottom of this, or on the flip side i’m happy to help contribute to fixing this if it actually is an issue. Anyway, onto the issue!

We had the scenario in which one of my play testers was able to “block” the goal node from being pathed to from one of the spawner nodes, initially i chalked this up to a small bug in my own code and worried about it later… Since this occurance it’s cropped up many more times and i’ve made a lot of alterations to the code and searches through this forum to try to remedy the issue, to no avail. Eventually we were able to pin down certain collider placement configurations that would cause the issue time after time. Just to be sure that this was not a conflict or issue with the rest of my games code, i’ve made an entirely new fresh project with the absolute bare minimum to replicate this issue and can do so every time without fail, whilst using the exact method for checking for runtime path blocking in the documentation. The reason why i think this is a bug with the Astar system is because it works most of the time, but in certain scenarios which run the exact same code on my end, provide different than expected results.

The premise of the game is a grid-based tower defense where the player can place path obstacles (towers) on any tile except for “spawners” and the “goal” tile, the relevant info related to how we use your pathfinding system is the following;

** As stated, the screenshots are from the stripped down “bare minimum” version of my project to avoid any issues from my own game logic.

  • Map consists of a grid of 2d tiles which are 1x1 game units
  • Within the map are X number of “Spawner tiles” (the can be thought of as start points for a path)
  • Within the map there is 1 Goal (a single tile, on the very centre tile of the map)

A freshly generated map will look like the following (Screenshot #1)
Purple Tile = Goal Node (single tile in center)
Blue Tiles = Spawners (Start of enemy paths, 1 in each corner of grid, total of 4)
Clear Tiles = Empty Tile (All the rest until obstacle placements are made)

If the player is to click on any “Clear” tile, it will place an object with a 0.9diameter 2D Circle Collider ontop of that tile emulating what would be a “Tower” or an “unwalkable tile”

I then implemented a simple function to check over each of the clear tiles, place a new obstacle, check if the GraphUpdateUtilities.UpdateGraphsNoBlock function returned true/false for that tile, and updated it’s color to represent the result, green = allowed to place, red = invalid or blocking placement

As pictured below (Screenshot #1), this is working great/as expected with various placement scenarios
** Note, this display for checking does actually line up with what im able/not able to place, e.g it accurately reflects the potential for placement of an obstacle/tower via running the same UpgradeGraphsNoBlock function

However, it seems running all the exact same code that seems to work perfectly fine in different placement configurations, causes the graph to allow placement in areas that it should not be aloud to be placed;

Breaking scenarios pictures below (Screenshot #2)

Many more than just the above scenarios have been found to cause this same issue just figured picturing a few is all thats required to understand the issue.

The code pretty much comes straight out of your documentation, and i’ve tried various suggested fixes on other posts such as attempting to Physics2D.SyncTransforms() etc, nothing seems to be able to remedy this solution.

There are only 3 scripts that run this entire demo project (Map, Tile & Wall)

  • Map just generates the tile locations and stores the spawner/goal node locations in a list
  • Tile just has an OnMouseDown that builds the wall as a child of the tile checks for no blocks and then rescans the graph
  • Wall is simply just a test script that lets me destroy a wall if i click on it again so i can reset my placements (this is relevant as it’s how players are allowed to play with their towers in the proper project)

The main placement function is pasted here below, if you need more code/snippets or the entire demo project, i can send that through also, i just figured this is getting pretty long

Tile.cs

private void OnMouseDown()
    {
        if (transform.childCount == 0)
        {
            GameObject placedObstacle = Instantiate(wallPrefab, transform);

            if (placedObstacle != null)
            {
                // Create new guo with newly instantiated gameobject collider bounds
                GraphUpdateObject guo = new GraphUpdateObject(placedObstacle.GetComponent<Collider2D>().bounds);

                // Get all nodes (Goal + 4 Spawners, added to list when map created)
                List<GraphNode> nodesToCheck = new List<GraphNode>();
                foreach (Vector3 pos in map.pathStartAndGoalPoints) {
                    nodesToCheck.Add(AstarPath.active.GetNearest(pos).node);
                }

                if (GraphUpdateUtilities.UpdateGraphsNoBlock(guo, nodesToCheck, false))
                {
                    // do nothing, this enemy path was not blocked
                }
                else
                {
                    // Invalid tower position. It blocks the path between the spawn point and the goal
                    // The effect on the graph has been reverted
                    Debug.Log("Tower/card invalidated path so is being destroyed.");
                    Destroy(placedObstacle);
                }

                GridGraph graphToScan = AstarPath.active.data.gridGraph;
                AstarPath.active.Scan(graphToScan);
            }
        }
    }

Sorry for the massive post, and thanks in advance if you can assist. If you need any further information at all please just let me know, fixing this is really our only remaining bug in the project before we can start polishing and getting ready for release, hope to hear from you soon!

Best Regards,
Jake

Hi

Thank you for the detailed bug report. If you could send the demo project that shows the issue, that would be very helpful :slight_smile:

Hey Aron,

Really appreciate your time! let me know if you need anything else clarified, the zip folder just contains the base project stripped down to little more than the astar project and my test scripts, in Unity 2019.4.28f1 Personal.

i coulnd’t attach the project here, so i’ve uploaded to a google drive link;
https://drive.google.com/file/d/1mB4KYk2O0-qP9VMRIpUjHvefYC3UlHuD/view?usp=sharing

Best Regards,
Jake

Hey Aron,

Replied and pasted a link to download the test project, was wondering if you’ve yet had a chance to look into this issue?

Best Regards
Jake

Hi

I tried it out, and this seems to be an edge case bug in 4.2.17. However, I verified that it doesn’t happen in the latest beta. So you could try that one out.

Hello Aron,
It looks like this issue might be the same as mine here.
To test the beta version do I need a pro licence ?

Yes, the beta requires the pro version.