I’m writing a little program based on the LunarLander example project. What I want to achieve is to update my SurfaceView (reposition some Drawables mainly) between fixed intervals like this one:
private static final int UPDATE_INTERVAL = 1000 / 20; // 20 FPS
I’m running a Thread which is doing this in its run() method:
@Override
public void run() {
while (isRunning) {
Canvas c = null;
try {
c = view.getSurfaceHolder().lockCanvas(null);
synchronized (view.getSurfaceHolder()) {
if (GameState.RUNNING.equals(state)) {
long now = System.currentTimeMillis();
if (now - lastUpdate > UPDATE_INTERVAL) {
lastUpdate = now;
updater.updatePieces();
}
doDraw(c);
}
}
} finally {
if (c != null) {
view.getSurfaceHolder().unlockCanvasAndPost(c);
}
}
}
}
My problem is that it is possible that this Thread is busy waiting for the (now - lastUpdate > UPDATE_INTERVAL) condition to be true. But there is an other case if redrawing takes more than 1000 / 20 seconds. This means that the animation is not always seamless. I tried it out in my emulator and it is usually OK but sometimes my Drawable is slowing down and after that it speeds up for approximately a half second. Is this just the emulator or something else?
I won’t bother you with the details, updatePieces() just moves a little circle from top to bottom. I’m not creating any new objects. I somehow get the feeling that this piece of code is not right. Is this a good practice for animating Drawables or I’m missing something obvious? I’m kind of new in this topic.
I propagate touch and key events from the UI thread to this one so I don’t really want to call sleep() in this Thread because it may cause the UI thread to become unresponsive.
Think about how objects react in reality. An object moves a certain distance. The distance it will move in a certain amount of time is dependent on a velocity. Velocity is dependent on the very last acceleration. Distance, velocity and acceleration all depends on time.
In your code, you do not deal with time at all and therefore there is no real world interpretation to your current code. Put together your physics like this:
For example:
Knowing a little physics help to understand why this makes sense:
is basically Newton’s second law,
F = ma.works because what we’re doing is to multiply acceleration
m/s^2by times. This will give you how much the velocity has changed since the previous frame. Simple cancellation gives us(m/s^2)*s = m*s/s^2 = m/s. Add the previous velocity and your done.The same logic applies to:
Note that you may have to add a scale factor to multiply with in order to make the physics realistic to your screen – like how many pixels equals five meter, or something like that.
There are tons of articles describing this, one for example is Integration Basics by Glenn Fiedler. Search and you will find more.