I have about 100 circle colliders set to dynamic/continuous. They’re all being dropped into a “hopper” at the start of the level.
I’ve noticed that this is:
A) Tremendously expensive (as I guess I should expect? But it’s only 100 balls so that seems low).
B) Tremendously jittery (the balls jitter and sometimes slip outside of the hopper, impossibly)
When I switch all the balls to discrete, they behave correctly and become much less expensive in the profiler.
I understand continuous being more expensive, but I don’t understand why there would be more jitter and tunnelling in continuous mode than in discrete.
Does anyone have any idea what might be going on?
Gravity is set to 60 and is being manually being applied like this:
float gravityMagnitude = Mathf.Abs(currentGravity) * rigidBody2D.mass;
Vector2 gravityForce = currentGravityDirection.DirectionVector * gravityMagnitude;
rigidBody2D.AddForce(gravityForce);
The mass of each ball is ~1.
Interesting. I concur that I observe this behavior. I assume it has to do with some underlying function of Box2D that just reaches a saturation point much sooner when in continuous mode.
One might infer that the intent of continuous isn’t to be accurate so much as it is to handle very fast objects and keeping them from sampling through each other purely due to speed…?
My code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// @kurtdekker: experimenting based on this forum post:
//
// https://discussions.unity.com/t/continuous-collision-jitter/1588157
//
// Discrete can easily support 1000+ balls
//
// Continuous chokes out after a few hundred and has much more penetration.
public class Ball2DFizz : MonoBehaviour
{
[Header("Rigidbody2D and CircleCollider2D and Sprite:")]
public Rigidbody2D BallExample;
[Header("Count output:")]
public TextMesh CountText;
Transform spawn1, spawn2;
void Start()
{
BallExample.gameObject.SetActive(false);
spawn1 = transform.GetChild(0);
spawn2 = transform.GetChild(1);
CountText.text = "";
}
const int FPS = 30;
float lastTime;
float SweepRate;
float ColorRate;
int count;
void SpawnBall()
{
// random?
float fraction = Random.value;
// sweep back and forth
if (SweepRate == 0)
{
SweepRate = Random.Range(1.0f, 4.0f);
}
float t = Time.time * SweepRate;
fraction = Mathf.PingPong(t, 1.0f);
Vector3 pos = Vector3.Lerp(spawn1.position, spawn2.position, fraction);
var copy = Instantiate<Rigidbody2D>(BallExample, pos, Quaternion.identity);
float scale = Random.Range(0.2f, 0.4f);
copy.transform.localScale = Vector3.one * scale;
copy.mass *= scale * scale;
// fun trick: make every 50th ball (or so) have 10x or 100x the mass!
if (Random.value < 0.02f)
{
copy.mass *= Random.Range(100, 200);
}
// half and half?
//copy.collisionDetectionMode = Random.value < 0.5f ? CollisionDetectionMode2D.Discrete : CollisionDetectionMode2D.Continuous;
copy.collisionDetectionMode = CollisionDetectionMode2D.Discrete;
copy.gameObject.SetActive(true);
if (ColorRate == 0)
{
ColorRate = Random.Range(0.1f, 1.0f);
}
float hue = Time.time * ColorRate;
hue %= 1.0f;
Color c = Color.HSVToRGB(hue, 1, 1);
var sr = copy.GetComponentInChildren<SpriteRenderer>();
sr.color = c;
count++;
CountText.text = count.ToString();
}
void Update()
{
float time = Time.time;
// only spawn as long as we haven't dogged
if ((time - lastTime) < 1.0f / FPS)
{
SpawnBall();
}
lastTime = time;
}
}
1 Like
Box2D v2 continuous collision detection is extremely expensive. In Box2D v3 it’s so cheap that it’s automatically activated if a body is moving fast and deactivated when it slows.
Likely the simulation is exploding because it’s a single island of contacts with lots of varying masses and that’s difficult for the solver. Having the same/similar mass is better and/or increasing the solver iterations but increasing iterations will just make it slower.
Compare that with v3 here at the start of the video: https://youtu.be/ksKVvwvpXX4?si=xqZ4_xLEnnuZdl4v
Looking forward to this being the default. 
2 Likes
Thanks very much to you both for the information! Good to know this is expected behavior.
@MelvMay any idea when V3 will be coming to Unity?
We’d like to introduced v3 as a low-level offering during the Unity 6 cycle as the first phase but we’re currently planning on how and when to replace the existing components as a second phase, as it involves breaking changes which need to be carefully coordinated.
v3 is quite different to v2 so the API and behaviours will need to change, for the better.
No specific dates I’m going to put my name on though. 
1 Like