Search code examples
javascripthtmlhtml5-canvascollision-detection

Ball to ball elastic collision: ball bounces in an unequal proportion


I've been working on a game that requires ball to ball collision and I can't seem to find any solution for this problem, I almost get the collision as the balls are going into the correct directions but messes up the velocity.

Once the balls hits each other, the horizontal(x) bounces off very hard while the vertical(y) bounces off very softly. I have no idea what is the cause or causes of this, I tried to reduce the x-velocity by dividing but that means it won't be in proportion to the y value.

This is my code for the collision:

function resolveCollision(b1, b2){
    var dot = function(v1, v2) {
        return v1.x * v2.x + v1.y * v2.y;
    };
    v1x = b1.vx/2
    v2x = b2.vx/2
    v1y = b1.vy
    v2y = b2.vy
    var length = function(v) {
        return Math.sqrt(v.x * v.x + v.y * v.y);
    };

    var delta = {x: b1.x - b2.x, 
                 y: b1.y - b2.y};
    var d = Math.sqrt((delta.x * delta.x) + (delta.y * delta.y));
    var dn = {x: delta.x / d,
              y: delta.y / d}

    var dt = {x: dn.y,
              y: -dn.x};
    if (d === 0){
        b2.x += 0.01;    
    }
    var m1 = b1.m;
    var m2 = b2.m;
    var M = m1 + m2;

    var mt = {x: dn.x * (b1.r + b2.r - d),
              y: dn.y * (b1.r + b2.r - d)};

    b1.x = b1.x + mt.x * m2 / M
    b1.y = b1.y + mt.y * m2 / M
    b2.x = b2.x + mt.x * m1 / M
    b2.y = b2.y + mt.y * m1 / M

    var v1 = {x: v1x, y: v1y};
    var v2 = {x: v2x, y: v2y};

    var v1n = {
        x: dn.x * (v1.x * v1.x + dn.y * dn.y),
        y: dn.y * (v1.x * v1.x + dn.y * dn.y)
    };

    var v1t = {
        x: dt.x * (v1.x * v1.x + dt.y * dt.y),
        y: dt.y * (v1.x * v1.x + dt.y * dt.y)
    };

    var v2n = {
        x: dn.x * (v2.x * v2.x + dn.y * dn.y),
        y: dn.y * (v2.x * v2.x + dn.y * dn.y)
    };

    var v2t = {
        x: dt.x * (v2.x * v2.x + dt.y * dt.y),
        y: dt.y * (v2.x * v2.x + dt.y * dt.y)
    };

    b1.velocity = {
        x: v1t.x + dn.x * ((m1 - m2) / M * length(v1n) + 2 * m2 / M * length(v2n)),
        y: v1t.y + dn.y * ((m1 - m2) / M * length(v1n) + 2 * m2 / M * length(v2n))
    };
    b2.velocity = {
        x: v2t.x - dn.x * ((m2 - m1) / M * length(v2n) + 2 * m1 / M * length(v1n)),
        y: v2t.y - dn.y * ((m2 - m1) / M * length(v2n) + 2 * m1 / M * length(v1n))
    };
    b1.vx = b1.velocity.x;
    b1.vy = b1.velocity.y;
    b2.vx = b2.velocity.x;
    b2.vy = b2.velocity.y;
}    

Also if anyone can tell me how to make a player(circle) pushes the ball further without bouncing off that would be great.

This is the files if anyone wants to have a look, everything is in app.js: https://www.mediafire.com/?d6dpqn1cmwzp756

Just for anyone who couldn't understand what I am trying to achieve, this is what I'm trying to replicate: http://www.haxball.com


Solution

  • 1) You should clarify your code, as it stands it is a bit complex, this is in itself a bug source.
    2) You're doing some strange things with v1n/t v2n/t : projecting + squaring the speed on X ...??? I didn't even try to understand the b1.velocity code. Ouch ! :-)

    So here your code with some simplifications : it is untested, but will hopefully help you solve your issue :

    function resolveCollision(b1, b2) {
        var v1x = b1.vx,
            v2x = b2.vx,
            v1y = b1.vy,
            v2y = b2.vy;
    
        // Collision vector
        var delta = {
            x: b2.x - b1.x,
            y: b2.y - b1.y
        };
        var d = length(delta);
    
        // Normalized collision vector
        var dn = {
            x: delta.x / d,
            y: delta.y / d
        }
    
        // Normalized tangent collision vector
        var dt = {
            x: dn.y,
            y: -dn.x
        };
    
        var m1 = b1.m;
        var m2 = b2.m;
        var M = m1 + m2;
    
        /*    
        // test those separation tricks in a second time
        if (d === 0) {
            b2.x += 0.01;
        }
        var mt = {
            x: dn.x * (b1.r + b2.r - d),
            y: dn.y * (b1.r + b2.r - d)
        };    
        b1.x = b1.x + mt.x * m2 / M
        b1.y = b1.y + mt.y * m2 / M
        b2.x = b2.x + mt.x * m1 / M
        b2.y = b2.y + mt.y * m1 / M
        */
    
        // projection of v1 on the collision vector
        var v1Proj = {
            n: dn.x * v1x + dn.y * v1y,
            t: dt.x * v1x + dt.y * v1y
        };
    
        // projection of v2 on the collision vector
        var v2Proj = {
            n: dn.x * v2x + dn.y * v1y,
            t: dt.y * v2x + dt.y * v2y
        };
    
        // solving collision on the normal
        var newV1ProjN = ((m1 - m2) * v1Proj.n + 2 * m2 * v2Proj.n) / M;
        var newV2ProjN = ((m2 - m1)* v2Proj.n + 2 * m1 * v1Proj.n) / M;
    
        // re-building speed vector out of projected vectors
        b1.vx = newV1ProjN * dn.x + v1Proj.t * dt.x;
        b1.vy = newV1ProjN * dn.y + v1Proj.t * dt.y;
    
        b2.vx = newV2ProjN * dn.x + v2Proj.t * dt.x;
        b2.vy = newV2ProjN * dn.y + v2Proj.t * dt.y;
    }
    
    function dot(v1, v2) {
        return v1.x * v2.x + v1.y * v2.y;
    };
    
    function length(v) {
        return Math.sqrt(v.x * v.x + v.y * v.y);
    };