2012-03-31 65 views
2

我正在用C++写一点物理模拟,基本上是在屏幕上移动圆圈,当两个圆圈发生碰撞时,它们应该像弹子球一样弹跳。当这些圈子相互碰撞时,大多数时候它们实际上会无限地减速/它们看起来相互粘在一起并变得静止。有时候只有一个球会在碰撞中反弹,另一个会保持它的运动轨迹。这只是一个简单的2D模拟。圆形碰撞回弹不能正常工作

所以这里就是我对检测/跳弹逻辑:

bool Ball::BallCollision(Ball &b2) 
{ 
    if (sqrt(pow(b2.x - x, 2) + pow(b2.y - y, 2)) <= b2.radius + radius) // Test for collision 
    { 
     normal[0] = (x - (x + b2.x)/2)/radius; // Finds normal vector from point of collision to radius 
     normal[1] = (y - (y + b2.y)/2)/radius; 
     xvel = xvel - 2 * (xvel * normal[0]) * normal[0]; // Sets the velocity vector to the reflection vector 
     yvel = yvel - 2 * (yvel * normal[1]) * normal[1]; 

     ////x = xprev; // These just move the circle back a 'frame' so the collision 
     ////y = yprev; // detection doesn't detect collision more than once. 
        // Not sure if working? 
    } 
} 

我想不出有什么不对我的功能。感谢您提前提供任何帮助!

编辑: 每个变量声明为float

功能:

void Ball::Move() 
{ 
    xprev = x; 
    yprev = y; 
    x += xvel; 
    y += yvel; 
} 

void Ball::DrawCircle() 
{ 
    glColor3ub(100, 230, 150); 
    glBegin(GL_POLYGON); 
    for (int i = 0; i < 10; i++) 
    { 
     angle = i * (2*3.1415/10); 
     newx = x + r*cos(angle); 
     newy = y + r*sin(angle); 
     glVertex2f(newx, newy); 
    } 
    glEnd(); 
} 

循环:

run_prev.clear(); // A vector, cleared every loop, that holds the Ball objects that collided 

    for (int i = 0; i < num_balls; i++) 
    { 
     b[i].Move(); 
    } 

    for (int i = 0; i < num_balls; i++) 
    { 
     b[i].WallCollision(); // Just wall collision detecting, that is working just fine 
    } 

    //The loop that checks for collisions... Am I executing this properly? 
    for (int i = 0; i < num_balls; i++) 
    { 
     for (int j = 0; j < num_balls; j++) 
     { 
      if (i == j) continue; 
      if (b[i].BallCollision(b[j]) == true) 
      { 
       run_prev.push_back(b[i]); 
      } 
     } 
    } 

    for (int i = 0; i < num_balls; i++) 
    { 
     b[i].DrawCircle(); 
    } 

    //xprev and yprev are the x and y values of the frame before for each circle 
    for (int i = 0; i < run_prev.size(); i++) 
    { 
     run_prev[i].x = run_prev[i].xprev; 
     run_prev[i].y = run_prev[i].yprev; 
    } 
+0

你应该发布你的变量是什么类型,只是为了知道我们是否可以排除舍入或其他铸造错误。 – vsz 2012-03-31 07:48:14

+0

我不明白你为什么要这样计算正常值。他们应该有单位长度吗? – 2012-03-31 08:06:41

+0

我以为他们是。无论我可能滑倒,请纠正我。 – Christian 2012-03-31 08:08:48

回答

2
  1. 只有当它们相互移动时,才会使球碰撞(反射运动向量)。如果他们彼此离开,不要处理碰撞。打破这个规则,他们会被粘在一起。
  2. 处理碰撞时,一次更新两个球。一次不更新一个球。
  3. 您的移动向量调整不正确。球不会互相反射,因为球可以以不同的速度移动。

正确的运动调整(假设球具有相同的质量)应该是类似的东西:

pos1 and pos2 = positions; 
v1 and v2 are movement vector (speed); 
n is collision normal == normalize(pos1 - pos2); 
collisionSpeed = dot((v2-v1), n); 
collisionSpeed *= elasticy; (0.0..1.0); 
v1 = v1 - dot(v1, n); 
v2 = v2 - dot(v2, n); 
v1 -= scale(n, collisionSpeed * 0.5); 
v2 += scale(n, collisionSpeed * 0.5); 

要理解公式,牛顿检查法(尤其是冲动)。或者查看Chris Hecker关于游戏物理学的论文。

+0

谢谢。你如何测试他们是否正在相互移动? – Christian 2012-04-01 03:59:53

+0

@ vorbis5:在上例中检查collisionSpeed的符号。 – SigTerm 2012-04-01 13:17:25

+0

大家帮我一把,谢谢大家! – Christian 2012-04-02 01:55:21

0

你计算正常是错误的方式。 (x + b2.x)/ 2不一定是碰撞点,如果球的半径不相等。

+0

迄今为止设置我的模拟的方式是所有半径相等。 – Christian 2012-03-31 08:23:12

1

目前尚不清楚你是如何调用这个函数的,但我认为我看到了这个问题。

假设您有Ball ballABall ballB,它们在当前帧中发生碰撞,然后运行ballA.BallCollision(ballB)

这将更新ballA的成员变量,并将其移回框架。但它不更新ballB的位置或轨迹。

即使您也打电话给对方(ballB.BallCollision(ballA)),它也不会检测到碰撞,因为当您调用ballA.BallCollision(ballB)时,它会将ballA移回框架。

+0

非常好的洞察力,我会编辑我的代码,看看是否解决了我的问题! – Christian 2012-03-31 09:42:49

+0

嗯,问题依然存在。当一个缓慢的圈子与另一个圈子发生碰撞时,他们都会紧紧地联系在一起并停止移动,而且篮板本身似乎有点不合适。这很奇怪,我把更多的代码放在顶部,也许你可以再看看它。 :) – Christian 2012-03-31 10:33:48

1

我没有详细看过你的代码,但没有考虑到这种类型的碰撞只能在动量帧的中心工作。现在,我假设你的球具有相同的质量。你所做的是取两个动量(或速度,因为它们具有相同的质量)的平均值,并从速度中减去该平均值。执行你的计算,并加回平均值。 Here是我问到可能与此有关的问题。

+0

真棒,我会尝试。 – Christian 2012-04-01 00:45:19

+0

好吧,我试过了,现在球仍然粘在一起,但至少当它们碰撞并粘住时,它们不会变成静止的。我认为我的主要问题是球碰撞时粘住球。 – Christian 2012-04-01 01:13:27

+0

你有没有足够的代码来移动球,这样就不会相交了?而且我不完全确定你计算法线的方式...... – slartibartfast 2012-04-01 01:16:31