【发布时间】:2022-09-30 21:55:30
【问题描述】:
我已经创建了我在下面遇到的问题的完整演示:
const rng = (min, max) => Math.random() * (max - min + 1) + min;
const canvas = document.querySelector(\"canvas\");
const ctx = canvas.getContext(\"2d\");
ctx.strokeStyle = \"#000\";
ctx.lineWidth = 4;
ctx.fillStyle = \"#ff0000\";
function drawCircle(c) {
ctx.beginPath();
ctx.arc(c.x, c.y, c.r, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill();
}
class Circle {
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
this.vX = 0;
this.vY = 0;
}
}
const circles = [];
for (let i = 0; i < 300; i++) {
circles.push(new Circle(rng(0, canvas.width), rng(0, canvas.height), rng(12, 14)));
}
function processCollision(c1, c2) {
const deltaX = c2.x - c1.x;
const deltaY = c2.y - c1.y;
const sumRadius = c1.r + c2.r;
const centerDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (centerDistance === 0 || centerDistance > sumRadius) { return; } // not colliding
const circleDistance = centerDistance - sumRadius;
const aX = deltaX / centerDistance;
const aY = deltaY / centerDistance;
const force = 5;
c1.vX += aX * circleDistance * force;
c1.vY += aY * circleDistance * force;
}
function update() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (const c of circles) {
c.vX = (canvas.width / 2) - c.x; // move towards center x
c.vY = (canvas.height / 2) - c.y; // move towards center y
}
for (const c1 of circles) {
for (const c2 of circles) {
c1 !== c2 && processCollision(c1, c2);
}
}
for (const c of circles) {
c.x += c.vX * (1 / 60);
c.y += c.vY * (1 / 60);
drawCircle(c);
}
}
setInterval(update, 16.6666);
<canvas width=\"600\" height=\"600\" style=\"border:1px solid #d3d3d3;\">
注意所有的圆圈是如何围绕中心吸引的。但是,它们都在彼此剧烈碰撞。我想修改processCollision 函数,使圆圈不再相互显着重叠,而是大致均匀地分布在中心点周围。
我尝试增加force 变量,但不幸的是,虽然这确实会导致更大的传播,但它也会产生很多摇晃和生涩的运动。解决方案必须是平滑的,类似于上面的示例。我已经搞砸了好几个星期,但不幸的是似乎无法找到解决方案。
-
您可以尝试实现en.wikipedia.org/wiki/Lennard-Jones_potential 之类的东西 - 传统吸引力 + 排斥力仅在小距离内起作用(总最小能量为 sumRadius)
-
@MBo 你好!嗯,我不太确定这将如何工作。我尝试为它查找一些代码示例,我找到了this relevant answer 并实际上在本地运行了发布的 pygame 示例,但它看起来就像是从墙上弹回的普通圆圈。他们似乎并没有真正相互吸引或排斥。这仅仅是因为他们的示例对变量使用了不同的参数吗?如果是这样,我应该调整什么以获得我正在寻找的结果?我对这个算法很陌生。
-
Lennard-Jones 只是示例 - 您可以拟合一些函数 F(r),该函数对于小距离具有非常高的正值(排斥),对于较大距离具有负值(吸引力),并且在 sumradius 处具有最小值。我试图用你的代码做到这一点,但还没有得到可靠的结果。
-
啊,非常感谢你调查这个!是的,我一直在尝试类似的调整,当物体严重碰撞时会产生很大的排斥力,但它似乎也只会引起力的爆炸和非常刺耳、生涩的运动。我很难让一些既能工作又能工作的东西既高性能(简单的代码,因为它必须非常频繁地运行)而且也很流畅。
标签: javascript geometry html5-canvas collision-detection physics