PolygonCollider2D and Physics2D.Boxcast issue

Hey,
I’m having an issue with making an A* grid that is using a polygoncollider2d as the map bounds and then using the boxcast to determine if A collider was hit, however the boxcast is always returning true:

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

public class AStarGrid : MonoBehaviour
{
    public LayerMask layerMask;
    public PolygonCollider2D unwalkableCollider;

    public Vector2 gridWorldSize;
    public float nodeRadius;

    Node[,] grid;

    float nodeDiameter;
    uint gridSizeX, gridSizeY;

    public void Start()
    {
        nodeDiameter = nodeRadius * 2;
        gridSizeX = (uint)(gridWorldSize.x / nodeDiameter);
        gridSizeY = (uint)(gridWorldSize.y / nodeDiameter);

        Debug.Log("Gridsize = : " + gridSizeX + "," + gridSizeY);

        CreateGrid();
    }

    private void CreateGrid()
    {
        grid = new Node[gridSizeX, gridSizeY];
        bool isWalkable = true;

        Vector3 worldBottomLeft = transform.position - Vector3.right * gridWorldSize.x / 2 - Vector3.up * gridWorldSize.y / 2;

        for (int i = 0; i < gridSizeX; i++)
        {
            for (int j = 0; j < gridSizeY; j++)
            {
                Vector3 worldPoint = worldBottomLeft + Vector3.right * (i * nodeDiameter + nodeRadius) + Vector3.up * (j * nodeDiameter + nodeRadius);

                /*
                RaycastHit2D hit = (Physics2D.BoxCast(new Vector2(worldPoint.x - nodeRadius, worldPoint.y - nodeRadius), new Vector2(nodeDiameter, nodeDiameter), 0.0f, Vector2.right))
                if (hit.collider != null)
                {
                    Debug.Log("Hit Collider: " + hit.collider.name);
                    if (hit.collider == unwalkableCollider)
                    {
                        isWalkable = false;
                    }
                }
                */
                Collider2D[] colls = Physics2D.OverlapBoxAll(new Vector2(worldPoint.x - nodeRadius, worldPoint.y - nodeRadius), new Vector2(nodeDiameter, nodeDiameter), 0.0f);
                foreach (Collider2D coll in colls)
                {
                    if (coll == unwalkableCollider)
                        isWalkable = false;
                }

                grid[i, j] = new Node(isWalkable, worldPoint);
            }
        }
    }

    private void OnDrawGizmos()
    {
        Gizmos.DrawWireCube(transform.position, new Vector3(gridWorldSize.x, gridWorldSize.y, 1));

        if (grid != null)
        {
            foreach (Node node in grid)
            {
                Gizmos.color = (node.isWalkable) ? Color.white : Color.red;
                Gizmos.DrawCube(node.worldPosition, Vector3.one * (nodeDiameter - .1f));
            }
        }
    }
}

The node class simply holds whether it’s walkable and it’s position.

however when the code is run all node returned are red (and thus determined to have collided with the polygon 2D, even nodes that are spawned over the edge of the sprite holding the collider)



I was wondering if anyone could tell me what I’m doing wrong / how they’ve done it in the past,

Thank you

Inside your double-for-loop inside your CreateGrid() function, if you ever set “isWalkable” to false, it never gets reset to true. This means once 1 node sets that value to false, all future nodes will also have that value set to false. I think you should reset “isWalkable” to true after you create your “new Node()”.

I do recommend you continue to use “OverlapBoxAll” over “BoxCast” since the “box” you’re testing shouldn’t move. You do not need to subtract nodeRadius from your position because the first parameter represents the center of the box, not the starting corner.

Good luck!

2 Likes

Additionally, you should consider how bad (performance-wise) what you’re doing is. I would suggest placing the collider above on its own layer then you can simply perform an Physics2D.OverlapBox() which returns the collider only rather than an array. You’d expect either a collider or null. Even faster still would be to test either a point or a circle, both of which are much faster.

One thing I’m also confused about from the images is if you’re trying to detect if something overlaps the solid green area only or not. If so then I can see that area outside of that is still part of the polygon region (looking at the lines extending outwards) so it’ll also show overlap.

1 Like

Thank you for the help, with the bool change it now works as expected, And I’ve also implemented MelvMay’s suggestion.

    private void CreateGrid()
    {
        grid = new Node[gridSizeX, gridSizeY];
        bool isWalkable;

        Vector3 worldBottomLeft = transform.position - Vector3.right * gridWorldSize.x / 2 - Vector3.up * gridWorldSize.y / 2;

        for (int i = 0; i < gridSizeX; i++)
        {
            for (int j = 0; j < gridSizeY; j++)
            {
                Vector3 worldPoint = worldBottomLeft + Vector3.right * (i * nodeDiameter + nodeRadius) + Vector3.up * (j * nodeDiameter + nodeRadius);

                Collider2D coll = Physics2D.OverlapBox(new Vector2(worldPoint.x, worldPoint.y), new Vector2(nodeDiameter, nodeDiameter), 0.0f, layerMask); //Node radius isn't needed as the box point is the center
                if (coll != null)
                {
                    isWalkable = true;
                }
                else
                {
                    isWalkable = false;
                }

                grid[i, j] = new Node(isWalkable, worldPoint);
            }
        }
    }
2 Likes