Detect objects within a certain range

I am making my first project in Unity and decided to go with something relatively simple. The idea is that you are a block that needs to defend itself from waves of ‘zombie’ blocks coming at you. The zombie blocks are already able to follow the player around and collide with walls and the player itself. But right now, the zombie blocks are able to walk into each other and after a while, they can merge into one block of 20-30 blocks such as here:

What I am trying to do is make a ‘repelling force’ between the zombie blocks. I have already written a function that works and has the effect that I want, displayed in this GIF:

But the way I do it right now is horribly inefficient(it works in O(n²) time). Right now, I save all my enemies in a list. Then, every enemy checks that entire list and if it sees that an element is within a certain range it will calculate the repelling force. Thus, every update every enemy block has to check every single other enemy block. This is horribly inefficient and surely there must be a better way!

This brings me to my question:
Is there an efficient way to only detect/look at objects within a certain range?

Could you not just add a CircleCollider2D around each that is slightly bigger than the block to stop them coming together instead of the presumed BoxCollider2D you may have? Perhaps even add a tiny random variation on the radius so that it seems more natural when they are ‘compressed’ together? Unfortunately it’s in 5.0 but there’s a PointEffector2D that would’ve helped you here but wanted to mention it nevertheless.

I guess you could make the CircleCollider2D a trigger and perform your ‘repulsion’ action in the callbacks.

That idea could just work! Is it possible though to have both a boxCollider2D and a circleCollider2D? The method I used for collision detection relied on the 2D bounding box.

Absolutely, you can have as many colliders as you like on a GameObject.

Great! So is it then possible to detect collisions with the circle collider and the box collider seperately?
The only way I’ve learned to detect collisions with your boxCollider2D is by using the function OnCollisionEnter2D(Collision2D )
{

}

How can I specifiy collisions with the box Collider and collisions with the circle collider?

You need to explain a bit better what the set-up is then i.e is the circle a non-trigger and the box a trigger or the other way around. What is the purpose of the circle and the box? The idea I suggested above was to set the circle to a non-trigger so that the 2D physics keeps them separated. In this case, what is the use of the box?

For triggers you use the “OnTriggerEnter2D (Collider2D col)” and as you’ve indicated, the non-trigger uses “OnCollisionEnter2D (Collision2D col)”.

Note that it’s also possible to put one collider on the parent GameObject (one with the Rigidbody2D) and one on a child GameObject. That way you can have a dedicated script for each if you like.

Currently, the boxcillider is used for determining the correct position for raycasts. These raycasts are used for collision detection. This box collider is attached to my enemy object. This is the setup right now

I now want the circle collider around my object to detect what objects intersect with it, e.g. what objects are within a certain range so that I can perform calculations on those objects.

My question now is, what methods can I use to detect what objects collide with the circleCollider2D? I have tried to use the OnCollisionEnter2D(Collision) method, but according to some other forum threads that does not work if rigidBody2D is set to ‘is Kinematic’.

back in the day you would use some sort of proximity grid to avoid the O(n²) look ups , but in unity im sure colliders and triggers are all you need. Im sure nvidia physx and box2D physics are using this kind of optimization internally already.

Okay so this is all kinematic and you’re just positioning stuff yourself? Wondering why you’re using kinematic and not just specifying forces or using Rigidbody2D.MovePosition and using colliders and the physics system to keep things separated.

I would personally just use a circle collider (non-trigger) to keep them separated. Then if I wanted to do some algorithm based upon a certain distance I would have another circle collider (trigger) on a child GameObject and add a script that uses the “OnTriggerStay2D(Collider2D col)” to process them. You get a callback for each collider so no need to perform a ray-cast.

but according to some other forum threads that does not work if rigidBody2D is set to ‘is Kinematic’
That was an earlier version and is completely bogus. The problem was actually something else, ignore it.

Maybe the piece you’re missing is that you can put a collider on a child and set it to a different collision layer. You can then specify that collision layer on the ray-cast (assuming you must do them still). You also get a callback for that collider only on that GameObject.

Note that I’m trying to make it fast here and avoid the ray-casts completely.

So far so good! It now does indeed detect when objects are inside the circle collider!

The only problem now is that the rays I use for collision detection, also detect the circle collider of the enemy. This causes my player to collide with the circle around the enemy, which is not what I want.

Is there a way to let my rays collide exclusively with boxColliders and not with circleColliders?

As I said here:

Maybe the piece you’re missing is that you can put a collider on a child and set it to a different collision layer. You can then specify that collision layer on the ray-cast (assuming you must do them still). You also get a callback for that collider only on that GameObject.

In other words, put the collider that you’re trying to find with the ray-cast as a child and set it to a different layer. You can then test for that layer only with the ray-cast using the ‘layerMask’ parameter.

I’m still confused as to why you need to perform a ray-cast but the above should resolve your issue.

I have a solution I am satisfied with now! I decided to just take the original boundingBox2D collider as my range. So in the end I decided not to use the circleCollider2D. Using this technique the blocks are unable to form into a single entity just like I wanted!

Thank you very much for your help, it is much appreciated!

The reason I perform a ray-cast is simply because I followed a tutorial that handled the movement and collisions in that particular way. Because I am still quite new to Unity, I am now mostly combining things I learn from tutorials into a single game.

An option for optimizing such speed is to break your game area into a grid of cells, and then locate each zombie in a cell, and as it moves between cells relocate it to the new cell… then when you’re doing the collision checks, just check the neighboring cells for nearby zombies, instead of having to check them all.