A way to optimize moving a huge group of colliders at once

I’m making a 2D top down game where the player runs around and random segments will spawn so that they are constantly surrounded by a 3x3 group of segments giving the illusion of an endless map. These segments have a box collider and a huge amount of primitive colliders as child objects. (100-300 colliders per segment give or take) and a bunch of sprites. Here is an example of a segment:

I’m using an object pooling system with a total of 24 segments, 9 being used at a time and the rest off screen (disabling them caused a bigger spike than just moving them). No matter what method I try I can’t escape the massive physics.simulate spike. I’ve considered trying a mesh collider instead of primitives but that would require an enormous amount of work with all the segments I’ve already made and may not even help. Does anyone know a way to remove or reduce the spike caused by this? Note that I’ve tried having a kinematic ridgedbody on all colliders, just the parent colliders, and on none of the colliders and it doesn’t seem to make much of a difference.

Here’s the code that ‘generates’ the segments:

	IEnumerator GenSegments() {
		//Move all segments outside of the 3x3 box back into the segment pool (objects at y -1000 are in this pool)
		foreach (Transform OtherSeg in UseableSegments)
		{
			if (Vector3.Distance(CurrentSegment.position, OtherSeg.position) > 80 && OtherSeg.position.y > -500)
			{
				//Move the segment
				OtherSeg.position = new Vector3(0, -1000, 0);
			}
			//Stagnate the spike to avoid a frameskip
			yield return new WaitForFixedUpdate();
		}
		//CheckPos is used to check for existing segments before moving in a new one
		Vector3 CheckPos = new Vector3 (CurrentSegment.position.x + 50, 25, CurrentSegment.position.z);
		//Checks all 9 spots where a segment can be
		for (int A = 0; A < 8; A++)
		{
			if (!Physics.Raycast (CheckPos, Vector3.down, out SegmentRay, 30f, SegmentLayerMask))
			{
				//If there is no segment, grab a random one from the pool and move it to the empty spot
				Transform CurrentSeg = null;
				int RandomInt = Random.Range(0, 11);
				while (!CurrentSeg)
				{
					if (UseableSegments[RandomInt].position.y < -500) CurrentSeg = UseableSegments[RandomInt];
					else {
						RandomInt++;
						if (RandomInt > 11) RandomInt = 0;
					}
				}
				//Move the segment
				CurrentSeg.position = new Vector3(CheckPos.x, 0, CheckPos.z);
			}
			//Used to move CheckPos to the next segment spot
			if (A == 1 || A == 2){
				CheckPos.x -= 50;
			} else if (A == 3 || A == 4){
				CheckPos.z -= 50;
			} else if (A == 5 || A == 6){
				CheckPos.x += 50;
			} else if (A == 0){
				CheckPos.z += 50;
			}
			//Stagnate the spike to avoid a frameskip
			yield return new WaitForFixedUpdate();
		}
	}

I am using 3D colliders as I found that most of the 2D features did not have top down games in mind and that made things difficult. All movement is based on raycasting so there is no actual physics. I would greatly appreciate any help you gives can give.

Hi, a physics engine uses some optimizations to reduce the number of collisions tests it makes. Those optimizations rely on structures that are fast to do some things, but slow to do some other things. You can read more about this here : jitter-physics.com.

In your case, I believe when you move a segment, the physics internal structs must be updated for lots of colliders in the same frame so it causes a spike. Enabeling + disabeling colliders usually causes the same structure update. You can read Unity’s blog about physics in Unity 5.0 here: High-performance physics in Unity 5 | Unity Blog it explains some of this stuff. Hopefully, Unity 5 could fix your problem, you may be able to ask for a beta to check if it does, and then maybe you can live with the spikes until 5.0 is released.

Another way to fix this would be to reduce the number of active colliders. Your map has some kind of islands of those colliders, maybe you can regroup each island under a bigger sphere that would be a trigger (this sphere object would have childs containing colliders). When your player enters that trigger, it enables all the childs colliders it contains (and disable them when exiting). This way, you would force the physics system to update its internal structs very often, but only with a limited amount of colliders and this should not “spike”. Also, as all the colliders from other segments would be disabled (except the few triggers), I think the spike of moving them should disappear. This is the same kind of “divide & conquer” thing physics engine broadphase does, but made specific to your game.

This solution may not work if you have lots of other objects that must raycast on those spheres, like enemies. They would also have to trigger enabeling/disabeling lots of colliders and this could lead to other spikes. If this is the case, I would switch to the 2D colliders system as it is faster (I’m sure you can write an editor script that could “convert” all your 3D objects in 2D).

When you are moving, you will have to move 1 object every frame or 2, so put a yield wait for fixed update line or wait for seconds in the loop that finds what to move. actually, find what to move, and every time the loop finds a moveable, add 1 to a var called moveable delay, multiply the process time that actually moves the object by that incremental number, so you can run teh compare move loop in 1 frame but actually move teh objects in 100 frames say.

so you never move more than 1 object ever 0.02 seconds for example.