我试图制作一个应用程序,其中球从墙壁反弹并且也相互脱离。从墙上弹起来的效果很好,但我在让他们互相反弹方面遇到了一些麻烦。这是我用来使它们从另一个球上反弹的代码(用于测试我只有2个球)
// Calculate the distance using Pyth. Thrm.
GLfloat x1, y1, x2, y2, xd, yd, distance;
x1 = balls[0].xPos;
y1 = balls[0].yPos;
x2 = balls[1].xPos;
y2 = balls[1].yPos;
xd = x2 - x1;
yd = y2 - y1;
distance = sqrt((xd * xd) + (yd * yd));
if(distance < (balls[0].ballRadius + balls[1].ballRadius))
{
std::cout << "Collision\n";
balls[0].xSpeed = -balls[0].xSpeed;
balls[0].ySpeed = -balls[0].ySpeed;
balls[1].xSpeed = -balls[1].xSpeed;
balls[1].ySpeed = -balls[1].ySpeed;
}
发生的事情是他们随机反弹或互相传递。我缺少一些物理学吗?
编辑:这是完整的功能
// Callback handler for window re-paint event
void display()
{
glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
// FOR LOOP
for (int i = 0; i < numOfBalls; i++)
{
glLoadIdentity(); // Reset model-view matrix
int numSegments = 100;
GLfloat angle = 0;
glTranslatef(balls[i].xPos, balls[i].yPos, 0.0f); // Translate to (xPos, yPos)
// Use triangular segments to form a circle
glBegin(GL_TRIANGLE_FAN);
glColor4f(balls[i].colorR, balls[i].colorG, balls[i].colorB, balls[i].colorA);
glVertex2f(0.0f, 0.0f); // Center of circle
for (int j = 0; j <= numSegments; j++)
{
// Last vertex same as first vertex
angle = j * 2.0f * PI / numSegments; // 360 deg for all segments
glVertex2f(cos(angle) * balls[i].ballRadius, sin(angle) * balls[i].ballRadius);
}
glEnd();
// Animation Control - compute the location for the next refresh
balls[i].xPos += balls[i].xSpeed;
balls[i].yPos += balls[i].ySpeed;
// Calculate the distance using Pyth. Thrm.
GLfloat x1, y1, x2, y2, xd, yd, distance;
x1 = balls[0].xPos;
y1 = balls[0].yPos;
x2 = balls[1].xPos;
y2 = balls[1].yPos;
xd = x2 - x1;
yd = y2 - y1;
distance = sqrt((xd * xd) + (yd * yd));
if(distance < (balls[0].ballRadius + balls[1].ballRadius))
{
std::cout << "Collision\n";
balls[0].xSpeed = -balls[0].xSpeed;
balls[0].ySpeed = -balls[0].ySpeed;
balls[1].xSpeed = -balls[1].xSpeed;
balls[1].ySpeed = -balls[1].ySpeed;
}
else
{
std::cout << "No collision\n";
}
// Check if the ball exceeds the edges
if (balls[i].xPos > balls[i].xPosMax)
{
balls[i].xPos = balls[i].xPosMax;
balls[i].xSpeed = -balls[i].xSpeed;
}
else if (balls[i].xPos < balls[i].xPosMin)
{
balls[i].xPos = balls[i].xPosMin;
balls[i].xSpeed = -balls[i].xSpeed;
}
if (balls[i].yPos > balls[i].yPosMax) {
balls[i].yPos = balls[i].yPosMax;
balls[i].ySpeed = -balls[i].ySpeed;
}
else if (balls[i].yPos < balls[i].yPosMin)
{
balls[i].yPos = balls[i].yPosMin;
balls[i].ySpeed = -balls[i].ySpeed;
}
}
glutSwapBuffers(); // Swap front and back buffers (of double buffered mode)
}
**注意:大多数函数使用带有numOfBalls
的for循环作为计数器,但是为了测试碰撞,我只使用了2个球,因此balls[0]
和{{ 1}}
答案 0 :(得分:1)
以下是需要考虑的事项。
如果(xSpeed,ySpeed)的长度与.ballRadius
大致相当,那么两个球可以通过&#34; thru&#34;彼此之间相互关联&#34; ticks&#34;模拟时钟(一步)考虑两个球在水平方向上完全垂直,一个向上,一个向下,以及 1 .ballRadius
。在现实生活中,它们会明显发生碰撞,但如果.ySpeed
〜.ballRadius
,您的模拟很容易错过此事件。
其次,你改变球的矢量导致每个球停下来,因为
balls[0].xSpeed -= balls[0].xSpeed;
是一种非常奇特的写作方式
balls[0].xSpeed = 0;
答案 1 :(得分:0)
对于物理几乎正确的东西,您只需要反转垂直于接触平面的分量。
换句话说,将collision_vector
作为球中心之间的向量(只需从另一个点中减去一个点的坐标)。因为你有球体,这也恰好是碰撞平面的法线。
现在依次为每个球,你需要分解他们的速度。 A
组件将是与colision_vector
对齐的组件,您可以通过执行一些向量算术A = doc(Speed, collision_vector) * collision_vector
来获取它。这将是你想要反转的东西。您还需要提取与碰撞平面平行的B
组件。因为它是平行的,所以不会因为碰撞而改变。您可以通过从速度向量中减去A
来获得它。
最后,新的速度将类似于B - A
。如果你想让球旋转,你将需要A - B
方向的角动量。如果球的质量不同,那么您需要在第一个公式中使用重量比作为A
的乘数。
这将使碰撞看起来合法。检测仍需要正确进行。确保速度明显小于球的半径。对于可比较或更大的速度,您将需要更复杂的算法。
注意:上面的大部分内容都是矢量算术。也是在这里很晚,所以我可能会混淆一些迹象(对不起)。在纸上举一个简单的例子来解决它。它还可以帮助您更好地理解解决方案。