Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How To Do Efficient Area Scanning With Physics?

Discussion in 'Physics' started by ryanzec, Aug 24, 2021.

  1. ryanzec

    ryanzec

    Joined:
    Jun 10, 2008
    Posts:
    696
    So I am trying to figure out an efficient way of doing area scanning but running into an issue with physics performance for a 2D game. I am using physics for movement (using `AddForce()`) as I want a physics feeling for my entities (slight acceleration / deceleration, knock back from being hit / explosion, etc.) so those entities have a dynamic Rigidbody2D component. I also have a detection collider as a child that can be quite big (20 - 50 units) and that is causing an exponential performance issue with `Physics2D.FindNewContacts()` taking up a ton of time in the profile. When I have 4 entities moving in range of each other that is 4 entities re-calculating contact points for 3 other entities and then I have 30 entities moving in range of each other that is 30 entities re-calculating contact points for 29 other entities so each entity add even more than the last.

    The only 2 options I can think of are:
    1. Use a kinematic Rigidbody2D and write custom code for handling "physics" interactions
    2. Remove the detection collider and do area scanning in a different way.
    Option #1 seems like a lot of work especially since I don't really need anything outside of what unity physics support (it is really just the performance which I assume is more just because of how I am doing things) so I am thinking of how to handle Option #2.

    What I am thinking of doing at a high level is:
    1. Remove the detection collider
    2. Add a queue for a detection area scanning (for lack of a better term) that game objects can add themselves to or remove themselves from
    3. I can process this queue in a co-routine or something (it does not need to check every frame for every entity that need detection scanning) so that each frame I do a scan for X entities
    4. This detection scanner would call something like `Physics2D.CircleCastAll()` and then process those hits (in the same way the detection script did when using the collider).
    For content, this scanning is mainly for AI purposes. Right now it is just for enemies to be able to track the player when in range however it will be expanded upon later (like enemies keep track of nearby enemies to heal if possible as one example).

    Does this seem like a sane way to handle this kind of problem? Is there "standard" way of handling something like this? Am I missing something with the core problem that could solve this issue easier?
     
  2. diXime

    diXime

    Joined:
    Oct 2, 2018
    Posts:
    162
    Hello,
    The slowdown caused by colliders (I've never heard of FindNewContacts() and can't seem to find it in manual?) is often their shapes. Polygon colliders requires a lot of work. Maybe box or even better circle colliders are faster.

    I would go for option 2. Instead of adding various colliders to check areas, one way I can think of right now would be to make some sort of field (with a much lower aspect ratio, so less pixels to iterate) for each range tracking (heal tracking, attack tracking...) and use it for your decision making.
    Another option would be to keep a list of ennemies and simply checking their distance to the player (or the other ennemies for friendly healing), but you maybe you have some complications preventing it, like vision fields and so on.
    Using GPU (with ComputeShaders) also greatly increases performance, but I don't know if it's an option.
     
  3. ryanzec

    ryanzec

    Joined:
    Jun 10, 2008
    Posts:
    696
    `Physics2D.FindNewContacts()` as far as I know it an internal method that Unity itself calls and can't be called externally. I am also using circle colliders.

    I don't know what you mean by "some sort of field (lower aspect ratio = les pixel to iterate) as I am not iterating over pixel at all (nor not sure why I would be)
     
  4. diXime

    diXime

    Joined:
    Oct 2, 2018
    Posts:
    162
    That explains it ! I'm not working a lot with 2D, sorry. Unity is checking for distances to compute colliders (as far as I know), which is the reason why circles are usually faster (since there's only one center and one distance). Now if it's polygon, it has to iterate through various points which is computationally consuming. My bad if it was already circles !

    Well, it's in 2D. Now imagine you set up a grid. Each square (what I've called pixel) of that grid can be filled if it's in range, and not filled if it's not. If your target (player, ally...) is in a filled square, it means it's in the range of something. Now instead of filling per se you can set up a structure saying what type of range this is (healing, attack...) and the source of the range (the ennemy), and filling the square with said structures.
    Maybe I'm not clear at all but it should be working.