Mehul Mohan - 4 months ago 5x
Android Question

# Why is the energy of this ball is increasing?

I've been trying from hours to setup gravity and relate it to time or what we call frame independent bounce ball. I did everything correct I guess, and I tried to implement the system where height of ball would decrease after every bounce. I did not even start that, and my code is creating something absurd I don't understand why. Here's my code:

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

currentFrame = System.currentTimeMillis();

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

lastFrame = currentFrame;

myFreakinRect.set(0,0, canvas.getWidth(), canvas.getHeight());
freakinRed.setColor(Color.RED);
freakinRed.setStyle(Paint.Style.FILL);
canvas.drawRect(myFreakinRect, freakinRed);

//

// o yuea

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

if(posX > w - ballRadius*2) {
goingRight = false;
}
if(posX < 0) {
goingRight = true;
}
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;
}
if(velocityY <= 0) {
goingDown = true;
runTime = currentFrame;
}

if(goingDown) posY += velocityY*dt;
else posY -= velocityY*dt;

if(goingRight) posX += velocityX*dt;
else posX -= velocityX*dt;

canvas.drawText(String.valueOf(posX)+"  "+String.valueOf(posY), 10, 10, new Paint());
canvas.drawBitmap(rBall, (float)posX, (float)posY, myFreakingFaintPaint);

invalidate();
}
``````

Here's a GIF what is happening:

UPDATE:

Here's my updated code which is clean, understandable and works perfect:

``````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();
}
``````

Here ...

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

... you update the velocity (speed, actually) assuming that the ball will not bounce during this frame.

Then here ...

``````    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;
}
``````

... you have not yet updated `posY`, so you are determining whether the ball hit the floor as a result of the previous update. If it did, you reverse the direction of motion, but keep the speed you already computed for this frame. As a result, each time the ball bounces, its initial upward speed is one frame's worth of acceleration greater than the speed it was traveling when it hit the floor.

You have a similar effect at the top of the ball's motion, but it's smaller because the speed is small there.

There are a couple of ways you might solve this problem. The simplest is probably to perform the bounce check after the position update instead of before.

• use the signs of your X and Y speeds instead of separate direction-of-motion flags (thus making the names `velocityY` etc. accurate). Your code will be simpler, and you'll need to handle only one change of vertical direction, not two, because the equations of motion will handle the other automatically.
• this computation is suspicious: `dt = dt/1000`. Since `dt` seems to be computed from `System.currentTimeMillis()`, I am inclined to guess that it, too, has type `long`. In that case, you are performing an integer division and thereby losing precision.