Search Unity

Resolved having 1000+ gameobjects with colliders, over 2 fps (2D)

Discussion in 'Scripting' started by SomeVVhIteGuy, Nov 29, 2022.

  1. SomeVVhIteGuy

    SomeVVhIteGuy

    Joined:
    Mar 31, 2018
    Posts:
    162
    IM working on a simulation project which is struggling to get off the ground.

    The current goal is getting an "Ant" bot that can
    -See ahead
    -determine where food gameobjects are
    -move to that food
    -interact with that food
    -Instantiate new ants after eating enough food (I know that isnt how ants work)

    I have achieved all these steps, but cannot have more than about 15 ants active at a time without frames plummeting. The Profiler tool shows me that alot of time (about 95%) is being spent on physics2D.

    As far as I know, physics should only be applying to 'ants' right now, as they are the only object with a rigidbody.

    If I had to guess where the problem is, its how my 'ant's see what is ahead of them.
    each ant has a child gamobject that is a collider, the ant stores any other colliders that enter and are a 'food', then removes them when they are no longer in sight.

    But I have no idea if this is actually the issue, or how I can even approach figuring out why physics is spiking so much. Its not the food (the only other go's in the scene with even a collider) because I removed them and got the same results
    Heres what the Profiler is showing me. its all good until some arbitrary number of ants have spawned, and then boom,
     
  2. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,605
    First of all, the gameobject workflow is not made for that many entities. However, thats not (yet) the problem here, since 15 ants is certainly way too low an amount to cause issues.
    (To allow for truly large amounts of entities, in the region of thousands plus, use DOTS. Which is by no means beginner friendly or easy to get into - so i dont recommend that unless you have to.)

    I'd like to see your code.. not sure how else i would be able to help you.

    Why are you not using raycasts for vision? Thats the most common approach.
    Also, reduce the amount of code in FixedUpdate to the absolute utmost bare minimum.
     
    DevDunk likes this.
  3. TzuriTeshuba

    TzuriTeshuba

    Joined:
    Aug 6, 2019
    Posts:
    185
    a couple things worth trying:
    1) replacing the single ant collider with multiple primitive colliders that acheive your shape
    2) in your physics settings, untick physics collision detections between the Ant colliders' layer with themselves. also the same for food on food collisions. Of course only if you dont need to detect those collisions.

    Also, what is happening before the giant spike in the profiler? instantiating 1 more ant? 100 more ants. 15 ants should not cause an issue as you described them.
     
  4. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,638
    Since this is on the CPU, If you select a heavy frame and scroll down, there should be a break down below of what API calls are made on a particular frame and what percentage of the run-time they took. Try to find out more info.
     
  5. SomeVVhIteGuy

    SomeVVhIteGuy

    Joined:
    Mar 31, 2018
    Posts:
    162
    Im looking into raycasting in order for 'ants' to "see" right now, will try to update how that goes.

    the ants currently have 1 polygon collider, I will replace it with a box collider, precision is not really needed here so idk why I didnt do that in the first place.

    I think I already have layers not colliding with themselves, thats in the collision matrix correct?

    and nothing of note is happening before the large spike, except spawning more ants. to test the breaking point of what im doing right now, I just have each ant spawning a new ant on a coroutine.
     
  6. SomeVVhIteGuy

    SomeVVhIteGuy

    Joined:
    Mar 31, 2018
    Posts:
    162
    I dont exactly know how to read the information. and cannot upload the profiler data here, the file size is too large.
    if im looking at the correct module, i THINK there is a spike in 'contacts' at the same time as new ants are added to the scene. so maybe the ants are hitting each other as they are created and causing a large spike of physics interactions?
     
  7. SomeVVhIteGuy

    SomeVVhIteGuy

    Joined:
    Mar 31, 2018
    Posts:
    162
    would you happen to have a good way to do multiple small angle raycasts? most things covering it just use transform.right or .up but that doesnt help me much, this is more of a topdown view and would need small adjustments and im not sure how to go about that
     
  8. Trindenberg

    Trindenberg

    Joined:
    Dec 3, 2017
    Posts:
    398
    Colliders/raycasts work with minimal objects say <100, for anything higher you should think abstract. You need to compare objects that are close to each other. In that sense if 2 objects pass an axis distance threshold, you only have 2 colliders for each specific comparison A/B, and you could, to save math, just turn on some colliders for close objects where collision is relevant. As for method, not tried it, but interested to try at some point.
     
  9. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,605
    There is probably many aproaches to this. Since you have your ant as a starting location and a view radius, you could look for solutions for finding equally spaced points on a circle. You'd discard any that are not in the field of view of your ant (which you can do by calculating the angles). Now you'd have equally spaced raycasts within your field of view. You would however need to figure out a way so that you wouldnt have to calculate this every frame - but while thinking about that i realised you could probably just utilize a spherecast / overlapcircle, get all food items in the vicinity, and then calculate the angle to those to determine whether they are in the field of view or not. That should be comparably cheap and easy to implement. I then also found this video where Sebastian Lague did just that, fittingly, for an ant simulation:


    (5:35, since the Unity Forum appears to eat up youtube timestamps..)

    Also a general piece of advice, which might or might not be obvious: you are never the first to attempt something. So usually, for any given topic you want (at least to some degree) there will be articles, blogposts, tutorials or even scientific papers describing something that will help you, which you will likely find when googling for the broad topic itself, since others who attempted it would have had the same issues - or at least needed a solution that works aswell.
     
    SomeVVhIteGuy likes this.
  10. TzuriTeshuba

    TzuriTeshuba

    Joined:
    Aug 6, 2019
    Posts:
    185
    I would recommend first diagnosing EXACTLY where your performance issue lies. the time breakdown of function calls in the profiler should tell you. you can click on the time columns to order the rows by time spent if it isnt already.
    Then Try simple solutions.
    Then try solutions that require calculated backflips.
    15 ants with a collider should not demand clever workarounds. Ill have hundreds of 3D colliders and run on mobile without issue.
     
    Yoreki likes this.
  11. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,487
    Having lots of colliders, despite popular belief, doesn't cause any issues. The problem is the active part of that. Mostly this comes down to solving contacts. You don't need to upload large files from the profiler but also showing some spike in a graph isn't useful either. There's a 2D physics profile area that shows you lots of detail but even the CPU area shows you what specifically is taking time in the hierarchy view of it.

    In the end, you can use the fastest collision detection which is CircleCollider2D (circle vs circle is quickest) but it doesn't mean it'll help if the problem is somewhere else. Maybe you're doing what lots and lots of devs do which is not have a Rigidbody2D and modify the Transform because of the invented idea that it'll be somehow quicker when it's orders of magnitude slower. I'm not saying this is the issue or that you're doing it but in the end, you need to provide useful profile information.

    Do you have half a million contacts? Are contacts constantly being created because you're mashing Static colliders? Is it time taken in your physics callbacks because of your scripts? etc.

    Without the information, you'll get distracting guesses.

    EDIT: I can see you have "CompileContactCallbacks" selected when showing the view but that's all I can see. This suggests its time spent in the physics callbacks i.e. your scripts and not 2D physics itself.
     
    Yoreki and SomeVVhIteGuy like this.
  12. SomeVVhIteGuy

    SomeVVhIteGuy

    Joined:
    Mar 31, 2018
    Posts:
    162
    Just want to say im learnign alot in a small amount of time so thankyou guys for being very purposful with your responses, really knocking it out of the park here.

    is that true? yeah I absolutely have been modifying transform directly, specifically because I assumed having the rigidbody component would intrinsically be heavier.
     
  13. SomeVVhIteGuy

    SomeVVhIteGuy

    Joined:
    Mar 31, 2018
    Posts:
    162
    For reference my current code for having the ants 'see' using raycasts instead of the child colliders

    Code (CSharp):
    1.     public void see()
    2.     {
    3.         Vector3 sightEdge = transform.right * senseRange;
    4.         for (int Exx = -5; Exx <= 5; Exx++)
    5.         {
    6.             Vector3 sightPoint = sightEdge + (transform.up * Exx);
    7.             RaycastHit2D[] canSee = UnityEngine.Physics2D.RaycastAll(transform.position, transform.position + sightPoint, senseRange);
    8.             Debug.DrawLine(transform.position, transform.position +  sightPoint, Color.red);
    9.             foreach (RaycastHit2D Ell in canSee)
    10.             {
    11.                 if (Ell.collider.gameObject.GetComponent<Food>() != null && !plantsInSight.Contains(Ell.collider.gameObject.GetComponent<Food>()))
    12.                 {
    13.                     plantsInSight.Add(Ell.collider.gameObject.GetComponent<Food>());
    14.                 }
    15.             }
    16.         }
    17.         Invoke("see", 1f);
    18.     }

    which is working okay. Im sort of avoiding the actual issue which, after sleeping on it im convinced is from ants spawning other ants on top of themselves and causing an avalanche of collisions.

    I think i understand that if I just make the ants kinematic then they wont cause all those collisions?
     
  14. SomeVVhIteGuy

    SomeVVhIteGuy

    Joined:
    Mar 31, 2018
    Posts:
    162
    The immediate issue was in fact that the ants could collide with themselves, and when spawning in caused a huge amount of collisions while trying to separate from each other. Thats the original issue solved, updating the title
     
  15. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,487
    You're not the only one and it's a terrible assumption to make. Rule#1: Never modify the Transform when using 2D physics. Remember this and any other mistakes you make won't be fundamental ones.

    If you're seeing contacts then that's because they are set to collide with each other using the Layer Collision Matrix on the "Project Settings > Physics 2D" window. Yep, it's a common mistake to spawn a lot of things over the top of each other. Even 10 things on top of each other is 10 x 10 collisions but depending on the collider type that could be from 1 contact to dozens x 100 for no good reason.

    Make sure if you're spawning, spawn by passing in the position/rotation you want to the Instantiate call itself. Don't change the Transform after because you should NEVER modify the Transform when using 2D physics. That change won't even happen until the simulation runs anyway. Understand that Transform changes only change the Transform. It doesn't synchronously inform other systems that it's changed; they only know about that change when they run.

    No, don't try to simplify to rules like this, it creates misunderstandings. Yes, Kinematic does not by default create contacts with other Kinematic or Static but this isn't a reason to use it. You use Kinematic when you don't want forces to affect a body pose and you want to position it yourself. You don't do it to "stop gravity" or "stop contacting other things". Dynamic bodies contact all body types so setting Kinematic doesn't stop that.

    Choose a body-type for its intended purpose. Not for anything else. If you don't want types of things to contact the same types of things then use the Layer Collision Matrix. This is what it's for.
     
    Yoreki likes this.