games: progressive difficulty + Tetris controls panel
Snake: speed derived from pixels/second; +1 px/sec per 5 food eaten (pps = 70 + food/5, step = cell*1000/pps, floored at 40ms). Tetris: speed derived from pixels/second; +1 px/sec per 10 lines cleared (pps = 23 + lines/10, step = CELL*1000/pps, floored at 40ms), replacing the old level-driven formula. Level still drives the score multiplier. Tetris: list all controls concisely in the free space of the right panel (KEYS, 4/6 MOVE, 2 ROTATE, 8 SOFT, 0 DROP, # PAUSE, 5 OK).
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+15
-5
@@ -101,7 +101,8 @@ static int ndirx = 1, ndiry = 0; // buffered next direction
|
|||||||
static int foodx, foody;
|
static int foodx, foody;
|
||||||
static int score = 0;
|
static int score = 0;
|
||||||
static int best = 0;
|
static int best = 0;
|
||||||
static int speed = 130; // ms per step (speeds up with score)
|
static int speed = 130; // ms per step (derived from pps below)
|
||||||
|
static int pps = 70; // base speed px/sec; +1 px/sec per 5 food eaten
|
||||||
static unsigned long nextTick = 0;
|
static unsigned long nextTick = 0;
|
||||||
static bool running = true;
|
static bool running = true;
|
||||||
static unsigned long now_ms() {
|
static unsigned long now_ms() {
|
||||||
@@ -110,6 +111,14 @@ static unsigned long now_ms() {
|
|||||||
return (unsigned long)(tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
return (unsigned long)(tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Derive the per-step delay (ms) from the target pixels/second. The snake
|
||||||
|
// advances one cell (cell pixels) per step, so step time = cell / pps.
|
||||||
|
static void update_speed() {
|
||||||
|
int ms = (cell * 1000) / pps;
|
||||||
|
if (ms < 40) ms = 40; // cap so the snake never becomes uncontrollable
|
||||||
|
speed = ms;
|
||||||
|
}
|
||||||
|
|
||||||
static void compute_grid() {
|
static void compute_grid() {
|
||||||
int m = 2;
|
int m = 2;
|
||||||
int topH = 14; // reserved status strip for SCORE/BEST
|
int topH = 14; // reserved status strip for SCORE/BEST
|
||||||
@@ -151,7 +160,8 @@ static void reset_game() {
|
|||||||
dirx = 1; diry = 0;
|
dirx = 1; diry = 0;
|
||||||
ndirx = 1; ndiry = 0;
|
ndirx = 1; ndiry = 0;
|
||||||
score = 0;
|
score = 0;
|
||||||
speed = 130;
|
pps = 70;
|
||||||
|
update_speed();
|
||||||
place_food();
|
place_food();
|
||||||
state = PLAYING;
|
state = PLAYING;
|
||||||
nextTick = now_ms() + speed;
|
nextTick = now_ms() + speed;
|
||||||
@@ -184,9 +194,9 @@ static void step() {
|
|||||||
if (ate) {
|
if (ate) {
|
||||||
score += 10;
|
score += 10;
|
||||||
if (score > best) best = score;
|
if (score > best) best = score;
|
||||||
int ns = 130 - (score / 50) * 8;
|
int food = score / 10; // food items eaten so far
|
||||||
if (ns < 60) ns = 60;
|
pps = 70 + food / 5; // +1 px/sec per 5 food eaten (progressive difficulty)
|
||||||
speed = ns;
|
update_speed();
|
||||||
place_food();
|
place_food();
|
||||||
}
|
}
|
||||||
nextTick = now_ms() + speed;
|
nextTick = now_ms() + speed;
|
||||||
|
|||||||
+25
-5
@@ -109,7 +109,8 @@ static int board[PCOLS][PROWS]; // 0 empty, else type+1
|
|||||||
static int curType = 0, curRot = 0, curX = 3, curY = 0;
|
static int curType = 0, curRot = 0, curX = 3, curY = 0;
|
||||||
static int nextType = 0;
|
static int nextType = 0;
|
||||||
static int score = 0, best = 0, lines = 0, level = 1;
|
static int score = 0, best = 0, lines = 0, level = 1;
|
||||||
static int speed = 1000; // ms per gravity step
|
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 unsigned long nextTick = 0;
|
||||||
static bool running = true;
|
static bool running = true;
|
||||||
|
|
||||||
@@ -137,6 +138,15 @@ static unsigned long now_ms() {
|
|||||||
return (unsigned long)(tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
return (unsigned long)(tv.tv_sec * 1000 + tv.tv_usec / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Derive the gravity delay (ms) from the target pixels/second. A piece drops
|
||||||
|
// one cell (CELL pixels) per gravity step, so step time = CELL / pps.
|
||||||
|
static void update_speed() {
|
||||||
|
pps = 23 + lines / 10; // +1 px/sec per 10 cleared lines (progressive difficulty)
|
||||||
|
int ms = (CELL * 1000) / pps;
|
||||||
|
if (ms < 40) ms = 40; // floor on gravity so it stays playable
|
||||||
|
speed = ms;
|
||||||
|
}
|
||||||
|
|
||||||
static void spawn() {
|
static void spawn() {
|
||||||
curType = nextType;
|
curType = nextType;
|
||||||
nextType = rand() % 7;
|
nextType = rand() % 7;
|
||||||
@@ -176,11 +186,11 @@ static void lock_piece() {
|
|||||||
}
|
}
|
||||||
if (cleared > 0) {
|
if (cleared > 0) {
|
||||||
lines += cleared;
|
lines += cleared;
|
||||||
|
level = 1 + lines / 10;
|
||||||
int pts[5] = {0, 100, 300, 500, 800};
|
int pts[5] = {0, 100, 300, 500, 800};
|
||||||
score += pts[cleared] * level;
|
score += pts[cleared] * level;
|
||||||
if (score > best) best = score;
|
if (score > best) best = score;
|
||||||
int nl = 1 + lines / 10;
|
update_speed(); // +1 px/sec per 10 cleared lines
|
||||||
if (nl != level) { level = nl; speed = 1000 - (level - 1) * 40; if (speed < 300) speed = 300; }
|
|
||||||
}
|
}
|
||||||
spawn();
|
spawn();
|
||||||
}
|
}
|
||||||
@@ -227,7 +237,7 @@ static void try_rotate() {
|
|||||||
|
|
||||||
static void reset_game() {
|
static void reset_game() {
|
||||||
for (int x = 0; x < PCOLS; x++) for (int y = 0; y < PROWS; y++) board[x][y] = 0;
|
for (int x = 0; x < PCOLS; x++) for (int y = 0; y < PROWS; y++) board[x][y] = 0;
|
||||||
score = 0; lines = 0; level = 1; speed = 600;
|
score = 0; lines = 0; level = 1; update_speed();
|
||||||
nextType = rand() % 7;
|
nextType = rand() % 7;
|
||||||
spawn();
|
spawn();
|
||||||
state = PLAYING;
|
state = PLAYING;
|
||||||
@@ -319,6 +329,16 @@ static void render() {
|
|||||||
snprintf(buf, sizeof(buf), "LEVEL %d", level); draw_text(sx, ty + 18, 1, C_DIM, buf);
|
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 (best > 0) { snprintf(buf, sizeof(buf), "BEST %d", best); draw_text(sx, ty + 27, 1, C_DIM, buf); }
|
||||||
|
|
||||||
|
// concise controls in the free space below the stats
|
||||||
|
int ky = ty + 27 + 12;
|
||||||
|
draw_text(sx, ky, 1, C_DIM, "KEYS");
|
||||||
|
draw_text(sx, ky + 9, 1, C_DIM, "4/6 MOVE");
|
||||||
|
draw_text(sx, ky + 18, 1, C_DIM, "2 ROTATE");
|
||||||
|
draw_text(sx, ky + 27, 1, C_DIM, "8 SOFT");
|
||||||
|
draw_text(sx, ky + 36, 1, C_DIM, "0 DROP");
|
||||||
|
draw_text(sx, ky + 45, 1, C_DIM, "# PAUSE");
|
||||||
|
draw_text(sx, ky + 54, 1, C_DIM, "5 OK");
|
||||||
|
|
||||||
if (state == PAUSED || state == GAMEOVER) {
|
if (state == PAUSED || state == GAMEOVER) {
|
||||||
XSetForeground(dpy, gc, C_BG);
|
XSetForeground(dpy, gc, C_BG);
|
||||||
XFillRectangle(dpy, back, gc, 0, 0, winW, winH);
|
XFillRectangle(dpy, back, gc, 0, 0, winW, winH);
|
||||||
@@ -352,7 +372,7 @@ static void setup_window() {
|
|||||||
if (winW < 96) winW = 96;
|
if (winW < 96) winW = 96;
|
||||||
if (winH < 96) winH = 96;
|
if (winH < 96) winH = 96;
|
||||||
win = XCreateWindow(dpy, RootWindow(dpy, screen), bw, TOPBAR + bw, winW, winH, 0,
|
win = XCreateWindow(dpy, RootWindow(dpy, screen), bw, TOPBAR + bw, winW, winH, 0,
|
||||||
CopyFromParent, InputOutput, CopyFromParent, 0, nullptr);
|
CopyFromParent, InputOutput, CopyFromParent, 0, nullptr);
|
||||||
XStoreName(dpy, win, "Tetris");
|
XStoreName(dpy, win, "Tetris");
|
||||||
XClassHint* ch = XAllocClassHint();
|
XClassHint* ch = XAllocClassHint();
|
||||||
if (ch) { ch->res_name = (char*)"tetris"; ch->res_class = (char*)"tetris"; XSetClassHint(dpy, win, ch); XFree(ch); }
|
if (ch) { ch->res_name = (char*)"tetris"; ch->res_class = (char*)"tetris"; XSetClassHint(dpy, win, ch); XFree(ch); }
|
||||||
|
|||||||
Reference in New Issue
Block a user