为什么这个球的能量在增加?

时间:2016-06-06 19:11:15

标签: java android game-physics

我一直在努力设置引力并将其与时间或我们称之为独立于框架的弹跳球联系起来。我猜想我做的一切都是正确的,并且我试图实现每次弹跳后球的高度都会降低的系统。我甚至没有开始,我的代码创造了一些荒谬的东西,我不明白为什么。这是我的代码:

protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        currentFrame = System.currentTimeMillis();

        dt = currentFrame - lastFrame;
        dt = dt/1000;

        lastFrame = currentFrame;

        velocityY = downV + gravity*(currentFrame - runTime);
        posY += velocityY*dt;
        posX += velocityX*dt;
        if(posX > w - ballRadius*2 || posX < 0) {
            velocityX = -velocityX;
        }

        if(posY >= h - ballRadius*2) {
            posY = h - ballRadius*2 - 2;
            runTime = currentFrame;
            downV = -0.8*velocityY;
        }

        canvas.drawBitmap(rBall, (float)posX, (float)posY, null);


        invalidate();
    }

这是GIF正在发生的事情:

enter image description here

更新

这是我的更新代码,它干净,易懂且完美无缺:

foreach my $id (keys %SERVICES)
{
  my $des = $SERVICES{$id}{'description'};
  print "$des\n";
}

2 个答案:

答案 0 :(得分:2)

这里......

    if(goingDown) {
        //velocityY = Math.sqrt(100 + 2*gravity*(posY));
        velocityY = gravity*(currentFrame - runTime);
    } else {
        velocityY = downV - gravity*(currentFrame - runTime);
    }

...你更新速度(实际速度),假设球在此帧期间不会反弹。

然后在这里......

    if(posY > h - ballRadius*2) {
        //initY = initY - 0.25F;
        //if(initY < 0) initY = 0;
        Log.i("xxx", String.valueOf(initY));
        runTime = currentFrame;
        downV = velocityY;
        goingDown = false;
    }

...你还没有更新posY,所以你要确定球是否因之前的更新而落地。如果是,则反转运动方向,但保持已为此帧计算的速度。结果,每次球反弹时,其初始向上速度是一帧的加速度,大于它撞击地面时的速度。

你在球的运动顶部有类似的效果,但它更小,因为那里的速度很小。

有几种方法可以解决这个问题。最简单的可能是在位置更新之后而不是之前执行跳回检查。

附加说明:

  • 使用X和Y速度的符号而不是单独的运动方向标志(从而使名称velocityY 。准确)。你的代码会更简单,你只需要处理一个垂直方向的变化,而不是两个,因为运动方程将自动处理另一个。

  • 你有一点精度问题,因为你假设球在整个框架中以相同的方向行进。如果你允许球达到高速,这可能会变得明显:它会在弹回之前穿透地板。

  • 这个计算是可疑的:dt = dt/1000。由于dt似乎是根据System.currentTimeMillis()计算出来的,所以我倾向于猜测它也有类型long。在这种情况下,您正在执行整数除法,从而失去精度。

答案 1 :(得分:1)

一般来说:
分成模型和视图。在这种情况下,渲染仍然运行良好,因为计算非常轻量级,但是您不应该在渲染例程中运行与绘制内容无直接关系的代码。

下一点:
如果您模拟物理,请尽可能贴近现实。您可以随后进行优化,但首先要确保您的代码实际上正在执行它应该执行的操作。我目前正在玩弹丸运动,所以我对代码应该做什么有一个基本的想法。到目前为止,我一直试图了解你的代码10分钟。中期结果:我很困惑,也不太明白。

我的建议:
从更清晰的代码开始,尽量贴近物理规则。这段代码并没有尽可能优化,但它的可读性,可理解性和模拟性与现实生活相近。这使得调试变得更加简单:

final double GRAVITY = -9.81;
final double BALL_ELASTICITY = 0.95;

double vx, vy;
double x, y;

//dt is delta-time in seconds!!!
void simulateBall(double dt){
    //calculate when the ball will touch the floor the next time
    double next_floor_touch = (-vy + Math.sqrt(vy * vy - 2 * GRAVITY * y)) / GRAVITY;
    double after_floor_touch = dt - next_floor_touch;
    boolean touches_floor = (next_floor_touch <= dt);

    //calculate new y
    if(touches_floor){
        //predict the speed the ball will have, after it bounces from the floor
        double vy_at_floor = vy + GRAVITY * next_floor_touch;
        double vy_from_floor = vy_at_floor * (-1) * BALL_ELASTICITY;

        //predict y starting from the floor at t = next_floor_touch until dt
        y = 0 + vy_from_floor * after_floor_touch + 0.5 * GRAVITY * after_floor_touch * after_floor_touch;
     }else{
        //uniform acceleration
        y = y + vy * dt + 0.5 * GRAVITY * dt * dt;
     }

     //calculate vy
     if(touches_floor){
         //see above
         double vy_after_floor = (vy + GRAVITY * next_floor_touch) * (-1) * BALL_ELASTICITY;
         vy = vy_after_floor + GRAVITY * after_floor_touch;
     }else{
         vy = vy + GRAVITY * dt;
     }

     ... //that's already the hardest part
}

这使用quadratic equation来预测球何时会到达地面,uniform acceleration来计算从给定位置,速度和加速度开始的位置。除非我在计算中犯了任何错误(此代码未经测试),否则这应该是物理上精确的。 BALL_ELASTICITY表示球击中地板后剩余的速度。这在身体上并不精确 - 可能是,IDK - 但应该为此目的。