将重力应用于物体

3

我在实现物体的重力方面遇到了困难。

我使用OpenGL绘制了一堆圆形物体。我使用delta-xdelta-y来移动这些圆(球)。我正在尝试每帧向y坐标添加一个重力常量,以便模拟被向下拉的情况,但我不知道如何实现。

以下是相关代码:

class Ball
{
    public:
        double x;
        double y;
        double radius;
        double deltaX;
        double deltaY;
};


std::vector<Ball> gAllBalls;  // a vector of balls with random positions and delta-values
double gGravity = ?;  // gravitational constant - I know it's 92 m/s^s, but I don't know how to apply that to deltaX and deltaY


void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);

    for (auto &thisBall : gAllBalls)
    {
        // draw
        glColor3d(thisBall.red, thisBall.green, thisBall.blue);
        DrawCircle(thisBall.x, thisBall.y, thisBall.radius);

        // gravity - not working
        if (thisBall.y + thisBall.radius < gScreenHeight - gGravity)
        {
            thisBall.y += gGravity;
        }

        // wall bouncing
        if (thisBall.y + thisBall.radius + thisBall.deltaY >= gScreenHeight)  // up
        {
            thisBall.deltaY = -thisBall.deltaY;
        }

        if (thisBall.y + thisBall.deltaY - thisBall.radius < 0)  // down
        {
            thisBall.deltaY = -thisBall.deltaY;
        }

        if (thisBall.x + thisBall.deltaX - thisBall.radius < 0) // left
        {
            thisBall.deltaX = -thisBall.deltaX;
        }

        if (thisBall.x + thisBall.radius + thisBall.deltaX >= gScreenWidth)  // right
        {
            thisBall.deltaX = -thisBall.deltaX;
        }

        // move
        thisBall.x += thisBall.deltaX;
        thisBall.y += thisBall.deltaY;
    }
    glutSwapBuffers();
    glutPostRedisplay();
}

我遇到的一个大问题是我不知道如何计算重力,因为我正在使用 deltaXdeltaY 而不是使用分别计算速度和距离的变量来计算 92 米/秒^2 的重力。无论我将重力设置为多少,球都不会像应该一样运动 - 不管重力强度如何,所以还有其他问题,但我不知道是什么。

这将导致恒定速度,而不是恒定加速度。如果您调整deltaY而不是Y,则可能会更接近您的意图。最好使用工程单位(如米和秒)而不是像素和任意时间步长进行工作,然后根据需要进行转换。最后,您的“G”值有误,实际上是9.8 m / sec ^ 2。 - Jim Lewis
当然,这更有意义。我将其更改为deltaY而不是Y,最初似乎可以工作,但球开始加速得越来越快,而不是减速。我只使用1作为重力常数。我很想使用更好的单位,但我不确定如何实现。你有什么建议或资源吗? - Grav
92 m/s^2”,你是在模拟什么,超级木星还是小恒星? - genpfault
这是哪个应用程序?如果您想在均匀重力场中模拟真实运动,则可以使用方程y_{t} = y_{t-dt} + v_{y,t-dt}dt - 0.5gdt^{2}。y_{t}是时间t的位置,dt是调用“display()”之间的时间,v_{y,t-dt}是上一个时间步长(上次调用“display()”时)的速度,而g是地球上重力加速度(9.8m/s^{2})的大小。 - PrestonH
顺便说一句,除非你想在地球上进行真实的运动模拟,否则没有使用9.8米/秒^2的真正理由。我上面发布的方程式仍然会给出正确类型的运动,并且您可以将g更改为任何您认为看起来不错的值。 - PrestonH
1个回答

4

我认为问题在于物理学,而不是编程技术。 对于你的情况,我会将Ball类中的“delta”成员更改为“速度”,因为它们是每个周期(时间)改变对象位置的距离单位,但这只是建议,以便更容易地可视化...

class Ball
{
    public:
        double x;
        double y;
        double radius;
        double speedX;
        double speedY;
};

其次,在你的代码中,你修改了“y”成员而不是速度,因为重力会改变速度,所以出现了问题。尝试这样做,并且出于调试目的,我建议使用点对象(没有半径,只有纯粹的(x,y)坐标)。

因此,总之,我只需将你的重力代码更改为以下内容:

  // gravity - 'fixed'
  if (thisBall.y + thisBall.radius < gScreenHeight - gGravity)
  {
      thisBall.speedY -= gGravity; //notice the '-'
  }

重力的值应该是绝对和正的,这样可以使物理模拟更加简单。如果你尝试这个方法,你会得到一个理想的简单物理模拟器,其中一个球以恒定的速度X运动(只改变方向,而不是大小)。

请尝试一下,并告诉我效果如何。祝好运,加油!=)


作为一名物理学家,speedY -= gGravity; 看起来很奇怪。这会使 gGravity 本身成为一个负数,并且正数相加 (+=)。 - datenwolf
谢谢!这让我更接近期望的结果了。但是,我仍然有一个小问题:当球弹跳时,它们每次弹跳都会越来越高,而不是减速并最终停在底部。我改变的唯一一件事是重力影响速度而不是位置。您有任何建议为什么会发生这种情况吗? - Grav
我认为我遇到了类似的问题。当球弹跳时,我翻转了dx和dy的负值。这对于倾斜的表面有效。我通过仅在倾斜的表面上翻转它们,并在平坦的表面上否定它们来修复它们。 - Iain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接