Hello everybody. I am trying to make a simulator with a large numbers (ideally over +3000) of indipendent agents. Every agent has a rigidbody and a collider attached. The rigidbody is needed for movement using AddForce and the collider for collision with enemies. They also have material with friction = 0 to smooth movement. I am able to run it a +30 fps with over 700 agents, but I am aware that there is (and I will need it) a lot of room for improvement, in particular when there will be enemies, a more complex graphics (which is now very simple for prototyping purposes). The code for each agent is:
Which is the best way to optimize it? Remove rigidbodies/colliders, alter this code or make calculation simpler? I also tried InvokeRepeating instead of Update but it seems to make the game slower.
I am also thinking to move to 2D.
Any help is appreciated!
Looking at your code, specifically the Rotation method. Why are you geting the rigidbody component again? -You have a reference that you got in you Awake function. Just use that reference. That will stop the mass getcomponent calls every fixed update.
Secondly, if you are using a rigidbody you really shouldnt be touching the transform directly like you do in Rotation. Use rigidbody.MoveRotation instead. It will keep the physics engine happy.
Finally, this seems to be AI code right? Does it really need to be invoked every fixed update? Thats many times per second. Could you try it inside a coroutine and set that to update every 1 second or half a second? Play around until you get an update speed that is a good balance between gameplay and performance.
Thanks a lot for the reply. Sorry for the game tags, I was used to Unity answers where there is a direct icon. But I managed to find it also here.
Thank for the advices, in particular the first one was my mistake.
I will implement corountines as you suggest. Before I use InvokeRepeating but it seems slowering things.
I will post soon an update and thank you very much
Use the Profiler to see what slows your game down. Depending on your target platform, and how close each agent is to each other and obstacles (and your physics layer maps), 3000 agents with Rigidbodies are definitely doable.
Thanks everybody for all hints. I run the profiler, and as I imagined physics calculations are putting the cpu on the knees:
The big peak occurs after I spawned 1400 “cube agents” samples:
By the way, for simplicity and to test it, I just throw away the rotation function, so basically there is only a corountine which calls every 3 sec the random movement function adding force.
Any hints about this situation? I do not know if switching to 2d would be better, or doing something else. Actually the rigidbody is needed to detect collision between the agents and enemies and buildings. Maybe I should find a way to avoid collision detection only between “friends” agents?
Update: removing v-synch and changing Fixed timestep greatly improve performance.
I also switched to 2D agent and now I am able to have +2500 agents at 20fps.
I think what you could do to improve this much more is have group AI. Say one ai agent manages 3-4 units at one time. These units always move together in a similar direction. Could work?
I agree with Korno, however you can go a step further, create a manager class which caches and updates each instance. Also let the manager class call FixedUpdate and then manually call the fixed update (with a different name) in your agent classes, this use to be alot quicker but may have changed with updates. Cache as many variables as possible and try not to create any “new” instances after the start. I would also ditch the physics movement and just calculate the new position and rotation in the update for each agent. If your still slow try processing less each frame e.g. process 1/2 the agents each frame but calculate their new positions twice the distance. This reduces the rotation calculations to half and to compensate the jerky effect this will create by lerping the movement.
Update: changed layer collision matrix to reduce collision: now civilians do not detect collisions among themselves, resulting in big improvement.
Thank you Korno for the idea. Yes, I think it could work. I will try to figure out how to set up random group size (let’s say 1 to 5 agents) at the beginning of the scene and let them follow “the leader”.
Also, thanks bajeo88 for all your tips. But what do you mean for a manager class to cache the agents? Do you mean add them to some list at the beginning of the scene when they spawn, and cycle through them?
Now the code for every agent is:
using UnityEngine;
using System.Collections;
public class civilian3D : MonoBehaviour {
Vector2 randomDirection;
public float speed = 2f;
Rigidbody rigidbody;
// Use this for initialization
void Awake () {
rigidbody = gameObject.GetComponent<Rigidbody>();
StartCoroutine("randomMovement");
}
IEnumerator randomMovement()
{
while(true){
randomDirection = Random.insideUnitCircle * 5;
rigidbody.AddForce(new Vector3(randomDirection.x, randomDirection.y, 0f));
yield return new WaitForSeconds(2f);
}
}
}
I am still testing both 2d and 3d for the moment. I followed your advice for collision detection with ground and restricted movement.
Done
By the way, thanks everybody. Now things are getting better, with +3000 agents (2d or 3d) running at 25fps on a tile map of 70x70 procedurally generated. If I restrict the view, I can also get 50/60!