Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Physics circle collisions popping and sliding against bounds

In Java, I'm writing a mobile app for Android to interact with some dynamic balls with some classes I wrote myself. Gravity is determined on the tilt of the phone.

I noticed when I have a bunch of balls bunched up in a corner that some of them will begin to jitter, or sometimes slide while colliding with other balls. Could this be because I'm executing steps in the wrong order?

Right now I have a single loop going through each ball to:

  • Sim an iteration
  • Check collisions with other balls
  • Check collisions against scene bounds

I should add that I have friction with the bounds and when a ball to ball collision occurs, just to lose energy.

Here's a portion of code of how collision is being handled:

    // Sim an iteration
    for (Ball ball : balls) {
        ball.gravity.set(gravity.x, gravity.y);

        if (ball.active) {
            ball.sim();

            // Collide against other balls
            for (Ball otherBall : balls) {
                if (ball != otherBall) {
                    double dist = ball.pos.distance(otherBall.pos);
                    boolean isColliding = dist < ball.radius + otherBall.radius;
                    if (isColliding) {
                        // Offset so they aren't touching anymore
                        MVector dif = otherBall.pos.copy();
                        dif.sub(ball.pos);
                        dif.normalize();
                        double difValue = dist - (ball.radius + otherBall.radius);
                        dif.mult(difValue);
                        ball.pos.add(dif);

                    // Change this velocity
                    double mag = ball.vel.mag();
                    MVector newVel = ball.pos.copy();
                    newVel.sub(otherBall.pos);
                    newVel.normalize();
                    newVel.mult(mag * 0.9);
                    ball.vel = newVel;

                    // Change other velocity
                    double otherMag = otherBall.vel.mag();
                    MVector newOtherVel = otherBall.pos.copy();
                    newOtherVel.sub(ball.pos);
                    newOtherVel.normalize();
                    newOtherVel.mult(otherMag * 0.9);
                    otherBall.vel = newOtherVel;
                    }
                }
            }
        }
    }
like image 268
Green Cell Avatar asked Feb 27 '16 15:02

Green Cell


2 Answers

If this is the only code that checks for interactions between balls, then the problem seems pretty clear. There is no way for a ball to rest atop another ball, in equilibrium.

Let's say that you have one ball directly on top of another. When you compute the acceleration of the top ball due to gravity, you should also be doing a collision check like the one you posted, except this time checking for dist <= ball.radius + otherBall.radius. If this is the case, then you should assume a normal force between the balls equal to that of gravity, and negate the component of gravity in line with the vector connecting the two balls' centers. If you fail to do this, then the top ball will accelerate into the bottom one, triggering the collision code you posted, and you'll get the jitters.

Similar logic must be used when a ball is in contact with a scene bound.

like image 198
Ken Clubok Avatar answered Sep 19 '22 19:09

Ken Clubok


Since I've been experimenting with my own Phys2D engine (just for fun), I know you're talking about. (Just in case - you may check my demo here: http://gwt-dynamic-host.appspot.com/ - select "Circle Collisions Demo" there, and corresponding code here: https://github.com/domax/gwt-dynamic-plugins/tree/master/gwt-dynamic-main/gwt-dynamic-module-bar).

The problem is in a nature of iterations and infinite loop of colliding consequences. When e.g. ball is reached the scene corner, it experiences at least 3 vectors of force: impulse of bounce from the wall, impulse of bounce from the floor and impulse of gravity - after you summarize all 3 impulses, reduce it according loosing energy algorithm, you have to have the new vector where your ball should be. But, e.g. this impulse directs it into wall - then you have to recompute the set of vectors again according to all the stuff: energy of bounce, impulses, gravity, etc. Even in case if all these impulses are small, you never get all of them 0, because of precision of doubles and your tolerance comparison constants - that because you have the "jitter" and "sliding" effects.

Actually, most of existing 2D engines have these effects one kind or another: you may see them here: http://brm.io/matter-js/demo/#wreckingBall or here: http://box2d-js.sourceforge.net/index2.html - they actually just make the small impulses to be absorbed faster and stop iterating when the whole system becomes more or less stable, but it is not always possible.

Anyway, I'd just recommend do not reinvent your own wheel unless it is just for your fun - or for your better understanding this stuff.

For last one (JFF) - here is good tutorial: http://gamedevelopment.tutsplus.com/tutorials/how-to-create-a-custom-2d-physics-engine-the-basics-and-impulse-resolution--gamedev-6331

For real things, I'd recommend to use the existing engines, e.g. Unity (https://unity3d.com/learn/tutorials/modules/beginner/2d/physics2d) or Box2d (http://box2d.org/)

Hope this helps.

like image 38
domax Avatar answered Sep 19 '22 19:09

domax