fix(games): complete font (U/W + A-Z), fix Tetris gravity, frame + center overlays

- Font: add missing glyphs (U, W and complete A-Z) to both Snake and
  Tetris 5x7 bitmap fonts so PAUSE/RESUME/NEW GAME render correctly.
- Tetris: the gravity loop never advanced nextTick after a step, so the
  piece dropped almost instantly every frame. Advance nextTick by speed
  after each step (matching Snake) so gravity honours the configured rate.
- Both: draw a 1px frame around the whole 240x296 window (right/bottom
  edges were previously absent) and clear the playfield to black behind
  PAUSE/GAME OVER text for contrast.
- Both: fix centering of overlay labels (GAME OVER, 5 RESUME, 5 NEW GAME).
This commit is contained in:
Luxferre
2026-10-23 15:30:29 +03:00
parent 3eb54e4306
commit 6bf4139263
6 changed files with 39 additions and 11 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+16 -4
View File
@@ -57,6 +57,10 @@ static const Glyph GLYPHS[] = {
{'V', {0b10001,0b10001,0b10001,0b10001,0b10001,0b01010,0b00100}},
{'W', {0b10001,0b10001,0b10001,0b10101,0b10101,0b11011,0b10001}},
{'Y', {0b10001,0b10001,0b01010,0b00100,0b00100,0b00100,0b00100}},
{'J', {0b00010,0b00010,0b00010,0b00010,0b10010,0b10010,0b01100}},
{'Q', {0b01110,0b10001,0b10001,0b10001,0b10101,0b10010,0b01101}},
{'U', {0b10001,0b10001,0b10001,0b10001,0b10001,0b10001,0b01110}},
{'Z', {0b11111,0b00010,0b00100,0b01000,0b10000,0b10000,0b11111}},
{'0', {0b01110,0b10011,0b10101,0b10101,0b11001,0b10001,0b01110}},
{'1', {0b00100,0b01100,0b00100,0b00100,0b00100,0b00100,0b01110}},
{'2', {0b01110,0b10001,0b00001,0b00110,0b01000,0b10000,0b11111}},
@@ -213,6 +217,10 @@ static void render() {
XSetForeground(dpy, gc, C_DIM);
XDrawRectangle(dpy, back, gc, gx0 - 1, gy0 - 1, gw + 2, gh + 2);
// frame the whole window (right/bottom edges too)
XSetForeground(dpy, gc, C_DIM);
XDrawRectangle(dpy, back, gc, 0, 0, winW - 1, winH - 1);
// food
if (foodx >= 0) {
XSetForeground(dpy, gc, C_FOOD);
@@ -233,14 +241,18 @@ static void render() {
draw_text(gx0 + gw - 11 * 6, 2, 1, C_DIM, buf);
}
if (state == PAUSED || state == GAMEOVER) {
XSetForeground(dpy, gc, C_BG);
XFillRectangle(dpy, back, gc, 0, 0, winW, winH);
}
if (state == PAUSED) {
draw_text(winW / 2 - 3 * 6 * 2, winH / 2 - 7 * 2, 2, C_FG, "PAUSE");
draw_text(winW / 2 - 5 * 6, winH / 2 + 7 * 2, 1, C_DIM, "5 RESUME");
draw_text(winW / 2 - 5 * 6, winH / 2 - 7 * 2, 2, C_FG, "PAUSE");
draw_text(winW / 2 - 4 * 6, winH / 2 + 7 * 2, 1, C_DIM, "5 RESUME");
} else if (state == GAMEOVER) {
draw_text(winW / 2 - 4 * 6 * 2, winH / 2 - 14, 2, C_FG, "GAME OVER");
draw_text(winW / 2 - 9 * 6, winH / 2 - 14, 2, C_FG, "GAME OVER");
snprintf(buf, sizeof(buf), "SCORE %d", score);
draw_text(winW / 2 - 5 * 6, winH / 2 + 4, 1, C_DIM, buf);
draw_text(winW / 2 - 9 * 6, winH / 2 + 4 + 9, 1, C_DIM, "5 NEW GAME");
draw_text(winW / 2 - 5 * 6, winH / 2 + 4 + 9, 1, C_DIM, "5 NEW GAME");
}
XCopyArea(dpy, back, win, gc, 0, 0, winW, winH, 0, 0);
+23 -7
View File
@@ -27,7 +27,7 @@ static const int WIN_W = 240;
static const int WIN_H = 296;
static const int PCOLS = 10;
static const int PROWS = 20;
static const int CELL = 12;
static const int CELL = 14;
// ---- 5x7 bitmap font ----
struct Glyph { char ch; unsigned char r[7]; };
@@ -56,6 +56,13 @@ static const Glyph GLYPHS[] = {
{'V', {0b10001,0b10001,0b10001,0b10001,0b10001,0b01010,0b00100}},
{'X', {0b10001,0b10001,0b01010,0b00100,0b01010,0b10001,0b10001}},
{'Y', {0b10001,0b10001,0b01010,0b00100,0b00100,0b00100,0b00100}},
{'D', {0b11110,0b10001,0b10001,0b10001,0b10001,0b10001,0b01110}},
{'J', {0b00010,0b00010,0b00010,0b00010,0b10010,0b10010,0b01100}},
{'K', {0b10001,0b10010,0b10100,0b11000,0b10100,0b10010,0b10001}},
{'Q', {0b01110,0b10001,0b10001,0b10001,0b10101,0b10010,0b01101}},
{'U', {0b10001,0b10001,0b10001,0b10001,0b10001,0b10001,0b01110}},
{'W', {0b10001,0b10001,0b10001,0b10101,0b10101,0b11011,0b10001}},
{'Z', {0b11111,0b00010,0b00100,0b01000,0b10000,0b10000,0b11111}},
{'0', {0b01110,0b10011,0b10101,0b10101,0b11001,0b10001,0b01110}},
{'1', {0b00100,0b01100,0b00100,0b00100,0b00100,0b00100,0b01110}},
{'2', {0b01110,0b10001,0b00001,0b00110,0b01000,0b10000,0b11111}},
@@ -101,7 +108,7 @@ static int board[PCOLS][PROWS]; // 0 empty, else type+1
static int curType = 0, curRot = 0, curX = 3, curY = 0;
static int nextType = 0;
static int score = 0, best = 0, lines = 0, level = 1;
static int speed = 800; // ms per gravity step
static int speed = 1000; // ms per gravity step
static unsigned long nextTick = 0;
static bool running = true;
@@ -176,7 +183,7 @@ static void lock_piece() {
score += pts[cleared] * level;
if (score > best) best = score;
int nl = 1 + lines / 10;
if (nl != level) { level = nl; speed = 800 - (level - 1) * 40; if (speed < 250) speed = 250; }
if (nl != level) { level = nl; speed = 1000 - (level - 1) * 40; if (speed < 300) speed = 300; }
}
spawn();
}
@@ -250,6 +257,10 @@ static void render() {
XSetForeground(dpy, gc, C_DIM);
XDrawRectangle(dpy, back, gc, px0 - 1, py0 - 1, PCOLS * CELL + 2, PROWS * CELL + 2);
// frame the whole window (right/bottom edges too)
XSetForeground(dpy, gc, C_DIM);
XDrawRectangle(dpy, back, gc, 0, 0, winW - 1, winH - 1);
// settled blocks
for (int x = 0; x < PCOLS; x++)
for (int y = 0; y < PROWS; y++)
@@ -298,13 +309,17 @@ static void render() {
snprintf(buf, sizeof(buf), "LEVEL %d", level); draw_text(sx, ty + 18, 1, C_DIM, buf);
if (best > 0) { snprintf(buf, sizeof(buf), "BEST %d", best); draw_text(sx, ty + 27, 1, C_DIM, buf); }
if (state == PAUSED || state == GAMEOVER) {
XSetForeground(dpy, gc, C_BG);
XFillRectangle(dpy, back, gc, 0, 0, winW, winH);
}
if (state == PAUSED) {
draw_text(winW / 2 - 3 * 6 * 2, winH / 2 - 7, 2, C_FG, "PAUSE");
draw_text(winW / 2 - 5 * 6, winH / 2 + 10, 1, C_DIM, "5 RESUME");
draw_text(winW / 2 - 5 * 6, winH / 2 - 7, 2, C_FG, "PAUSE");
draw_text(winW / 2 - 4 * 6, winH / 2 + 10, 1, C_DIM, "5 RESUME");
} else if (state == GAMEOVER) {
draw_text(winW / 2 - 5 * 6 * 2, winH / 2 - 14, 2, C_FG, "GAME OVER");
draw_text(winW / 2 - 9 * 6, winH / 2 - 14, 2, C_FG, "GAME OVER");
snprintf(buf, sizeof(buf), "SCORE %d", score); draw_text(winW / 2 - 5 * 6, winH / 2 + 4, 1, C_DIM, buf);
draw_text(winW / 2 - 9 * 6, winH / 2 + 13, 1, C_DIM, "5 NEW GAME");
draw_text(winW / 2 - 5 * 6, winH / 2 + 13, 1, C_DIM, "5 NEW GAME");
}
XCopyArea(dpy, back, win, gc, 0, 0, winW, winH, 0, 0);
@@ -441,6 +456,7 @@ int main() {
}
if (running && now_ms() >= nextTick) {
if (state == PLAYING) step();
if (state == PLAYING) nextTick = now_ms() + speed;
else nextTick = now_ms() + 80;
render();
}