One Frame Behind Forever — Java Bug Hunt
Inspired by the fixed-timestep game loops described in every "Fix Your Timestep!" postmortem: the accumulator pattern must run whole simulation frames and…
- Language: Java
- Layer: Frontend
- Difficulty: Hard
- Concepts: Game Loops, Rounding
- Modelled on: Game engines
- Visible tests: underfunded frames do not run; full frames run with exact remainder; exact multiples leave zero remainder
- Reward: 50 XP for a complete fix
Briefing
Inspired by the fixed-timestep game loops described in every "Fix Your Timestep!" postmortem: the accumulator pattern must run whole simulation frames and carry the exact remainder. Round instead of floor, and the simulation runs frames it hasn't earned — leaving a negative time debt that compounds into stutter.
GameLoop.java computes frames-to-run from the accumulator.
Bug report
BUG-TIMESTEP · Reported by: engine team
framesToRun(accumulatorMs, frameMs) -> int[]{frames, remainderMs}:
- frames = floor(accumulator / frame) — only FULLY funded frames
- remainder = accumulator - frames * frame (always 0 <= r < frame)
Observed: 15ms of accumulated time runs a 16ms frame — remainder -1ms. The debt snowballs and the camera micro-stutters forever.
Logs
[loop] acc=15 frame=16 -> ran 1 frame, remainder -1The code as shipped
GameLoop.java (editable)
class GameLoop {
static int[] framesToRun(int accumulatorMs, int frameMs) {
int frames = Math.round((float) accumulatorMs / frameMs);
int remainder = accumulatorMs - frames * frameMs;
return new int[] { frames, remainder };
}
}Open the hunt to edit the files, run the visible tests and submit against the hidden ones. More Java bug hunts.