0

我有这个奇怪的问题。我正在尝试编写一些 2d 碰撞并偶然发现碰撞检测程序。我决定尝试将其翻译成 javascript,并可能在此过程中学到一些东西。

问题是,当我在浏览器中运行它时,一旦两个圆圈发生碰撞,所有圆圈就会冻结在原地,但程序不会崩溃,我在控制台中也没有错误。

我试图调试它,我认为问题出在 checkForCollision 函数中的第一个 if 语句中。就像它总是假的一样。

这是原始版本的链接(向下滚动到“清单 3”以获取完整代码): http ://compsci.ca/v3/viewtopic.php?t=14897&postdays=0&postorder=asc&start=0

这是我的翻译:

var canvas = document.getElementById('canvas01');
var drawFps = document.getElementById('fps');
var context = canvas.getContext('2d');

// The amount of delay between frames
var delay = 50;

// The maximum distance two circles can be apart and still be considered colliding
var epsilon = 10^-9;

// The number of circles
var numCircles = 5;

// We anticipate many circles so we create an array
var circles = new Array();

// Stores the amount of time untill a collision occurs
var t;

// Initialize the circles
createCircle();

function createCircle() {
    for(var i = 0; i < numCircles; i++) {

        var velX = Math.floor(Math.random() * 5) + 1; // this will get a number between 1 and 5;
        velX *= Math.floor(Math.random() * 2) == 1 ? 1 : -1; // this will add minus sign in 50% of cases
        var velY = Math.floor(Math.random() * 5) + 1;
        velY *= Math.floor(Math.random() * 2) == 1 ? 1 : -1;
        var radius = Math.floor(Math.random() * 30) + 15;
        var mass = Math.PI * Math.pow(radius, 2);

        circleData = {
            x : Math.floor(Math.random() * canvas.width),
            y : Math.floor(Math.random() * canvas.height),
            vx : velX,
            vy : velY,
            vxp : velX,
            vyp : velY,
            r : radius,
            m : mass
        }
        circles.push(circleData);
    }
}

setInterval(loop, 17);

// Returns the amount of frames untill a collision will occur
function timeToCollision() {
    var t = Number.MAX_VALUE;
    var A;
    var B;
    var C;
    var D;
    var DISC;

    // Loop through every pair of circles and calculate when they will collide
    for(var i = 0; i < circles.length; i++) {       

        for(var j = 0; j < circles.length; j++) {           

            if(movingToCircle (circles[i], circles[j])) {

                // Breaking down the formula for t 
                A = Math.pow(circles[i].vx, 2) + Math.pow(circles[i].vy, 2) - 2 * circles[i].vx * circles[j].vx + Math.pow(circles[j].vx, 2) - 2 * circles[i].vy * circles[j].vy + Math.pow(circles[j].vy, 2);
                B = -circles[i].x * circles[i].vx - circles[i].y * circles[i].vy + circles[i].vx * circles[j].x + circles[i].vy * circles[j].y + circles[i].x * circles[j].vx - circles[j].x * circles[j].vx + circles[i].y * circles[j].vy - circles[j].y * circles[j].vy;
                C = Math.pow(circles[i].vx, 2) + Math.pow(circles[i].vy, 2) - 2 * circles[i].vx * circles[j].vx + Math.pow(circles[j].vx, 2) - 2 * circles[i].vy * circles[j].vy + Math.pow(circles[j].vy, 2);
                D = Math.pow(circles[i].x, 2) + Math.pow(circles[i].y, 2) - Math.pow(circles[i].r, 2) - 2 * circles[i].x * circles[j].x + Math.pow(circles[j].x, 2) - 2 * circles[i].y * circles[j].y + Math.pow(circles[j].y, 2) - 2 * circles[i].r * circles[j].r - Math.pow(circles[j].r, 2);
                DISC = Math.pow((-2 * B), 2) - 4 * C * D;

                // If the discriminent if non negative, a collision will occur and
                // we must compare the time to our current time of collision. We
                // udate the time if we find a collision that has occurd earlier
                // than the previous one.
                if(DISC >= 0) {

                    // We want the smallest time 
                    t = Math.min(Math.min(t, 0.5 * (2 * B - Math.sqrt(DISC)) / A), 0.5 * (2 * B + Math.sqrt(DISC)) / A) 
                }
            }
        }
    }

    return t;
}

// Draws all the circles to the screen
function drawCircles() {
    for(var i = 0; i < circles.length; i++) {

        context.fillStyle = '#000000';
        context.beginPath();
        context.arc(circles[i].x, circles[i].y, circles[i].r, 0, 2 * Math.PI, true);
        context.closePath();
        context.fill();
    }
}

// Updates all the circles attributes. If a collision Occures in between frames,
// the circles will be updated to the point of the collision. We return when the
// collision occurs so that we can adjust the delay in the main loop.
function updateCircles() {
    // We want to increment by at most one frame
    var t = Math.min(1, timeToCollision());

    for(var i = 0; i < circles.length; i++) {
        circles[i].x += circles[i].vx * t;
        circles[i].y += circles[i].vy * t;
    }

    return t;
}

// Collision reaction function
function collide(c1, c2) {
    var nx = (c1.x - c2.x) / (c1.r + c2.r);
    var ny = (c1.y - c2.y) / (c1.r + c2.r);
    var a1 = c1.vx * nx + c1.vy * ny;
    var a2 = c2.vx * nx + c2.vy * ny;
    var p = 2 * (a1 - a2) / (c1.m + c2.m);

    c1.vxp = c1.vx - p * nx * c2.m;
    c1.vyp = c1.vy - p * ny * c2.m;

    c2.vxp = c2.vx + p * nx * c1.m;
    c2.vyp = c2.vy + p * ny * c1.m;
}

// Checks if a collision has occured between any of the circles
function checkForCollision() {

    for(var i = 0; i < circles.length; i++) {
        for(var j = 0; j < circles.length; j++) {           
            if(movingToCircle(circles[i], circles[j]) && Math.pow((circles[j].x - circles[i].x), 2) + Math.pow((circles[j].y - circles[i].y), 2) <= Math.pow((circles[i].r + circles[j].r + epsilon), 2)) {
                collide(circles[i], circles[j]);
            }
        }
        if(circles[i].x < 1 || circles[i].x > canvas.width) {
            circles[i].vxp *= -1;
        }
        if(circles[i].y < 1 || circles[i].y > canvas.height) {
            circles[i].vyp *= -1;
        }
    }
    for(var i = 0; i < circles.length; i++) {
        circles[i].vx = circles[i].vxp;
        circles[i].vy = circles[i].vyp;
    }
}

// Tells us if two circles are moving towards each other
function movingToCircle(c1, c2) {
    // Position Vector dotted with the Relative Velocity Vector
    return (c2.x - c1.x) * (c1.vx - c2.vx) + (c2.y - c1.y) * (c1.vy - c2.vy) > 0;
}

// Main animation loop
function loop() {

    // Clear Canvas
    context.fillStyle = '#ffffff';
    context.fillRect( 0, 0, canvas.width, canvas.height );

    drawCircles();
    checkForCollision();
    t = updateCircles();
}

请注意,我将球改为圆形只是因为我发现它更适合 2d。

先感谢您。

4

0 回答 0