Problem with list of collisions from Physics2D.OverlapCircle

I have a player represented as a white circle here, that moves over a 8x15 grid of instantiated tiles. I’m trying to use Physics2D.OverlapCircle to compare the layer of the tiles the player collides with against the player layer. In the image below you can see Tile45 acts as expected but I would expect Tile60 to behave identically yet it isn’t caught until after Tile46 is registered. This problem continues with Tile 61 as we can see.

Here’s my code:

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

public class PlayerController : MonoBehaviour
{
    //references
    public GameManager gameManager;
    Rigidbody2D myRB;

    private GameObject player;
    private Renderer pSprite;

    public LayerMask playerLayerIndex; //8 White ,9 Red , 10 Green, 11 Blue 
    private Color playerColor;

    public Color White;
    public Color Red;
    public Color Green;
    public Color Blue;
    Color[] ColorArray = new Color[4];


    //Tile interactions
    private List<Collider2D> collisions = new List<Collider2D>();
    public float radius = 0.47f;
    private float dist;
    private float lastStatusUpdateTime = 0f;
    private List<string> colTileNames = new List<string>();


    void Start()
    {
        player = gameObject;

        myRB = GetComponent<Rigidbody2D>();
        pSprite = GetComponent<Renderer>();

        playerLayerIndex = 16;

        ColorArray[0] = White;
        ColorArray[1] = Red;
        ColorArray[2] = Green;
        ColorArray[3] = Blue;


    }

    void Update()
    {
        while (Time.time > lastStatusUpdateTime + GameManager.updateInterval) //Time.time = time at the beginning of this frame
        {
            lastStatusUpdateTime += GameManager.updateInterval; //+= Addition assignment operator
            TestStatusUpdate();
        }

    }

    public void TestStatusUpdate()
    {

        collisions.Add(Physics2D.OverlapCircle(transform.position, radius));

        foreach (Collider2D nearbyObject in collisions)
        {
            if (nearbyObject.gameObject.CompareTag("Tile"))
            {
                if (nearbyObject.gameObject.layer != playerLayerIndex && nearbyObject.gameObject.layer != 8)
                {
                    colTileNames.Add(nearbyObject.name.ToString());
                }

            }
        }

        print(string.Join(", ", colTileNames));
        collisions.Clear();
        colTileNames.Clear();

    }

}

As an aside I’m also not entirely sure why my print isn’t joining all the tile indices together.

OverlapCircle only checks if some collider overlaps and it’s undefined which it returns if there are multiple. It can return the same collider over and over again even if there are other colliders overlapping.

To get all overlapping colliders, you need to use Physics2D.OverlapCircleAll instead.

1 Like

Thanks for your response Adrian. I had it set to “All” before but was told:

Edit:

It does work when I go back to using All though. I guess its ok that I’m not reusing the list and its garbage collected in this context because I’m calling the function frequently right? I’m kind of doing my own clean up when I clear the list.

If you are concerned about creating garbage, there is a non-alloc version of OverlapAll here: Unity - Scripting API: Physics2D.OverlapCircleNonAlloc

You pass it an array and it will populate the array with the results for you. You can reuse the same array every frame. Just make sure you provide an array big enough to capture the maximum number of overlaps you expect to happen, or you will miss some.

1 Like

To note, all the NonAlloc and All suffixes are tentatively deprecated. All 2D physics queries without exception have overloads that return a single result or an array or List of results. Just look at the API docs without the above suffixes, you’ll see them all there.

For instance, OverlapCircle.

1 Like

I can’t seem to find any examples of the straight OverlapCircle returning a list of Collider2D objects. If I use the All version it works but when I don’t I get the problem described at the top of this post. Am I doing it correctly like this?

collisions.Add(Physics2D.OverlapCircle(transform.position, radius));

List.AddRange() should be used to add a collection of objects to another.
The method overloading is likely choosing OverlapCircle that returns one object to List.Add()

Edit:
Looking at the method overloads of OverlapCircle you need to use one that takes a list as extra argument for your desired use case. So not entirely interchangeable.

Hi, thanks for your comment. I understand that I need to use .AddRange now but I’m still unable to work out how to get OverlapCircle to return a list of Collider2D.

We don’t write methods from now on that produce garbage. Each time you call the All methods, the list is create and then left to be garbage collected. If you don’t care about this then go ahead and use it. A far better method is to reuse a list so you don’t get this.

Create a list and reuse it for your query. Pass it to the overload of OverlapCircle that requires a list. It’ll populate the list for you. Reuse that list and you’ll also get no garbage.

1 Like

In the end I solved it like this:

var contactFilter = new ContactFilter2D();
        contactFilter.NoFilter();
        Physics2D.OverlapCircle(transform.position, radius, contactFilter, collisions);

foreach (Collider2D nearbyObject in collisions)
        {
                //Doing stuff here        
        }

collisions.Clear();
1 Like

Glad you got it working.

Note that you don’t need to clear the list as the query will set the size according to the returned results. It doesn’t add to any existing contents.

2 Likes