Search Unity

Detect objects within a certain range

Discussion in '2D' started by ShellpadInteractive, Oct 20, 2014.

  1. ShellpadInteractive

    ShellpadInteractive

    Joined:
    Oct 20, 2014
    Posts:
    13
    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?
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    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.
     
    Last edited: Oct 20, 2014
  3. ShellpadInteractive

    ShellpadInteractive

    Joined:
    Oct 20, 2014
    Posts:
    13
    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.
     
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    Absolutely, you can have as many colliders as you like on a GameObject.
     
  5. ShellpadInteractive

    ShellpadInteractive

    Joined:
    Oct 20, 2014
    Posts:
    13
    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?
     
  6. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    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.
     
  7. ShellpadInteractive

    ShellpadInteractive

    Joined:
    Oct 20, 2014
    Posts:
    13
    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'.
     
  8. shaderbytes

    shaderbytes

    Joined:
    Nov 11, 2010
    Posts:
    900
    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.
     
  9. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    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.
     
    Last edited: Oct 20, 2014
  10. ShellpadInteractive

    ShellpadInteractive

    Joined:
    Oct 20, 2014
    Posts:
    13
    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?
     
  11. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    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.
     
  12. ShellpadInteractive

    ShellpadInteractive

    Joined:
    Oct 20, 2014
    Posts:
    13
    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.
     
  13. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    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.
     
  14. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    Glad you got it working, good luck with your project.