Okay, I have up to 1 000 circles on a 2D plane (no gravity, it’s a top-down view). They can collide with each other and with axis-aligned square walls. All is fine when there are just a few objects colliding, but when too many objects start to pile up it starts to vibrate and eventually random circles are ejected from the center or fly around randomly. To prevent this I added a “smoothness” to collisions, which allows units to be compressed instead of completely pushing away other objects and themselves. This improved things, but too many circles stacked together can be very compressed, which looks like crap, since they start to melt together.
I had an idea of dynamically adapting the smoothness value depending on how many other things a circle is colliding with, but I realized that this would reduce the position correction when more circles are close together, leading to even more compression, and I would end up with the worst of both low smoothness and high smoothness. Clearly I need a different solution.
I’ve thought of using Box2D and just let it solve all collisions, but the problem is that I have potentially millions of static wall squares, and JBox2D just crashes when I go over 2048 shapes.
My current implementation does this:
for(Circle circle1 : allCircles){
List<Circle> nearbyCircles = getCollidingCircles(circle1, ...);
if(nearbyCircles.isEmpty()){
continue;
}
for(Circle circle2 : nearbyCircles){
double dx = circle1.x - circle2.x;
double dy = circle1.y - circle2.y;
double distance = Math.sqrt(dx*dx + dy*dy);
double distanceToAdd = circle1.radius + circle2.radius - distance;
double multiplier = distanceToAdd / distance * SMOOTHNESS; //SMOOTHNESS is less than or equal to 1
circle1.deltaX += dx * multiplier;
circle1.deltaY += dy * multiplier;
}
movedCircles.add(circle1);
}
while(!movedCircles.isEmpty()){
Circle c = movedCircles.remove(movedCircles.size() - 1);
c.x += c.deltaX;
c.x += c.deltaY;
c.deltaX = 0;
c.deltaY = 0;
}
THIS CODE IS COMPLETELY REWRITTEN FOR THIS THREAD FOR CLARITY!!! Please do not bash any performance problems or anything, as my actual code is completely different.
As you can see, I only update the position of one of the circles in a collision, but as the collisions will both collide with each other, they will both be pushed away by the same amount. This is not a performance problem either (getting around 300 FPS for 1000s of circles). I just need something with better collision response than what I have now.