【问题标题】:Bouncing Ball in JavaJava中的弹跳球
【发布时间】:2023-03-13 07:52:01
【问题描述】:

这可能是一个非常基本的问题,但我似乎找不到任何其他文章。

无论如何,我已经用 Java 编写了一个小的弹跳球程序来尝试扩展我的基本技能。该程序只是一个简单的弹跳球,它会掉落并希望弹跳一段时间。原始程序运行良好,但现在我尝试在程序中添加重力。重力实际上可以正常工作一段时间,但是一旦反弹变得非常小,动画就会在很短的时间内变得不稳定,然后球的位置就会不断减小。我试图找出问题所在,但我就是看不到它。任何帮助都将受到欢迎。

public final class Ball extends Rectangle {
float xspeed = 1.0f; float yspeed = 1.0f; float gravity = 0.4f;


public Ball(float x, float y, float width, float height) {
    super(x, y, width, height);
}

public void update(){
    yspeed += gravity;

    move(xspeed, yspeed);

    if(getX() < 0){
        xspeed = 1;
    }
    if(getX() + getWidth() > 320){
        xspeed = -1;
    }
    if(getY() < 0){
        yspeed = 1;
    }
    if(getY() + getHeight() > 200 && yspeed > 0){
        yspeed *= -0.98f;
    }
    if(getY() + getHeight() > 200 && yspeed < 0){
        yspeed *= 0.98f;
    }

}

public void move(float x, float y){
    this.setX(getX()+x);
    this.setY(getY()+y);
}

}

编辑:谢谢,似乎已经对不稳定的运动进行了分类。我仍在努力寻找如何在球停止弹跳时阻止它向下移动。现在它会移动停止弹跳然后继续向下移动通过“地板”。我认为这与我的 yspeed += 重力线有关。我只是不知道如何停止运动。

【问题讨论】:

    标签: java graphics physics


    【解决方案1】:

    当你这样做时

    yspeed += gravity;
    

    假设球有空间移动距离 dx = v_i * t + 1/2 (-g) t^2。当您非常靠近地板时,这可能不是真的。如果出现以下情况,则失败:

    • 您离地板足够近,正在向下移动
    • 您非常靠近地面并且速度较低(例如当球失去大部分能量时)

    此错误会导致您的模拟停止保存能量,从而导致您在低振幅下看到不稳定的行为。

    您可以通过使用更小的时间步来减少问题,如果您进行测试计算以注意到您何时离开房间并为选择一个安全的时间步,您可以彻底摆脱它 em> 迭代(即,除非出现问题,否则始终使用默认值,然后计算最佳时间步长)。

    但是,您在此处使用的基本近似值也存在其他问题。在任何数值分析文本中查找关于数值求解微分方程的讨论。

    【讨论】:

      【解决方案2】:

      第一件事:当你在窗口顶部弹跳时将 y-speed 设置为 1 是不正确的,你应该将 yspeed 设置为 -yspeed(但如果你从边界内开始,它不应该弹到顶部无论如何)。

      其次,在底部弹跳时乘以 -0.981 是可以的,但我担心每次迭代都会向 yspeed 添加恒定的 0.4 重力。我认为这就是导致您在底部扭动的原因,因为您在检查可能导致球落到地面以下之前进行了移动。

      我会尝试通过替换 move 来确保 y 值永远不会低于地面:

      if (getY() + getHeight() + yspeed > 200) {
          move(xspeed, 200 - getY() - getHeight());
      } else {
          move(xspeed, yspeed);
      }
      

      【讨论】:

        【解决方案3】:

        问题在于,当反弹变得非常小时,

        yspeed *= -0.981;
        

        line 将被连续调用。球会低于底部,然后开始反弹,但最终仍会低于底部(因为 0.981

        if(getY() + getHeight() > 200){
          yspeed *= -0.981;
          setY(400 - getY() - getHeight()); // I believe this is right.
        }
        

        通过固定位置,您不会在减少和增加之间快速交替,也不会因为总是低于界限​​而陷入始终减少的情况。

        【讨论】:

        • 200 - (getY() + getHeight() - 200) = 200 - getY() - getHeight() + 200 = 400 - getY() - getHeight()
        【解决方案4】:

        [编辑:我想我误解了,所以这可能没什么用:)]

        if(getY() + getHeight() > 200){
          yspeed *= -0.981;
        }
        

        您在每次更新时都在否定垂直速度。我可能会尝试在更新大小的切片中处理重力。假设您每秒进行 30 次更新(对于 30fps),可能类似于

        // Define some constants
        SecondsPerUpdate = (1.0f / 30);
        AccelDueToGravity = 0.981;
        
        if(getY() + getHeight() > 200){
          yspeed -= (AccelDueToGravity * SecondsPerUpdate);
        }
        

        【讨论】:

          【解决方案5】:

          我怀疑这是因为当球反弹时,它实际上会略低于“地面”,并且在低速时,它不会在一个滴答声中移回地面 - 所以下一个 update() 会看到它仍然在地面以下,然后再次反弹 - 但这次向下,所以循环继续。

          当球弹起时,您需要将球移回地面,如下所示:

              if(getY() + getHeight() > 200){
                      yspeed *= -0.981;
                      setY(200 - getHeight());
              }
          

          【讨论】:

          • 移动似乎需要增量,而不是绝对值,你的球很可能会飞出宇宙的边缘:-)
          猜你喜欢
          • 2012-10-12
          • 2021-08-12
          • 2021-06-20
          • 1970-01-01
          • 2013-05-23
          • 1970-01-01
          • 1970-01-01
          • 2017-01-16
          • 1970-01-01
          相关资源
          最近更新 更多