diff --git a/overlay/rootfs/usr/bin/snake b/overlay/rootfs/usr/bin/snake index eb21fd5..ed4eb61 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 ece86ab..3d8790f 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 eb21fd5..ed4eb61 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 ece86ab..3d8790f 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 08a96a0..49f49b0 100644 --- a/src/games/snake.cpp +++ b/src/games/snake.cpp @@ -102,13 +102,12 @@ static State state = PLAYING; static int snake[COLS * ROWS][2]; // x,y per segment (0 = tail) static int snakelen = 4; static int dirx = 1, diry = 0; // current direction -static int tqx[4], tqy[4]; // queued pending turns (rapid presses not lost) -static int tqh = 0, tqt = 0, tqn = 0; +static int ndirx = 1, ndiry = 0; // buffered next direction (latest keypress wins) static int foodx, foody; static int score = 0; static int best = 0; static int speed = 90; // ms per step (derived from pps below) -static int pps = 130; // base speed px/sec; +1 px/sec per 5 food eaten +static int pps = 100; // 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() { @@ -164,33 +163,19 @@ static void reset_game() { snake[i][1] = cy; } dirx = 1; diry = 0; - tqh = tqt = tqn = 0; + ndirx = 1; ndiry = 0; score = 0; - pps = 130; + pps = 100; update_speed(); place_food(); state = PLAYING; nextTick = now_ms() + speed; } -// Queue a pending direction change; rapid key presses are stored so none are lost. -static void tq_push(int dx, int dy) { - if (tqn >= 4) return; // queue full: drop the new turn - tqx[(tqh + tqn) % 4] = dx; - tqy[(tqh + tqn) % 4] = dy; - tqn++; -} - static void step() { - // apply the oldest queued turn (no reversing); rapid presses are not lost - int tdx = 0, tdy = 0; - if (tqn > 0) { - tdx = tqx[tqt]; tdy = tqy[tqt]; - tqt = (tqt + 1) % 4; - tqn--; - } - if (!(tdx == -dirx && tdy == -diry) && !(tdx == 0 && tdy == 0)) { - dirx = tdx; diry = tdy; + // apply buffered direction (no reversing); latest keypress wins + if (!(ndirx == -dirx && ndiry == -diry) && !(ndirx == 0 && ndiry == 0)) { + dirx = ndirx; diry = ndiry; } int hx = snake[snakelen - 1][0] + dirx; int hy = snake[snakelen - 1][1] + diry; @@ -217,7 +202,7 @@ static void step() { score += 10; if (score > best) best = score; int food = score / 10; // food items eaten so far - pps = 130 + food / 5; // +1 px/sec per 5 food eaten (progressive difficulty) + pps = 100 + food / 5; // +1 px/sec per 5 food eaten (progressive difficulty) update_speed(); place_food(); } @@ -288,13 +273,13 @@ static void render() { static void handle_key(KeySym ks) { switch (ks) { case XK_Up: case XK_w: case XK_KP_Up: case XK_2: - tq_push(0, -1); break; + ndirx = 0; ndiry = -1; break; case XK_Down: case XK_s: case XK_KP_Down: case XK_8: case XK_x: - tq_push(0, 1); break; + ndirx = 0; ndiry = 1; break; case XK_Left: case XK_a: case XK_KP_Left: case XK_4: - tq_push(-1, 0); break; + ndirx = -1; ndiry = 0; break; case XK_Right: case XK_d: case XK_KP_Right: case XK_6: - tq_push(1, 0); break; + ndirx = 1; ndiry = 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; } @@ -390,12 +375,19 @@ int main() { render(); int xfd = ConnectionNumber(dpy); + const unsigned long FRAME_MS = 1000 / 60; // 60 fps rendering + unsigned long lastFrame = now_ms(); + while (running) { - long until = (long)nextTick - (long)now_ms(); + unsigned long now = now_ms(); + long until = (long)nextTick - (long)now; if (until < 0) until = 0; + // Never block select longer than one frame so the screen stays smooth + long wait = (until < (long)FRAME_MS) ? until : (long)FRAME_MS; + struct timeval tv; - tv.tv_sec = until / 1000; - tv.tv_usec = (until % 1000) * 1000; + tv.tv_sec = wait / 1000; + tv.tv_usec = (wait % 1000) * 1000; fd_set fds; FD_ZERO(&fds); FD_SET(xfd, &fds); @@ -407,17 +399,22 @@ int main() { XNextEvent(dpy, &e); handle_event(e); if (!running) break; + dirty = true; } if (!running) break; - dirty = true; } - if (running && now_ms() >= nextTick) { + now = now_ms(); + if (running && now >= nextTick) { if (state == PLAYING) step(); - if (state == PLAYING) nextTick = now_ms() + speed; - else nextTick = now_ms() + 80; // keep loop responsive while paused/over + if (state == PLAYING) nextTick = now + speed; + else nextTick = now + 80; // keep loop responsive while paused/over dirty = true; } - if (dirty) render(); + // Render at 60 fps or whenever state changed + if (dirty || now - lastFrame >= FRAME_MS) { + render(); + lastFrame = now; + } } XFreeGC(dpy, gc); diff --git a/src/games/tetris.cpp b/src/games/tetris.cpp index 8d5576d..86b0d81 100644 --- a/src/games/tetris.cpp +++ b/src/games/tetris.cpp @@ -499,12 +499,19 @@ int main() { render(); int xfd = ConnectionNumber(dpy); + const unsigned long FRAME_MS = 1000 / 60; // 60 fps rendering + unsigned long lastFrame = now_ms(); + while (running) { - long until = (long)nextTick - (long)now_ms(); + unsigned long now = now_ms(); + long until = (long)nextTick - (long)now; if (until < 0) until = 0; + // Never block select longer than one frame so the screen stays smooth + long wait = (until < (long)FRAME_MS) ? until : (long)FRAME_MS; + struct timeval tv; - tv.tv_sec = until / 1000; - tv.tv_usec = (until % 1000) * 1000; + tv.tv_sec = wait / 1000; + tv.tv_usec = (wait % 1000) * 1000; fd_set fds; FD_ZERO(&fds); FD_SET(xfd, &fds); @@ -516,17 +523,22 @@ int main() { XNextEvent(dpy, &e); handle_event(e); if (!running) break; + dirty = true; } if (!running) break; - dirty = true; } - if (running && now_ms() >= nextTick) { + now = now_ms(); + if (running && now >= nextTick) { if (state == PLAYING) step(); - if (state == PLAYING) nextTick = now_ms() + speed; - else nextTick = now_ms() + 80; + if (state == PLAYING) nextTick = now + speed; + else nextTick = now + 80; dirty = true; } - if (dirty) render(); + // Render at 60 fps or whenever state changed + if (dirty || now - lastFrame >= FRAME_MS) { + render(); + lastFrame = now; + } } XFreeGC(dpy, gc);