I’m just starting out with Unity although I’ve managed to grasp enough UI & C# scripting concepts to create a functioning calculator application. I’m trying out different small ideas and one of them is making objects have independent random behavior (imagine gas molecules, or Sphere objects, moving around in a box). I don’t want to use Physics because I’d like to learn how to do this via C# (and as efficiently as possible).
I am trying to figure out the best way to handle proximity detection (e.g. have spheres change color when they are close to each other). Let’s say I have a Controller object and script which instantiates a certain number of Sphere objects in random locations and keeps the list of the objects in an array. I can go through the array from within the Controller object at each frame and check, for every sphere, the distance it has to other spheres in the array. But this seems to be very inefficient when the number of objects increases. I’d like to know if it’s possible to do that from within each sphere’s script and not have a Controller object at all (except for instantiating the spheres).
Is there a way to have a object check if there are other objects within a limited radius (or cube) around itself? I’m not expecting a working script as an answer, just some ideas and concepts.
You’re correct that checking for each square is a slow operation (to use big-o notation, it’s O(N^2), or relative to the square of the number of spheres) that gets slower with every additional sphere. However, you’re incorrect in that moving the code to the spheres’ script would change that. The engine will still need to loop through the spheres just like your manager would, and it’d still end up at the exact same level of efficiency. In fact, it would be a tiny bit (I mean, infinitesimally) slower, because there’s a little bit of overhead for every Update() function that gets executed by the engine.
There are a few options you could do to improve the efficiency.
Take advantage of physics. Create a trigger collider around each sphere, and use OnTriggerEnter/Exit to change their colors. This would be an efficiency improvement because the physics engine is much more efficient than pretty much anything you or I would ever write (they’ve spent tens of thousands of manhours optimizing their engine), plus the physics engine is multithreaded. In this case, the goals of “as efficiently as possible” and doing it via C# are mutually exclusive.
You can stagger the updates in your manager class so that it only checks X number of spheres per frame. e.g. index 0-10 in frame 1, then 11-20 in frame 2, then 21-30 in frame 3, etc, until you loop back around.
The most efficient way to compare positions is
float distSquared = (sphere1.transform.localPosition - sphere2.transform.localPosition).sqrMagnitude;
if (distSquared < range * range) {
The reason being that multiplying a number by itself is an order of magnitude faster than finding the square root (the last mathematical step of the distance formula).
You can optimize #2 by having two kinds of checks for each sphere:
a) A sphere checks against ALL other spheres, and stores their distance at that time. This one gets staggered through the frames as described.
b) A sphere looks at just the two neighbors who are closest to the range threshold. This happens every frame (except the frames in which a full update is done)
Thank you for taking the time to write such a detailed reply, which is what I was hoping for.
Just a couple of clarifications (apologies if this is newbie stuff, because it is):
In the case of Physics, say you want to do different things at different distances. Is it possible to attach multiple colliders to each object, set them to different radii, and run checks on the “closer” collider only when the “further” collider has been entered?
Why is the code you propose in Step 3 better than simply using Vector3.distance?
Staggering the checks is a very good suggestion if I can pull it off, because obviously each sphere doesn’t need to check all the others, only those which haven’t checked their own distance from it first!
You would have to put them on different GameObjects (as children of the main one), but yes. Do ensure that they’re all on a layer so they don’t collide with themselves (in fact, in physics settings, set that layer to collide ONLY with the layer the spheres themselves are on - big speed improvement).
if you want to make this faster you can go into space partitioning with OctTrees.
you can then simply change the color of each molecule based on the population within each node. since each node can have a predetermined size, you can avoid any distance calculation altogether. and since no longer need to compare between two molecules, you only have to iterate through each molecule at most twice (once to determine which node they are and only if their position changes, second to determine their color base on node’s population density).
instead of O(N^2) it becomes O(N). that’s drastically faster.
Thank you @JoshuaMcKenzie . I was thinking about partitioning the 3D space somehow but I had never heard of Octrees before. Found this article which makes for a nice read if someone’s interested. Thing is, it’s mostly about using octrees for collision detection which actually drives home @StarManta 's point: there is no point of rebuilding an entire physics engine from scratch when Unity gives you one for free, especially when you’re a beginner like me with more humble goals to be accomplished
BTW the article I mention also insists on comparing distances squared instead of calculating square roots, like @StarManta wrote. It’s something I’d never thought of before today…