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
相关产品推荐
相关产品推荐

