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.
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
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
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
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?
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
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.
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
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.
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.
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):
f
foreach (Entity entity in Entity.allEntities) if (entity != this)
{
bool inRange = Vector3.Distance(transform.position, entity.transform.position) <= targetRange;
bool inList = entitiesInRange.Contains(entity);
if (inRange && !inList)
entitiesInRange.Add(entity);
else if (inList && !inRange)
{
if (target == entity)
target = null;
entitiesInRange.Remove(entity);
}
}
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.
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
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.
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…)