大规模球与球的碰撞处理(例如,很多球)
更新:发现我使用半径作为直径,这就是 mtd 过度补偿的原因。
另一个更新:我的球重叠的原因似乎是因为每次碰撞只有一次检查。经过一些研究,有人说,防止对象堆积重叠的方法之一是递归地执行碰撞检查。这在一定程度上是有效的,而且我怀疑如果物理原理更加准确的话,效果会更好。如果我找到更多解决方案,我会再次更新。另外,我正在使用 Simucal 的碰撞校正代码。
嗨,StackOverflow 。我不久前编写了一个模拟球物理的处理程序。基本上,我有大量的球(1000 个),并且重力已打开。检测效果很好,但我的问题是,当它们在各个方向上与其他球弹跳时,它们就会开始表现得很奇怪。
我非常有信心这涉及到处理。大多数情况下,我使用 Jay Conrod 的代码。一个不同的部分是
if (distance > 1.0)
return;
我已经更改为,
if (distance < 1.0)
return;
因为碰撞甚至没有用第一段代码执行,我猜这是一个拼写错误。
当我使用他的代码时,球会重叠,这不是我想要的。我尝试解决这个问题是将球移动到彼此的边缘:
float angle = atan2(y - collider.y, x - collider.x);
float distance = dist(x,y, balls[ID2].x,balls[ID2].y);
x = collider.x + radius * cos(angle);
y = collider.y + radius * sin(angle);
这是不正确的,我很确定这一点。
我尝试了之前的球对球主题中的校正算法:
// get the mtd
Vector2d delta = (position.subtract(ball.position));
float d = delta.getLength();
// minimum translation distance to push balls apart after intersecting
Vector2d mtd = delta.multiply(((getRadius() + ball.getRadius())-d)/d);
// resolve intersection --
// inverse mass quantities
float im1 = 1 / getMass();
float im2 = 1 / ball.getMass();
// push-pull them apart based off their mass
position = position.add(mtd.multiply(im1 / (im1 + im2)));
ball.position = ball.position.subtract(mtd.multiply(im2 / (im1 + im2)));
除了我的版本不使用向量,并且每个球的权重都是1。我得到的结果代码是这样的:
PVector delta = new PVector(collider.x - x, collider.y - y);
float d = delta.mag();
PVector mtd = new PVector(delta.x * ((radius + collider.radius - d) / d), delta.y * ((radius + collider.radius - d) / d));
// push-pull apart based on mass
x -= mtd.x * 0.5;
y -= mtd.y * 0.5;
collider.x += mtd.x * 0.5;
collider.y += mtd.y * 0.5;
这段代码似乎过度校正了碰撞。这对我来说没有意义,因为除此之外,我没有其他方式修改每个球的 x 和 y 值。
我的代码的其他部分可能是错误的,但我不知道。这是我正在使用的整个球与球碰撞处理的片段:
if (alreadyCollided.contains(new Integer(ID2))) // if the ball has already collided with this, then we don't need to reperform the collision algorithm
return;
Ball collider = (Ball) objects.get(ID2);
PVector collision = new PVector(x - collider.x, y - collider.y);
float distance = collision.mag();
if (distance == 0) {
collision = new PVector(1,0);
distance = 1;
}
if (distance < 1)
return;
PVector velocity = new PVector(vx,vy);
PVector velocity2 = new PVector(collider.vx, collider.vy);
collision.div(distance); // normalize the distance
float aci = velocity.dot(collision);
float bci = velocity2.dot(collision);
float acf = bci;
float bcf = aci;
vx += (acf - aci) * collision.x;
vy += (acf - aci) * collision.y;
collider.vx += (bcf - bci) * collision.x;
collider.vy += (bcf - bci) * collision.y;
alreadyCollided.add(new Integer(ID2));
collider.alreadyCollided.add(new Integer(ID));
PVector delta = new PVector(collider.x - x, collider.y - y);
float d = delta.mag();
PVector mtd = new PVector(delta.x * ((radius + collider.radius - d) / d), delta.y * ((radius + collider.radius - d) / d));
// push-pull apart based on mass
x -= mtd.x * 0.2;
y -= mtd.y * 0.2;
collider.x += mtd.x * 0.2;
collider.y += mtd.y * 0.2;
Update: Found out that I was using the radius as the diameter, which was why the mtd was overcompensating.
Another Update: The reason my balls are overlapping seem to be because there's only one check for every collision. After some research, some are saying that one of the ways you could prevent overlapping with objects piling up is to recursively perform the collision check. This works to an extent, and I suspect that it'd work even better if the physics were a lot more accurate. I'll update again if I find any more solutions. Also, I'm using Simucal's collision correction code.
Hi, StackOverflow. I've written a Processing program awhile back simulating ball physics. Basically, I have a large number of balls (1000), with gravity turned on. Detection works great, but my issue is that they start acting weird when they're bouncing against other balls in all directions.
I'm pretty confident this involves the handling. For the most part, I'm using Jay Conrod's code. One part that's different is
if (distance > 1.0)
return;
which I've changed to
if (distance < 1.0)
return;
because the collision wasn't even being performed with the first bit of code, I'm guessing that's a typo.
The balls overlap when I use his code, which isn't what I was looking for. My attempt to fix it was to move the balls to the edge of each other:
float angle = atan2(y - collider.y, x - collider.x);
float distance = dist(x,y, balls[ID2].x,balls[ID2].y);
x = collider.x + radius * cos(angle);
y = collider.y + radius * sin(angle);
This isn't correct, I'm pretty sure of that.
I tried the correction algorithm in the previous ball-to-ball topic:
// get the mtd
Vector2d delta = (position.subtract(ball.position));
float d = delta.getLength();
// minimum translation distance to push balls apart after intersecting
Vector2d mtd = delta.multiply(((getRadius() + ball.getRadius())-d)/d);
// resolve intersection --
// inverse mass quantities
float im1 = 1 / getMass();
float im2 = 1 / ball.getMass();
// push-pull them apart based off their mass
position = position.add(mtd.multiply(im1 / (im1 + im2)));
ball.position = ball.position.subtract(mtd.multiply(im2 / (im1 + im2)));
except my version doesn't use vectors, and every ball's weight is 1. The resulting code I get is this:
PVector delta = new PVector(collider.x - x, collider.y - y);
float d = delta.mag();
PVector mtd = new PVector(delta.x * ((radius + collider.radius - d) / d), delta.y * ((radius + collider.radius - d) / d));
// push-pull apart based on mass
x -= mtd.x * 0.5;
y -= mtd.y * 0.5;
collider.x += mtd.x * 0.5;
collider.y += mtd.y * 0.5;
This code seems to over-correct collisions. Which doesn't make sense to me because in no other way do I modify the x and y values of each ball, other than this.
Some other part of my code could be wrong, but I don't know. Here's the snippet of the entire ball-to-ball collision handling I'm using:
if (alreadyCollided.contains(new Integer(ID2))) // if the ball has already collided with this, then we don't need to reperform the collision algorithm
return;
Ball collider = (Ball) objects.get(ID2);
PVector collision = new PVector(x - collider.x, y - collider.y);
float distance = collision.mag();
if (distance == 0) {
collision = new PVector(1,0);
distance = 1;
}
if (distance < 1)
return;
PVector velocity = new PVector(vx,vy);
PVector velocity2 = new PVector(collider.vx, collider.vy);
collision.div(distance); // normalize the distance
float aci = velocity.dot(collision);
float bci = velocity2.dot(collision);
float acf = bci;
float bcf = aci;
vx += (acf - aci) * collision.x;
vy += (acf - aci) * collision.y;
collider.vx += (bcf - bci) * collision.x;
collider.vy += (bcf - bci) * collision.y;
alreadyCollided.add(new Integer(ID2));
collider.alreadyCollided.add(new Integer(ID));
PVector delta = new PVector(collider.x - x, collider.y - y);
float d = delta.mag();
PVector mtd = new PVector(delta.x * ((radius + collider.radius - d) / d), delta.y * ((radius + collider.radius - d) / d));
// push-pull apart based on mass
x -= mtd.x * 0.2;
y -= mtd.y * 0.2;
collider.x += mtd.x * 0.2;
collider.y += mtd.y * 0.2;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的“结果代码”看起来是正确的。您是否有一个显示过度校正的简单测试用例(例如 x1=0、x1=3、y1=y2=0,r1=r2=2)?
另外,如果忽略重叠并保留其他所有内容(就好像球是软橡胶一样),您会得到好的结果吗?
编辑:
这部分是错误的:
当两个球靠近时,它们会抑制彼此的速度,直到它们都停止。但好的一面是,你发明了固体(开玩笑)。关闭重叠的东西,在这部分工作之前不要担心它。
如果不了解基础物理学,让这部分工作几乎是不可能的。你需要一只手吗?
Your "resulting code" looks correct. Do you have a simple test case that shows the overcorrection (e.g. x1=0, x1=3, y1=y2=0, r1=r2=2)?
Also, do you get good results if you neglect the overlap and keep everything else, as if the balls were soft rubber?
EDIT:
This part is wrong:
When two balls get close they damp each other's velocity until they both stop. But on the bright side, you've invented solids (just kidding). Turn off the overlap stuff and don't worry about it until you have this part working.
Getting this part working will be just about impossible without an understanding of basic physics. Do you need a hand?