diff --git a/overlay/rootfs/usr/bin/snake b/overlay/rootfs/usr/bin/snake index a731467..9f8bcdf 100755 Binary files a/overlay/rootfs/usr/bin/snake and b/overlay/rootfs/usr/bin/snake differ diff --git a/overlay/rootfs/usr/bin/tetris b/overlay/rootfs/usr/bin/tetris index d6d8988..84af923 100755 Binary files a/overlay/rootfs/usr/bin/tetris and b/overlay/rootfs/usr/bin/tetris differ diff --git a/prebuilt/games/usr/bin/snake b/prebuilt/games/usr/bin/snake index a731467..9f8bcdf 100755 Binary files a/prebuilt/games/usr/bin/snake and b/prebuilt/games/usr/bin/snake differ diff --git a/prebuilt/games/usr/bin/tetris b/prebuilt/games/usr/bin/tetris index d6d8988..84af923 100755 Binary files a/prebuilt/games/usr/bin/tetris and b/prebuilt/games/usr/bin/tetris differ diff --git a/src/games/snake.cpp b/src/games/snake.cpp index 67dca9a..c657105 100644 --- a/src/games/snake.cpp +++ b/src/games/snake.cpp @@ -109,7 +109,6 @@ static int score = 0; static int best = 0; static int speed = 100; // ms per step (derived from pps below) static int pps = 90; // base speed px/sec; +1 px/sec per 5 food eaten -static unsigned long nextTick = 0; static bool running = true; static unsigned long now_ms() { struct timeval tv; @@ -170,7 +169,6 @@ static void reset_game() { update_speed(); place_food(); state = PLAYING; - nextTick = now_ms() + speed; } // Queue a pending direction change; rapid key presses are stored so none are lost. @@ -224,12 +222,10 @@ static void step() { score += 10; if (score > best) best = score; int food = score / 10; // food items eaten so far - pps = 90 + food / 5; // +1 px/sec per 5 food eaten (progressive difficulty) + pps = 90 + food / 5; // +1 px/sec per 5 food eaten (progressive difficulty) update_speed(); place_food(); } - if (nextTick < now_ms()) nextTick = now_ms(); - nextTick += speed; } static void draw_text(int x, int y, int scale, unsigned long col, const char* s) { @@ -251,7 +247,6 @@ static void render() { XSetForeground(dpy, gc, C_BG); XFillRectangle(dpy, back, gc, 0, 0, winW, winH); - // playfield border (single clean frame around the grid) // border framing the whole window (adapts to the actual screen size) XSetForeground(dpy, gc, C_DIM); XDrawRectangle(dpy, back, gc, 2, 2, winW - 4, winH - 4); @@ -315,12 +310,11 @@ static void handle_key(KeySym ks) { tq_push(1, 0); break; case XK_5: case XK_Return: case XK_KP_Enter: case XK_space: case XK_p: if (state == PLAYING) state = PAUSED; - else if (state == PAUSED) { state = PLAYING; nextTick = now_ms() + speed; } + else if (state == PAUSED) { state = PLAYING; } else if (state == GAMEOVER) reset_game(); break; case XK_Escape: case XK_BackSpace: case XK_Delete: case XK_End: case XK_Menu: - // quit is handled by the caller via a flag running = false; break; default: @@ -409,7 +403,8 @@ int main() { int xfd = ConnectionNumber(dpy); const unsigned long FRAME_MS = 1000 / 30; // 30 fps rendering - unsigned long frameStart = now_ms(); + unsigned long lastFrame = now_ms(); + unsigned long accumulator = 0; while (running) { // Process all pending input immediately (non-blocking) before each frame @@ -422,12 +417,21 @@ int main() { if (!running) break; unsigned long now = now_ms(); + unsigned long elapsed = now - lastFrame; + lastFrame = now; - // Game logic step at its own rate - if (now >= nextTick) { + // Cap elapsed time to prevent spiral of death + if (elapsed > 200) elapsed = 200; + + // Accumulate time + accumulator += elapsed; + + // Step game logic at fixed rate (max 2 steps per frame to prevent spiral) + int steps = 0; + while (accumulator >= (unsigned long)speed && steps < 2) { if (state == PLAYING) step(); - if (nextTick < now) nextTick = now; - nextTick += (state == PLAYING ? speed : 80); + accumulator -= speed; + steps++; } // Render every frame @@ -435,8 +439,8 @@ int main() { // Frame pacing: sleep until next frame, but wake up immediately on input now = now_ms(); - long sleepMs = (long)FRAME_MS - (long)(now - frameStart); - if (sleepMs > 0) { + long sleepMs = (long)FRAME_MS - (long)(now - (lastFrame - elapsed)); + if (sleepMs > 0 && sleepMs <= (long)FRAME_MS) { struct timeval tv; tv.tv_sec = sleepMs / 1000; tv.tv_usec = (sleepMs % 1000) * 1000; @@ -445,7 +449,6 @@ int main() { FD_SET(xfd, &fds); select(xfd + 1, &fds, nullptr, nullptr, &tv); } - frameStart = now_ms(); } XFreeGC(dpy, gc); diff --git a/src/games/tetris.cpp b/src/games/tetris.cpp index 48ebfd1..def1d2a 100644 --- a/src/games/tetris.cpp +++ b/src/games/tetris.cpp @@ -97,8 +97,6 @@ static unsigned long C_GB_DARK, C_GB_MED, C_GB_LIGHT, C_GB_PALE; // ---- tetromino definitions (state 0 within a 4x4 box) ---- // type 0..6 -> I,O,T,S,Z,J,L -// 7 tetrominoes, each with 4 explicit rotation states (classic SRS-style). -// type 0..6 -> I,O,T,S,Z,J,L. Coordinates are within a 4x4 box [x,y]. static const int SHAPES[7][4][4][2] = { { {{0,1},{1,1},{2,1},{3,1}}, {{2,0},{2,1},{2,2},{2,3}}, {{0,2},{1,2},{2,2},{3,2}}, {{1,0},{1,1},{1,2},{1,3}} }, // I { {{1,0},{2,0},{1,1},{2,1}}, {{1,0},{2,0},{1,1},{2,1}}, {{1,0},{2,0},{1,1},{2,1}}, {{1,0},{2,0},{1,1},{2,1}} }, // O @@ -117,7 +115,6 @@ static int nextType = 0; static int score = 0, best = 0, lines = 0, level = 1; static int speed = 600; // ms per gravity step (derived from pps below) static int pps = 23; // base speed px/sec; +1 px/sec per 10 lines cleared -static unsigned long nextTick = 0; static bool running = true; static void piece_cells(int type, int rot, int out[4][2]) { @@ -165,7 +162,6 @@ static void spawn() { state = GAMEOVER; if (score > best) best = score; } - nextTick = now_ms() + speed; } static void lock_piece() { @@ -337,15 +333,15 @@ static void render() { int boxY = py0 + 10; int boxH = 52; XSetForeground(dpy, gc, C_DIM); - XDrawRectangle(dpy, back, gc, sx - 2, boxY + 1, winW - sx - 3, boxH); // frame 2px left, 1px down, 1px wider (piece unchanged) + XDrawRectangle(dpy, back, gc, sx - 2, boxY + 1, winW - sx - 3, boxH); int nc[4][2]; piece_cells(nextType, 0, nc); int minx = 4, miny = 4, maxx = -1, maxy = -1; for (int i = 0; i < 4; i++) { minx = nc[i][0] < minx ? nc[i][0] : minx; - miny = nc[i][1] < miny ? miny : miny; + miny = nc[i][1] < miny ? nc[i][1] : miny; maxx = nc[i][0] > maxx ? nc[i][0] : maxx; - maxy = nc[i][1] > maxy ? maxy : maxy; + maxy = nc[i][1] > maxy ? nc[i][1] : maxy; } int pcell = 11; // larger next-piece preview int pcols = maxx - minx + 1; @@ -475,14 +471,14 @@ static void handle_key(KeySym ks) { if (state == PLAYING) { state = PAUSED; } else if (state == PAUSED) { - state = PLAYING; nextTick = now_ms() + speed; + state = PLAYING; } break; case XK_5: case XK_Return: case XK_KP_Enter: if (state == PLAYING) { hard_drop(); } else if (state == PAUSED) { - state = PLAYING; nextTick = now_ms() + speed; + state = PLAYING; } else if (state == GAMEOVER) { reset_game(); } @@ -521,7 +517,8 @@ int main() { int xfd = ConnectionNumber(dpy); const unsigned long FRAME_MS = 1000 / 30; // 30 fps rendering - unsigned long frameStart = now_ms(); + unsigned long lastFrame = now_ms(); + unsigned long accumulator = 0; while (running) { // Process all pending input immediately (non-blocking) before each frame @@ -534,12 +531,21 @@ int main() { if (!running) break; unsigned long now = now_ms(); + unsigned long elapsed = now - lastFrame; + lastFrame = now; - // Game logic step at its own rate - if (now >= nextTick) { + // Cap elapsed time to prevent spiral of death + if (elapsed > 200) elapsed = 200; + + // Accumulate time + accumulator += elapsed; + + // Step game logic at fixed rate (max 2 steps per frame to prevent spiral) + int steps = 0; + while (accumulator >= (unsigned long)speed && steps < 2) { if (state == PLAYING) step(); - if (nextTick < now) nextTick = now; - nextTick += (state == PLAYING ? speed : 80); + accumulator -= speed; + steps++; } // Render every frame @@ -547,8 +553,8 @@ int main() { // Frame pacing: sleep until next frame, but wake up immediately on input now = now_ms(); - long sleepMs = (long)FRAME_MS - (long)(now - frameStart); - if (sleepMs > 0) { + long sleepMs = (long)FRAME_MS - (long)(now - (lastFrame - elapsed)); + if (sleepMs > 0 && sleepMs <= (long)FRAME_MS) { struct timeval tv; tv.tv_sec = sleepMs / 1000; tv.tv_usec = (sleepMs % 1000) * 1000; @@ -557,7 +563,6 @@ int main() { FD_SET(xfd, &fds); select(xfd + 1, &fds, nullptr, nullptr, &tv); } - frameStart = now_ms(); } XFreeGC(dpy, gc);