简体   繁体   English

JavaScript Circle碰撞检测错误

[英]JavaScript Circle Collision Detection Bug

I got this wierd bug in my circle/ball collision simulation I'm doing as a school project. 我在做学校项目时所做的圆圈/球碰撞模拟中遇到了这个奇怪的错误。 I may also add that I'm somewhat of a noob, I've been programming for about a year. 我可能还会补充一点,我有点菜鸟,我已经编程了大约一年。

The collisions are working fine until i populate the canvas with lots of circles. 直到我在画布上填充了很多圆圈之后,这些碰撞才能正常工作。 I can't really see why. 我真的不明白为什么。 25 circles is working fine but when I go up to 50 the circles starts to get buggy. 25个圆圈可以正常工作,但是当我增加到50个时,圆圈开始变得越野车。

As you can see in the link below the circles start to attach to one another after running some time and spinning around like crazy, which is not something I's like to happen. 正如您在下面的链接中看到的那样,经过一段时间并像疯了似的旋转后,圆圈开始相互依存,这不是我想发生的事情。

Example of 50 Circles: https://dl.dropboxusercontent.com/u/9069602/circles/vers1/collisions.html 50个圆圈的示例: https : //dl.dropboxusercontent.com/u/9069602/circles/vers1/collisions.html

My guess is that the risk of circles attaching to one another is greater as the space between them decreases, but it seems they have enough space when starting the simulation. 我的猜测是,随着圆与圆之间的间距减小,圆彼此相接的风险更大,但似乎在开始模拟时它们具有足够的间距。 I use a nextY/nextX position variables to calculate an impact one frame before the actual impact is occurs. 我使用nextY / nextX位置变量在发生实际碰撞之前一帧计算碰撞。 That may also be a source of bugs. 这也可能是错误的来源。 I can't really point my finger at were to start debugging. 我真的无法将矛头指向开始调试。

Here is the code for the 50 circle case: https://dl.dropboxusercontent.com/u/9069602/circles/vers1/circle.js 这是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;
}

I hope I'm being clear about the problem. 我希望我对这个问题很清楚。

Thanks in advance! 提前致谢!

Your problem is two-fold. 您的问题有两个。

Your collideCircles(circle1, circle2) assumes circle1 and circle2 will be colliding at next coordinates, which is guaranteed by collide() and are not colliding in current coordinates (see how you calculate collisionAngle ), which may not be true at all. 您的collideCircles(circle1, circle2)假设circle1circle2将在下一个坐标处发生碰撞,这由collide()保证,并且不会与当前坐标发生碰撞(请参阅如何计算collisionAngle ),这可能根本不正确。 This is why your circles can get "stuck" if they get on top of each other. 这就是为什么您的圈子彼此重叠时会被“卡住”的原因。

Circles can end up on top of each other if, say collideCircles(circle1, circle2) and collideCircles(circle3, circle4) bounce circle2 and circle4 so that their next coordinates will be on top of each other. 如果说collideCircles(circle1, circle2)collideCircles(circle3, circle4)反弹circle2circle4以便它们的下一个坐标彼此collideCircles(circle1, circle2)则圆可以彼此collideCircles(circle1, circle2) However, the collision detection loop has already passed over them and their collision won't be picked and the circles will happily move on top of each other. 但是,碰撞检测循环已经越过了它们,它们的碰撞不会被拾取,并且圆圈将快乐地彼此重叠。

Let's assume you've developed a hinge joint! 假设您已经开发了铰链接头! =) Actually there could be several issues. =)实际上可能存在几个问题。 Eg: when you check for a free space, another circle can already occupy it; 例如:当您检查自由空间时,另一个圆圈已经可以占据它; I think that scenario is next: lets assume that two circles have 我认为接下来是这种情况:假设有两个圆圈

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

checking next step: 检查下一步:

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;

and at this step they join. 在这一步,他们加入了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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