JavaScript Circle Collision Detection Bug

时间:2013-09-05 15:48:29

标签: javascript geometry 2d collision

我在我的圈子/球碰撞模拟中得到了这个奇怪的错误,我正在做一个学校项目。我还可以补充说,我有点像菜鸟,我已经编程了大约一年。

碰撞工作正常,直到我用很多圆圈填充画布。我真的不明白为什么。 25个圆圈工作正常,但是当我达到50个圆圈时,圆圈开始出现问题。

正如你在下面的链接中所看到的那样,在经过一段时间并像疯了一样旋转之后,圆圈开始相互连接,这不是我想要发生的事情。

50圈的例子: https://dl.dropboxusercontent.com/u/9069602/circles/vers1/collisions.html

我的猜测是,随着它们之间的空间减小,圆圈相互连接的风险会更大,但是在开始模拟时它们似乎有足够的空间。我使用nextY / nextX位置变量来计算实际影响发生前一帧的影响。这也可能是错误的根源。我无法指出要开始调试。

以下是50圈案例的代码: https://dl.dropboxusercontent.com/u/9069602/circles/vers1/circle.js

// Returns true if two circles are overlapping
function overlapDetection( circle1, circle2 ) {
    var returnValue = false;
    var dx = circle1.nextX - circle2.nextX;
    var dy = circle1.nextY - circle2.nextY;
    var distance = ( dx * dx + dy * dy );

    if ( distance <= ( circle1.radius + circle2.radius ) * ( circle1.radius + circle2.radius ) ) {
        returnValue = true;
    }
    return returnValue; 
}

function collide() {
    var circle;
    var testCircle;
    var returnValue = false;

    for ( var i = 0; i < circles.length; i += 1 ) {
        circle = circles[i];
        for ( var j = i + 1; j < circles.length; j += 1 ) {
            testCircle = circles[j];
            if ( overlapDetection( circle, testCircle ) ) {
                collideCircles( circle, testCircle );
                collideCircle1 = circle.id;
                collideCircle2 = testCircle.id;
                returnValue = true;
            }
        }
    }
    return returnValue;
}

function collideCircles( circle1, circle2 ) {

    var dx = circle1.nextX - circle2.nextX;
    var dy = circle1.nextY - circle2.nextY;
    var collisionAngle = Math.atan2( dy, dx );

    var speed1 = Math.sqrt( circle1.velocityX * circle1.velocityX + circle1.velocityY * circle1.velocityY );
    var speed2 = Math.sqrt( circle2.velocityX * circle2.velocityX + circle2.velocityY * circle2.velocityY );

    var direction1 = Math.atan2( circle1.velocityY, circle1.velocityX );
    var direction2 = Math.atan2( circle2.velocityY, circle2.velocityX );

    var rotatedVelocityX1 = speed1 * Math.cos( direction1 - collisionAngle );
    var rotatedVelocityY1 = speed1 * Math.sin( direction1 - collisionAngle );
    var rotatedVelocityX2 = speed2 * Math.cos( direction2 - collisionAngle );
    var rotatedVelocityY2 = speed2 * Math.sin( direction2 - collisionAngle );

    var finalVelocityX1 = ( ( circle1.mass - circle2.mass ) * rotatedVelocityX1 + ( circle2.mass + circle2.mass ) * rotatedVelocityX2 ) / ( circle1.mass + circle2.mass );
    var finalVelocityX2 = ( (circle1.mass + circle1.mass ) * rotatedVelocityX1 + ( circle2.mass - circle1.mass ) * rotatedVelocityX2 ) / ( circle1.mass + circle2.mass );

    var finalVelocityY1 = rotatedVelocityY1;
    var finalVelocityY2 = rotatedVelocityY2;

    circle1.velocityX = Math.cos( collisionAngle ) * finalVelocityX1 + Math.cos( collisionAngle + Math.PI / 2 ) * finalVelocityY1;
    circle1.velocityY = Math.sin( collisionAngle ) * finalVelocityX1 + Math.sin( collisionAngle + Math.PI / 2 ) * finalVelocityY1;
    circle2.velocityX = Math.cos( collisionAngle ) * finalVelocityX2 + Math.cos( collisionAngle + Math.PI / 2 ) * finalVelocityY2;
    circle2.velocityY = Math.sin( collisionAngle ) * finalVelocityX2 + Math.sin( collisionAngle + Math.PI / 2 ) * finalVelocityY2;

    circle1.nextX += circle1.velocityX;
    circle1.nextY += circle1.velocityY;
    circle2.nextX += circle2.velocityX;
    circle2.nextY += circle2.velocityY;
}

我希望我能清楚这个问题。

提前致谢!

2 个答案:

答案 0 :(得分:1)

你的问题是双重的。

您的collideCircles(circle1, circle2)假定circle1circle2将在下一个坐标处发生碰撞,这由collide()保证,并且不会在当前坐标中发生碰撞(请参阅如何计算{ {1}}),这可能根本不是真的。这就是为什么你的圈子如果彼此叠加就会“卡住”的原因。

如果collisionAnglecollideCircles(circle1, circle2)反弹collideCircles(circle3, circle4)circle2,那么圈子可能会相互叠加,这样他们的下一个坐标就会相互叠加。然而,碰撞检测循环已经越过它们并且它们的碰撞将不被拾取并且圆圈将愉快地彼此重叠。

答案 1 :(得分:0)

让我们假设你开发了一个铰链接头! =) 实际上可能有几个问题。 例如:当你检查一个自由空间时,另一个圆圈已经占据了它; 我认为这种情况是下一个: 我们假设有两个圆圈

r=1; y =0;
circle1.x = 1, circle2.x =4;

检查下一步:

circle1.canMoveToX(2) //=> true; coz border will move to x=3 it's empty at the moment;
circle2.canMoveToX(3)  // => true; coz border will move to x=2 it's empty at the moment;

并且在这一步他们加入。