简体   繁体   中英

In a physics simulation in JS, a moving ball is 'trapped' by a fixed ball and can't escape, instead of bouncing off

The program is a variation based on lesson 3 of "10 minutes physics" by Matthias Müller.

That lesson is a simple billard where balls interact and bounce off one another. See demo here of the original (unmodified) code .

The modifications include using SVG, and the possibility to add balls (by clicking on the page) and change them into fixed obstacles (by clicking on them); it's also possible to pause the simulation, which makes it easier to catch a moving ball.

It works generally well, but in some cases a moving ball becomes "trapped" by a fixed one, and can't escape.

See the JSFiddle here ; when one clicks "run" on the fiddle the red ball moves a little and then becomes immediately trapped by the black ball. (It happens naturally; the fiddle is just a setup to reproduce the bug systematically. On the fiddle it's also possible to add more balls by clicking anywhere.)

The collision code is as follows (line 157+ in the fiddle):

function handleBallCollision(ball1, ball2, restitution) {
    const   pushVel = 2.0;
    const   dir = new Vector2();
    dir.subtractVectors(ball2.pos, ball1.pos);
    const   d = dir.length();
    const   rsum = ball1.radius + ball2.radius;
    if (d == 0.0 || d > rsum) return;

    dir.scale(1.0 / d);
    let     corr = (ball1.radius + ball2.radius - d) / 2.0;

    if (ball1.isMoving == 0 || ball2.isMoving == 0) {
        const ball = ball1.isMoving == 0 ? ball2 : ball1;

        ball.pos.add(dir, corr);
        var v = ball.vel.dot(dir);
        ball.vel.add(dir, pushVel - v);
        }
    // else handle case of two balls moving...

The general principle is that we test the proximity of two balls; if their distance ( d ) is smaller than the sum of their radii, they are in contact and should move apart.

Of course if one of the balls is fixed then only the other moves.

Once two balls have been in contact, their distance should start growing again; in the case of the bug, the distance keeps getting smaller.

This has something to do with the dir and corr vectors but I don't understand why it works in the general case, and sometimes fail.

There are some issues with the signs in line 177 and 180. Hence the above portion should read as follows. A working fiddle can be found here: https://jsfiddle.net/x47fv9te/

function handleBallCollision(ball1, ball2, restitution) {
    const   pushVel = 2.0;
    const   dir = new Vector2();
    dir.subtractVectors(ball2.pos, ball1.pos);
    const   d = dir.length();
    const   rsum = ball1.radius + ball2.radius;
    if (d == 0.0 || d > rsum) return;

    dir.scale(1.0 / d);
    let     corr = (ball1.radius + ball2.radius - d) / 2.0;

    if (ball1.isMoving == 0 || ball2.isMoving == 0) {
        const ball = ball1.isMoving == 0 ? ball2 : ball1;

        ball.pos.add(dir, -corr); // minus added
        var v = ball.vel.dot(dir);
        ball.vel.add(dir, -pushVel - v); // minus added
        }
    // else handle case of two balls moving...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM