【问题标题】:Mass Ball-to-Ball Collision Handling (as in, lots of balls)大规模球对球碰撞处理(例如,很多球)
【发布时间】:2011-05-27 17:47:52
【问题描述】:

更新:发现我使用半径作为直径,这就是 mtd 过度补偿的原因。

另一个更新:我的球重叠的原因似乎是因为每次碰撞只有一次检查。经过一些研究,有人说可以防止与堆积的对象重叠的一种方法是递归地执行碰撞检查。这在一定程度上有效,我怀疑如果物理学更准确,它会更好。如果我找到更多解决方案,我会再次更新。另外,我正在使用Simucal's collision correction code.

嗨,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 值。

我的代码的其他部分可能是错误的,但我不知道。这是我正在使用的整个球对球碰撞处理的 sn-p:

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;

【问题讨论】:

  • 如果您有新问题,您应该将其设为新帖子,而不是更改此问题。如果不查看您的修订历史,我无法说出您最初的要求。

标签: collision-detection simulation physics


【解决方案1】:

您的“生成的代码”看起来是正确的。您是否有显示过度校正的简单测试用例(例如 x1=0, x1=3, y1=y2=0, r1=r2=2)?

另外,如果忽略重叠并保留其他所有内容,就好像球是软橡胶一样,你会得到好的结果吗?

编辑:

这部分错了:

PVector velocity = new PVector(vx,vy);  
...
collider.vy += (bcf - bci) * collision.y;

当两个球靠近时,它们抑制彼此的速度,直到它们都停止。但从好的方面来说,你发明了固体(开个玩笑)。关闭重叠的东西,在这部分工作之前不要担心。

如果不了解基本物理学,这部分工作几乎是不可能的。需要帮忙吗?

【讨论】:

  • 当我关闭重叠校正时,它们会相互粘连,最终在重力开启的情况下沉到底部。
  • 好的,我想我会研究一些物理学,所以我可以使用我能理解的算法。另外:我从这里得到了算法:stackoverflow.com/questions/345838/… 感谢您的帮助,Beta。
猜你喜欢
  • 2010-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-19
  • 1970-01-01
  • 1970-01-01
  • 2010-12-29
相关资源
最近更新 更多