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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question Optimizing movement for hundreds (1000+) objects

Discussion in 'Scripting' started by mikikubs, Oct 2, 2022.

  1. mikikubs

    mikikubs

    Joined:
    Apr 5, 2020
    Posts:
    14
    Hello, I am planning to release an Ants Simulator game on Android based on ants' pheromone search. I've optimized the game quite well, but I'm not sure what to do about this snippet of code, which runs every frame for hundreds of ants:
    desiredDirection = (desiredDirection + Random.insideUnitCircle * wanderStrength).normalized;

    Vector2 desiredVelocity = desiredDirection * maxSpeed;
    Vector2 desiredSteeringForce = (desiredVelocity - velocity) * steerStrength;
    Vector2 acceleration = Vector2.ClampMagnitude(desiredSteeringForce, steerStrength);

    velocity = Vector2.ClampMagnitude(velocity + acceleration * GameInput.simDeltaTime, maxSpeed);
    position += velocity * GameInput.simDeltaTime;

    zAngle = Mathf.Atan2(velocity.y, velocity.x) * Mathf.Rad2Deg;
    transform.SetPositionAndRotation(position, Quaternion.Euler(0, 0, zAngle));

    Sebastian Lague actually made this for his Ants project, and I've struggled to come up with anything better. It takes just 0.007 ms per ant per frame to execute, but adds up on Android with hundreds of ants. Would converting monobehaviours to normal classes or using DOTS help in this instance? Thanks for help :D
     
  2. Terraya

    Terraya

    Joined:
    Mar 8, 2018
    Posts:
    646
    Mono to plane C# classes, "yes 100%", since Monobehaviours get handled performance intensive by unity, having loads of them is not a good idea, especially in your case.

    using the ECS will ofc. help you by alot but you have to rewrite 90% of your game i would gues :)
     
    mikikubs and DevDunk like this.
  3. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,022
    how does Deep Profiler look in hierarchy view? (whats on the top)
     
    mikikubs and DevDunk like this.
  4. DevDunk

    DevDunk

    Joined:
    Feb 13, 2020
    Posts:
    4,457
    The simple way is to have 1 monobehavior act like a manager. Here have a (native) array of your ants and loop through them when needed.
    The first step to optimize after that is to use the job system and/or burst to improve performance by quite a bit.

    If you need a ton more performance ECS might get you there, but will take a lot more work.

    Random idea: If it's just positions, maybe using a compute shader might work as well to run the logic on the GPU?
     
    mikikubs likes this.
  5. mikikubs

    mikikubs

    Joined:
    Apr 5, 2020
    Posts:
    14
    I've already done that
    On pc definitely, but would this work on mobile? Thank you for your answer!
     
  6. mikikubs

    mikikubs

    Joined:
    Apr 5, 2020
    Posts:
    14
    Yeah, since the game is almost done, it doesn't really make sense to switch to ECS. I guess I'll try to convert this class to plane C#, although it's worth noting that there is only two Unity functions there: Start() and OnDestroy(), but I'm not sure if that changes anything. I don't use Update(), I think that's what counts the most
     
  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,623
    It comes down to simply understanding what is slow. It sounds like you're considering it's some MonoBehaviour vs "plane" C# class; the profiler will tell you this. So it's not clear if you're guessing based on a wet finger in the air or if the profiler has highlighted that this part is a big problem. You posted the code above so I can only presume that part is slow and have spun-up the profiler and it's screaming at you that this code is in the hot-path. :)

    If so then speeding it up means you need to understand why it's slow. In most cases this is because of cache misses and random memory access but also not utilising all the cores on the device which is easily done when using heap-allocated objects on the main-thread so "plain" C# classes doesn't fix this.

    If all the positions, velocity and steering values above were laid out in memory then you could not only blast through the data in a job but go wide and do it multi-core really quickly. No ECS required.

    This is the kind of stuff I was doing here as a test although that was using ECS, the actual movement stuff was just operating on plain arrays of data in a job:

     
  8. AnimalMan

    AnimalMan

    Joined:
    Apr 1, 2018
    Posts:
    1,164
    that’s the coolest thing I’ve seen in a long time
     
    MelvMay and mikikubs like this.
  9. mikikubs

    mikikubs

    Joined:
    Apr 5, 2020
    Posts:
    14
    This is from a deep profile on my pc with 1000 ants. UpdatePosition() takes around 2/3 of all processor power. It's hard to zoom more, but it seems that processor is busy with just vector multiplication, addition and normalization (2/3 of 0.006ms) and then with Atan2, then Euler.(1/3 of 0.006ms).
     
    MelvMay likes this.
  10. mikikubs

    mikikubs

    Joined:
    Apr 5, 2020
    Posts:
    14
     
  11. mikikubs

    mikikubs

    Joined:
    Apr 5, 2020
    Posts:
    14
    Very cool indeed!
     
  12. mikikubs

    mikikubs

    Joined:
    Apr 5, 2020
    Posts:
    14
    I'll try using plain arrays of data in a job. I was thinking about that actually, but didn't do it yet. Thank you! Do jobs work on mobile as well as on a pc?
     
    MelvMay likes this.
  13. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,623
    Yes, they work on all platforms.

    It certainly seems like you'd benefit from raging through a bunch of arrays for sure. If you take out the actual code in that update, I'd be curious to see what the overhead is just calling an empty function i.e. figuring out the overhead split between all the calls vs what the calls do. :)

    EDIT: Oh I see, you're calling that from a central manager. I'd say then yes, go wide in a job!!
     
    mikikubs likes this.
  14. AnimalMan

    AnimalMan

    Joined:
    Apr 1, 2018
    Posts:
    1,164
    Here is a similar example, but this all happens on the main thread via specific and careful frame counting and control


    The map and its iterations can get large, from algae reproduction, continent growth, shift, etc.



    Same concept applies. I started threading this beast. But there were some minor design flaws in making a fun strategic game out of it :)
     
    mikikubs and MelvMay like this.
  15. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,623
    Yes, that's also a really good and often overlooked strategy to distribute updates over time in batches. Obviously it's not always appropriate but looks like a good approach above for sure!
     
    DevDunk and AnimalMan like this.
  16. AnimalMan

    AnimalMan

    Joined:
    Apr 1, 2018
    Posts:
    1,164
    Garbage management* was the key. Large debuff to the frame was painting the half triangle textures. If not filming it then it’s pretty stable fps around 200 or so. Lots of compute happening. Wind zones etc.
     
    MelvMay likes this.
  17. mikikubs

    mikikubs

    Joined:
    Apr 5, 2020
    Posts:
    14
    Seems very interesting! Out of curiosity, what does "frame counting and control" mean?
     
  18. mikikubs

    mikikubs

    Joined:
    Apr 5, 2020
    Posts:
    14
    Ok, I'll go in wide! Thank you for your help :D
     
  19. AnimalMan

    AnimalMan

    Joined:
    Apr 1, 2018
    Posts:
    1,164
    So it’s just an int that you count and cap and reset to zero, a numerator. You then ask if your CurrentFrame = DesiredNumber and do some logic. You reset your int back to zero when a full revolution of logic is complete
     
    mikikubs likes this.
  20. mikikubs

    mikikubs

    Joined:
    Apr 5, 2020
    Posts:
    14
    Oh, ok, pretty cool! Thanks for the explanation