让球互相反弹(openGL)

时间:2013-10-18 06:37:37

标签: c++ opengl

我试图制作一个应用程序,其中球从墙壁反弹并且也相互脱离。从墙上弹起来的效果很好,但我在让他们互相反弹方面遇到了一些麻烦。这是我用来使它们从另一个球上反弹的代码(用于测试我只有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}}

2 个答案:

答案 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的乘数。

这将使碰撞看起来合法。检测仍需要正确进行。确保速度明显小于球的半径。对于可比较或更大的速度,您将需要更复杂的算法。

注意:上面的大部分内容都是矢量算术。也是在这里很晚,所以我可能会混淆一些迹象(对不起)。在纸上举一个简单的例子来解决它。它还可以帮助您更好地理解解决方案。