如何避免粒子在弹性粒子碰撞模拟器中出现故障?

时间:2013-04-05 14:53:06

标签: javascript simulation collision

这是一个short video,其中可以看到两个(可能更多)粒子的组彼此相互闪烁。

可以找到源代码here

这是我用来计算碰撞的代码:

function collisionPhysics()
{
    for (var i = 0; i < N - 1; ++i)
    {
        for (var j = i + 1; j < N; ++j)
        {
            var Dx = objects[j].x - objects[i].x;    // Difference in X direction between objects[i] and objects[j].
            var Dy = objects[j].y - objects[i].y;    // Difference in Y direction between objects[i] and objects[j].
            var D2 = Dx * Dx + Dy * Dy;              // Distance between objects[i] and objects[j] squared.

            if (D2 <= (objects[i].rad + objects[j].rad) * (objects[i].rad + objects[j].rad))    // Colision check could be inserted here, reusing D2.
            {
                var delta = 2 * (Dx * (objects[i].Vx - objects[j].Vx) + Dy * (objects[i].Vy - objects[j].Vy)) / (D2 * (objects[i].m + objects[j].m));
                objects[i].Vx += -objects[i].m * delta * Dx;
                objects[i].Vy += -objects[i].m * delta * Dy;
                objects[j].Vx +=  objects[j].m * delta * Dx;
                objects[j].Vy +=  objects[j].m * delta * Dy;
            }
        }
    }
}

编辑2013/04/06: 我们提到的问题是引起奇怪的行为。而这个调整后的功能应该可以解决这个问题,不确定它是否可以提高性能但是有效:

function collisionPhysics()
{
    for (var i = 0; i < N - 1; ++i)
    {
        for (var j = i + 1; j < N; ++j)
        {
            var Dx = objects[j].x - objects[i].x + timeStep * (objects[j].u - objects[i].u);
            var Dy = objects[j].y - objects[i].y + timeStep * (objects[j].v - objects[i].v);
            var D2 = Dx * Dx + Dy * Dy;              // Distance between objects[i] and objects[j] squared.

            if (D2 <= (objects[i].r + objects[j].r) * (objects[i].r + objects[j].r))    // Colision check could be inserted here, reusing D2.
            {
                objects[i].col = true;
                objects[j].col = true;
                var dx = objects[j].x - objects[i].x;
                var dy = objects[j].y - objects[i].y;
                var du = objects[j].u - objects[i].u;
                var dv = objects[j].v - objects[i].v;
                var dr = objects[j].r + objects[i].r;
                var dt = (-Math.sqrt(2 * dx * du * dy * dv - du * du * (dy * dy - dr * dr) - dv * dv * (dx * dx - dr * dr)) - dx * du - dy * dv) / (du * du + dv * dv);
                Dx = objects[j].x - objects[i].x + dt * (objects[j].u - objects[i].u);
                Dy = objects[j].y - objects[i].y + dt * (objects[j].v - objects[i].v);
                D2 = Dx * Dx + Dy * Dy;
                var delta = 2 * (Dx * (objects[i].u - objects[j].u) + Dy * (objects[i].v - objects[j].v)) / (D2 * (objects[i].m + objects[j].m));
                objects[i].u += -objects[i].m * delta * Dx;
                objects[i].v += -objects[i].m * delta * Dy;
                objects[j].u +=  objects[j].m * delta * Dx;
                objects[j].v +=  objects[j].m * delta * Dy;
                objects[i].x += (timeStep - dt) * objects[i].u;
                objects[i].y += (timeStep - dt) * objects[i].v; 
                objects[j].x += (timeStep - dt) * objects[j].u;
                objects[j].y += (timeStep - dt) * objects[j].v;
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

问题是你的碰撞解决方法不能确保粒子在下一帧开始时仍然不会相交。

当您发现碰撞时,您需要向后工作到粒子边界发生碰撞并从那里解决碰撞的时间点。有关这样做的方法,请参阅this game development answer类似的问题。