I am writing a simple bouncing balls animation, where the balls bounce off the walls and the other balls. I am following the worm example from “Killer Game Programming in Java”. Here is my main game loop:
public void run() {
long beforeTime, afterTime, timeDiff, sleepTime;
long overSleepTime = 0L;
int noDelays = 0;
long excess = 0L;
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
isRunning = true;
gameStartTime = System.nanoTime();
prevStatsTime = gameStartTime;
beforeTime = gameStartTime;
while (isRunning) {
nextFrame(period/1000000L);
updateDisplay();
afterTime = System.nanoTime();
timeDiff = afterTime - beforeTime;
sleepTime = (period - timeDiff) - overSleepTime;
if (sleepTime > 0) {
try {
Thread.sleep(sleepTime / 1000000L /* nanosecs -> ms */);
} catch (InterruptedException ex) {
// do nothing
}
overSleepTime = (System.nanoTime() - afterTime) - sleepTime;
} else { // sleepTime <= 0; the frame took longer than the period
excess -= sleepTime; // store excess time value
overSleepTime = 0L;
if (++noDelays >= NO_DELAYS_PER_YIELD) {
Thread.yield(); // give another thread a chance to run
noDelays = 0;
}
}
beforeTime = System.nanoTime();
/*
* If frame animation is taking too long, update the game state
* without rendering it, to get the updates/sec nearer to the
* required FPS.
*/
int skips = 0;
while ((excess > period) && (skips < MAX_FRAME_SKIPS)) {
excess -= period;
nextFrame(period/1000000L); // update state but don't render
skips++;
}
framesSkipped += skips;
updateStats();
}
}
And here is my the code for updating the animation state:
public void nextFrame(double t) { // t is in microseconds
if (isPaused) return;
// t is the time of the earliest collision.
// if t == RATE then there are either no collisions
// or collision occur at time RATE
// Since only the earliest collision needs to be found,
// the collision test are performed for the current
// time of the earliest collision (t).
// Test for wall collisions
for (int i = 0; i < balls.length; i++) {
t = Math.min(t, balls[i].testWallCollision(t));
}
// Test for ball collisions
// collision are added to the head of this list
List<Collision> collisions = new LinkedList<Collision>();
Ball a, b;
for (int i = 0; i < balls.length; i++) {
a = balls[i];
for (int j = i+1; j < balls.length; j++) {
b = balls[j];
t = Math.min(t, a.testBallCollision(b, t, collisions));
}
}
// Move the balls
for (int i = 0; i < balls.length; i++) {
balls[i].move(t);
}
// Handle the collisions that occured
// NOTE: It is possible that two collision occurred at the
// same time. Therefore the collision list is iterated
// until we get to a collision that occured after the
// time of the first collision
for (Collision c : collisions) {
if (c.t == t) {
c.handle();
} else {
break;
}
}
}
My problem is that I want the frame to update according to how much time has passed since the last frame. At the moment I just assign t to the period (converting to ms) . Should I pass in timeDiff from the last loop instead (for the first nextFrame call that is rendered)?
Also multiple collisions may have occured since the last frame. At the moment I update the state to the time of first collision (or t if no collisions occured). I should continue to handle collision until no collisions are left for the frame. However will this not likely mean the nextFrame() method takes too much CPU time before we paint the next frame? How should I be handling this?