You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript 2D物理模拟中圆形碰撞后消失问题求助

问题分析与修复方案

我帮你定位到几个导致圆形消失的核心问题,咱们一步步来解决:

1. 速度计算公式的致命语法错误

看你这段速度计算代码:

newVx1 = (circles[i].vx * (circles[i].mass - circles[an].mass) + 2 * circles[i].mass[an] * circles[i].vx) / (circles[i].mass + circles[an].mass);

这里有两个严重错误:

  • circles[i].mass[an]完全是笔误!你想访问的是另一个圆的质量,应该写成circles[an].mass
  • 公式后半部分的速度变量用错了,正确的弹性碰撞公式里,这里应该用对方的速度circles[an].vx,而不是当前圆的circles[i].vx

同样的错误也出现在newVy1、newVx2、newVy2的计算里,这些错误会直接导致计算出的速度变成NaN,当圆的位置用NaN去更新时,就会从画布上“消失”。

修正后的速度计算应该是这样:

// 正确的弹性碰撞速度公式
newVx1 = (circles[i].vx * (circles[i].mass - circles[an].mass) + 2 * circles[an].mass * circles[an].vx) / (circles[i].mass + circles[an].mass);
newVy1 = (circles[i].vy * (circles[i].mass - circles[an].mass) + 2 * circles[an].mass * circles[an].vy) / (circles[i].mass + circles[an].mass);
newVx2 = (circles[an].vx * (circles[an].mass - circles[i].mass) + 2 * circles[i].mass * circles[i].vx) / (circles[i].mass + circles[an].mass);
newVy2 = (circles[an].vy * (circles[an].mass - circles[i].mass) + 2 * circles[i].mass * circles[i].vy) / (circles[i].mass + circles[an].mass);

2. 重复碰撞处理导致逻辑混乱

你现在的碰撞循环是让每个圆和所有其他圆都检测一次,比如当i=0、an=1处理一次,到i=1、an=0又会再处理一次同一对圆。这会导致同一对圆在一帧里被修改两次速度,运动状态完全混乱。

解决方法很简单,把内层循环的起始值改成i+1,这样每对圆只会被检测一次:

// 只检测当前圆之后的圆,避免重复处理
for (var an = i + 1; an < circles.length; an++) {

3. 碰撞后未分离重叠的圆

当你检测到碰撞时,两个圆已经处于重叠状态了,如果只修改速度不把它们分开,下一帧还会再次触发碰撞,导致速度被反复修改,甚至出现数值溢出的情况。

可以在修改速度后,添加一段代码把两个圆沿碰撞方向推开,消除重叠:

// 计算碰撞方向向量
var dx = circles[i].x - circles[an].x;
var dy = circles[i].y - circles[an].y;
var distance = Math.sqrt(dx*dx + dy*dy);
// 计算重叠的距离
var overlap = (circles[i].r + circles[an].r) - distance;
// 归一化方向向量
var nx = dx / distance;
var ny = dy / distance;
// 把两个圆向相反方向移动,消除重叠
circles[i].x += nx * overlap * 0.5;
circles[i].y += ny * overlap * 0.5;
circles[an].x -= nx * overlap * 0.5;
circles[an].y -= ny * overlap * 0.5;

修正后的完整animate函数片段

function animate() {
    c.fillStyle = "#000000";
    c.fillRect(container.x, container.y, container.width, container.height);

    //loop through the circles array
    for (var i = 0; i < circles.length; i++) {
        //draw the circles
        c.fillStyle = "hsl(" + circles[i].color++ + ", 100%, 100%)";
        c.beginPath();
        c.arc(circles[i].x, circles[i].y, circles[i].r, 0, Math.PI * 2, true);
        c.fill();

        //check circle on circle collisions - 只检测当前圆之后的圆
        for (var an = i + 1; an < circles.length; an++) {
            var dx = circles[i].x - circles[an].x;
            var dy = circles[i].y - circles[an].y;
            var distance = Math.sqrt(dx*dx + dy*dy);

            if (distance < circles[i].r + circles[an].r) {
                // 计算修正后的碰撞速度
                var newVx1 = (circles[i].vx * (circles[i].mass - circles[an].mass) + 2 * circles[an].mass * circles[an].vx) / (circles[i].mass + circles[an].mass);
                var newVy1 = (circles[i].vy * (circles[i].mass - circles[an].mass) + 2 * circles[an].mass * circles[an].vy) / (circles[i].mass + circles[an].mass);
                var newVx2 = (circles[an].vx * (circles[an].mass - circles[i].mass) + 2 * circles[i].mass * circles[i].vx) / (circles[i].mass + circles[an].mass);
                var newVy2 = (circles[an].vy * (circles[an].mass - circles[i].mass) + 2 * circles[i].mass * circles[i].vy) / (circles[i].mass + circles[an].mass);

                // 更新速度
                circles[i].vx = newVx1;
                circles[an].vx = newVx2;
                circles[i].vy = newVy1;
                circles[an].vy = newVy2;

                // 分离重叠的圆
                var overlap = (circles[i].r + circles[an].r) - distance;
                var nx = dx / distance;
                var ny = dy / distance;
                circles[i].x += nx * overlap * 0.5;
                circles[i].y += ny * overlap * 0.5;
                circles[an].x -= nx * overlap * 0.5;
                circles[an].y -= ny * overlap * 0.5;
            }
        }

        // 边界碰撞检测
        if (circles[i].x - circles[i].r + circles[i].vx < container.x || circles[i].x + circles[i].r + circles[i].vx > container.x + container.width) {
            circles[i].vx = circles[i].bounce * -circles[i].vx;
        }
        if (circles[i].y + circles[i].r + circles[i].vy > container.y + container.height || circles[i].y - circles[i].r + circles[i].vy < container.y) {
            circles[i].vy = circles[i].bounce * -circles[i].vy;
        }

        // 更新位置和重力
        circles[i].x += circles[i].vx;
        circles[i].y += circles[i].vy;
        circles[i].vy += 0.06; // 重力因子(你注释里写的wind factor应该是笔误)
    }
    requestAnimationFrame(animate);
}

建议你修复后先console.log一下newVx1、newVy1这些变量的值,确认没有出现NaN,这样就能解决圆形消失的问题了。

内容的提问来源于stack exchange,提问作者CranberryCode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:28:26