Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Question Check enter area without collisions

Discussion in 'Scripting' started by RoeeHerzovich, Sep 3, 2020.

  1. RoeeHerzovich

    RoeeHerzovich

    Joined:
    Apr 12, 2020
    Posts:
    103
    I have a script that needs to check for all the Entities(Entity is a monoBehaviour) in a certain area.

    Now, normally that's easy. I already made a working one by looping over all the entities in the scene and checking distance every frame(Because Entities constantly move).

    The problem is, ITS SUPER INEFFICIENT. Right now I have only 4 Entities in the scene because I am in testing so it's no problem, but when I actually implement it with many many Entities, it will surely lag due to the method being very expensive.

    I tried using colliders however since I am not even using colliders not to mention rigid bodies, it doesn't work, I tried putting colliders without rigidbodies but it's not enough and I want to look for another way. A way I can just check for enter or exit of any gameObject of a range that'd be less expensive than the one I am currently using.

    Appreciating all the help :)
     
  2. Terraya

    Terraya

    Joined:
    Mar 8, 2018
    Posts:
    646
    I dont know how efficient my Script is, but i hope it can help you out

    Code (CSharp):
    1.         [SerializeField] private List<GameObject> objectsInRange;
    2.  
    3.         private List<GameObject> ReturnObjectsInRange()
    4.         {
    5.             Collider[] hitColliders = Physics.OverlapSphere(transform.position, 10f);
    6.             foreach (Collider hitCol in hitColliders)
    7.             {
    8.                 if(!objectsInRange.Contains(hitCol.gameObject)){
    9.                     objectsInRange.Add(hitCol.gameObject);
    10.                 }
    11.             }
    12.             return objectsInRange;
    13.         }
    it gets all the objects with a collidger in range of 10f ,
    as long as you dont spam this function at 100 entitys, you should be fine

    Edit: The Return of a list makes here no sense since you got declared a List upfront, but sadly i have not enough time to change that quickly, im in a boring meeting :D
     
    adamgolden likes this.
  3. RoeeHerzovich

    RoeeHerzovich

    Joined:
    Apr 12, 2020
    Posts:
    103
    I thought of that solution, but that means every Entity will have to have a collider...
    I mean it's not THAT bad I guess, it kinda sucks tho... It'll be fine if the colliders can be isTrigger then they won't actually collide...

    But, how much more efficient is that?

    I tried using the System stopwatch to determine which of those two functions is faster, but the stopwatch said 0 milliseconds for the both of them which makes no sense at all (1 for what I said, and one for overlap sphere)

    The only big advantage I see in OverlapSphere is that it doesn't Iratete on ALL entities

    NOTE:
    I don't irritate once per frame.. that's the worst part...
    I loop once for EVERY ENTITY, not only the player has a detection range, entities also has, each its own meaning I will have to loop by the number of entities every frame... this is why it is so expensive
     
  4. Terraya

    Terraya

    Joined:
    Mar 8, 2018
    Posts:
    646

    I will stick to this thread reading, im also curious to see if anyone can find a solution for that,
    if you have to loop for ea. entity on every frame ... that sounds expensive at all :/

    have you thought about ECS ?
     
  5. RoeeHerzovich

    RoeeHerzovich

    Joined:
    Apr 12, 2020
    Posts:
    103
    I mean... the function exists once in the Entity script, but if there are 4 entities it means there are 4 entity scripts in the scene, and since every entity has its own range and entities within that range, I assume it runs on every entity...

    And.. I've heard of ECS, but I never tried it and idk how long it will take me to learn it + convert my code to it.

    And... how will ECS solve my problem? I mean, is it that much more efficient? or perhaps, is there a tool there that can help me?
     
  6. Terraya

    Terraya

    Joined:
    Mar 8, 2018
    Posts:
    646
    So well,

    i´ve seen Tutorials and Videos from ECS where the Developer had 1000 units which should head towards the Player,
    he had around 30~ fps,

    doing that in ECS improved hes fps to over 200 - 300,

    all the entitys depend then on "one" script, not on multiple,
    cant go more indepth since i didnt tryed it
     
  7. RoeeHerzovich

    RoeeHerzovich

    Joined:
    Apr 12, 2020
    Posts:
    103
    I made both of the functions (the one I used and one based on OverlapSphere) and tested the time it takes the both of the in milliseconds the execute, and Debugged the faster method. And.... no matter how many entities were near each other if at all, even when they were, the Distance method was actually faster than the overlap sphere every single frame(well makes sense but lol)... soo I just proved the Overlap sphere to be way slower

    EDIT:

    It's probably because OverlapSphere is a very expensive function
     
    Terraya likes this.
  8. adehm

    adehm

    Joined:
    May 3, 2017
    Posts:
    369
    You never need colliders same as you do not need physics or the UI system. These are all just constructs to assist rapid development but often at the cost of performance.

    You can have all your checkers in an array on a single script.
    Then loop them on that script in Update to make the check.
    If this trigger area is a 2D plane, for instance entities on ground so y is not important, just compare Entity[] xz rectangle vs Area xz rectangle.
     
    Last edited: Sep 3, 2020
  9. RoeeHerzovich

    RoeeHerzovich

    Joined:
    Apr 12, 2020
    Posts:
    103
    The trigger area is not a 2D plane, but a 3D, non-flat world. And I am very much aware I don't need those, the way I implement it is by looping and looking for the "Entity" component I made, I just mentioned that I assume OnTriggerEnter/Exit are more performant but require Colliders which I don't use.

    What you say here is what I already do, I have all my Entities in a list on a single script, I loop on them and check. But when there are many entities it becomes very not performant and I'm afraid that at more advanced times when I will deal with dozens of those Entities or maybe even near a hundred my game will lag. I am just looking for optimisations
     
  10. adehm

    adehm

    Joined:
    May 3, 2017
    Posts:
    369
    Colliders likely will not be more performant. Looping dozens should not be a problem and if that is then there is something else going wrong or your 3D math for the area check needs to be optimized in some way.
     
  11. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,606
    They should be more performant. While there may be some overhead, using colliders you will access Unitys' (Physx) own optimizations, such as the usage of trees to heavily reduce the total amount of checks required. For any large amount of normally O(n^2) checks, this should perform a lot better in theory. I never tested it tho.
    And of course one could re-implement similar optimizations to have an even better result without any overhead.. but generally speaking people wont bother.
     
  12. RoeeHerzovich

    RoeeHerzovich

    Joined:
    Apr 12, 2020
    Posts:
    103

    I am just using a classic Vector.DIstance..

    I didn't say it's not performant now... I am just afraid it WILL be more performance once I add more entities.

    Let me explain what's going on:

    Every update tick -
    Every single Entity in the game (Player and AI's alike) will look over all the Entities in the game (I get all the entities via FindObjectsOfType in the Awake function as a static value so that I'll be able to access it from everywhere, on EntitySpawn or EntityDeath events modifies the list.)
    And do a Vector3.Distance between the other entities and itself and check if the distance is smaller than its detection range, and if it is, insert it into its own "entitiesInRange" list

    Which means, that every entity loops over all entities and runs Vector3.Distance, so if I have 4 entities on the scene (player and 3 AI's)

    it will do

    4(number of entities) * 3(all entities that are not you) rounds PER FRAME.
    It's just 12 rounds which is nothing, but that's with 4 entities, bump the number to 50 and you get

    50 * 49 = 2450 rounds PER FRAME, which is quite a lot. And TBH Idk how many entities are gonna be on a single scene, but a big number will quickly get this method to lag.


    Here's the code inside the Entity script(Note this is just the loop this method also has another IF just to see if there are no entities around to set the target to null but it's not looped so no big deal):

    Code (CSharp):
    1.         f
    2. foreach (Entity entity in Entity.allEntities) if (entity != this)
    3.         {
    4.             bool inRange = Vector3.Distance(transform.position, entity.transform.position) <= targetRange;
    5.             bool inList = entitiesInRange.Contains(entity);
    6.             if (inRange && !inList)
    7.                 entitiesInRange.Add(entity);
    8.             else if (inList && !inRange)
    9.             {
    10.                 if (target == entity)
    11.                     target = null;
    12.                 entitiesInRange.Remove(entity);
    13.             }
    14.         }
     
  13. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,606
    That's actually not a lot for any modern CPU. Your point still stands tho, as with 1000 entities or the likes, this would be imperformant. As i mentioned above using colliders (or rather triggers) should have a way better performance than manually doing the checks. Other than that, you could implement your own solutions to reduce the amounts of checks via utilizing a more efficient data structure - such as an Octree.
     
  14. RoeeHerzovich

    RoeeHerzovich

    Joined:
    Apr 12, 2020
    Posts:
    103
    I know... this is why I wanted it at first
    But OnCollisionEnter/Exit only work with collider AND NON-KINETIC rigidbody(at least so it says in the docs)

    and my Entities are not based on that (Player on Character controller and AI on NavMesh)
     
  15. RoeeHerzovich

    RoeeHerzovich

    Joined:
    Apr 12, 2020
    Posts:
    103

    I am now looking at what Octrees are and I kinda understand that but...
    How is that structure faster?
     
  16. RoeeHerzovich

    RoeeHerzovich

    Joined:
    Apr 12, 2020
    Posts:
    103

    And about it not being a lot... I know, but I just wanted to make the point of how quickly those numbers grow, the formula is
    f(x) = x^2 - x

    And like you said, maybe 50 is not all that much, but with many entities, this could definitely cause some problems

    Altho- I don't see myself putting 1000 entities in a single scene, and a smart thing would be to clear the entities list upon switching a scene. However, I do assure I'll get around... maybe a 100 at a time? Idk, but I can always add some despawning system so entities that are far away would despawn and respawn upon getting close to the area... I guess
     
  17. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,606
    Where have you gotten this from? The documentation itself specifically gives an example of using a collider and a rigidbody with isKinematic turned on. https://docs.unity3d.com/ScriptReference/Collider.OnTriggerEnter.html

    Through the Octree you know which objects are close to each other, so you only need to check the distance to objects in the cells around you (depending on the checked distance). Obviously maintaining the tree is not free either, but it's cheap compared executing O(n^2) checks on thousands of objects. And pretty fast in general too. If you are having problems understanding the benefits of Octrees, this would be a great place to start: https://www.wobblyduckstudios.com/Octrees.php

    I know. Computer scientists like using the O-notation to indicate runtimes. The above would be known as O(n^2), which is read as quadratic runtime. So yeah, not exactly optimal for anything but small values of n. Still, for small values such as 50 or 100 it can still be fine, so do some testing. Chances are your CPU may not care, depending on the calculations done.

    With all of the above in mind, i can just recommend again to test triggers.
     
  18. RoeeHerzovich

    RoeeHerzovich

    Joined:
    Apr 12, 2020
    Posts:
    103

    I was just about to, until I asked the guy I'm working with, how many Entities he expects to have in a scene...

    he said not more than 30 maybe 40.... which means I'm all good, altho, a solution to this problem is definitely something many people would be interested in soo... if I'll find anything that's significantly better I'll say it. (I assume colliders are...)