add much-needed optimizations and enhance the snake example game

This commit is contained in:
2026-10-05 03:45:46 +02:00
parent e72588f792
commit 78ae90391a
7 changed files with 295 additions and 32 deletions
+91 -5
View File
@@ -11,7 +11,7 @@ typedef struct {
int32_t y;
} v2;
#define SNAKE_MAX_LENGTH 64
#define SNAKE_MAX_LENGTH 10
typedef struct {
// position of the head of the snake in the framebuffer
@@ -32,6 +32,9 @@ typedef struct {
} snake_state_t;
snake_state_t snake;
bool put_string_game_over;
bool put_string_win;
bool redraw = false;
bool
is_opposite_direction(v2 a, v2 b)
@@ -156,11 +159,17 @@ calculate_snake_death_collisions()
{
for (int i = 1; i < snake.length; i++) {
if (v2_eq(snake.body[0], snake.body[i])) {
game_state->is_running = false;
put_string_game_over = true;
}
}
}
void
evaluate_win()
{
put_string_win = (snake.length >= SNAKE_MAX_LENGTH);
}
/**
* performed every frame
* runs on a separate worker thread - you can take advantage
@@ -171,7 +180,7 @@ client_update_framebuffer()
{
uint64_t now = SDL_GetTicks();
if (now >= snake.next_move_time) {
if (now >= snake.next_move_time && !put_string_game_over) {
// ------- business logic --------
@@ -183,7 +192,62 @@ client_update_framebuffer()
calculate_snake_death_collisions();
evaluate_win();
v2 old_head = snake.body[0];
v2 old_tail = snake.body[snake.length - 1];
advance_snake_pos();
v2 new_head = snake.body[0];
clear_rect(
old_tail.x,
old_tail.y,
snake.size,
snake.size,
0x000000
);
if (snake.length > 1) {
put_rect(
old_head.x,
old_head.y,
snake.size,
snake.size,
0x00AA00
);
}
put_rect(
new_head.x,
new_head.y,
snake.size,
snake.size,
0x00FF00
);
mark_dirty_rect(
old_tail.x,
old_tail.y,
snake.size,
snake.size
);
mark_dirty_rect(
old_head.x,
old_head.y,
snake.size,
snake.size
);
mark_dirty_rect(
new_head.x,
new_head.y,
snake.size,
snake.size
);
// -------------------------------
@@ -193,8 +257,11 @@ client_update_framebuffer()
snake.next_move_time = now + snake.move_interval;
}
clear_framebuffer(0x000000);
redraw = true;
game_state->framebuffer_dirty = true;
}
if (redraw) {
// draw the apple
if (snake.is_apple_alive) {
put_rect_v2(
@@ -210,6 +277,7 @@ client_update_framebuffer()
snake.body[0].x, snake.body[0].y,
snake.size, snake.size, 0x00FF00
);
// draw the tail
for (int i = 1; i < snake.length; i++) {
put_rect(
@@ -217,6 +285,21 @@ client_update_framebuffer()
snake.size, snake.size, 0x00AA00
);
}
// draw the splash texts
if (put_string_game_over) {
put_string("GAME OVER!\n<q> to quit",
0, 0, 5, 2, 3, 0xFF0000, 0x000000
);
}
if (put_string_win) {
put_string("YOU WIN!\n<q> to quit",
0, 100, 5, 2, 3, 0x00FF00, 0x000000
);
}
redraw = false;
}
}
@@ -230,11 +313,14 @@ snake_init()
snake.dir = (v2){1, 0};
snake.length = 1;
snake.size = 20;
snake.move_interval = 300;
snake.move_interval = 50;
snake.next_move_time = snake.move_interval;
snake.is_apple_alive = false;
snake.pending_dir = snake.dir;
snake.direction_pending = false;
put_string_game_over = false;
put_string_win = false;
}
int