Compare commits
3
Commits
e72588f792
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5be3992a6 | ||
|
|
904b8c3a29 | ||
|
|
78ae90391a |
@@ -8,15 +8,17 @@ SRC := src/engine/engine.c \
|
|||||||
OUT := build/main
|
OUT := build/main
|
||||||
SNAKE_SRC := src/examples/snake.c $(SRC)
|
SNAKE_SRC := src/examples/snake.c $(SRC)
|
||||||
SNAKE := build/snake
|
SNAKE := build/snake
|
||||||
|
2048_SRC := src/examples/2048.c $(SRC)
|
||||||
|
2048 := build/2048
|
||||||
|
|
||||||
build:
|
build:
|
||||||
$(CC) -o $(OUT) src/main.c $(SRC) $(INC) $(LIBS)
|
$(CC) -o $(OUT) -O3 -DNDEBUG src/main.c $(SRC) $(INC) $(LIBS)
|
||||||
|
|
||||||
run:
|
run:
|
||||||
$(OUT)
|
$(OUT)
|
||||||
|
|
||||||
build-snake:
|
build-snake:
|
||||||
$(CC) -o $(SNAKE) $(SNAKE_SRC) $(INC) $(LIBS)
|
$(CC) -o $(SNAKE) -O3 -DNDEBUG $(SNAKE_SRC) $(INC) $(LIBS)
|
||||||
|
|
||||||
run-snake:
|
run-snake:
|
||||||
$(SNAKE)
|
$(SNAKE)
|
||||||
@@ -24,6 +26,15 @@ run-snake:
|
|||||||
clean-snake:
|
clean-snake:
|
||||||
rm $(SNAKE)
|
rm $(SNAKE)
|
||||||
|
|
||||||
|
build-2048:
|
||||||
|
$(CC) -o $(2048) -O3 -DNDEBUG $(2048_SRC) $(INC) $(LIBS)
|
||||||
|
|
||||||
|
run-2048:
|
||||||
|
$(2048)
|
||||||
|
|
||||||
|
clean-2048:
|
||||||
|
rm $(2048)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm $(OUT)
|
rm $(OUT)
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ typedef struct {
|
|||||||
uint32_t framebuffer[WINDOW_WIDTH * WINDOW_HEIGHT];
|
uint32_t framebuffer[WINDOW_WIDTH * WINDOW_HEIGHT];
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
bool is_running;
|
bool is_running;
|
||||||
|
bool framebuffer_dirty;
|
||||||
|
SDL_Rect dirty_rect;
|
||||||
uint16_t width, height;
|
uint16_t width, height;
|
||||||
} game_state_t;
|
} game_state_t;
|
||||||
|
|
||||||
@@ -88,6 +90,12 @@ clear_framebuffer(
|
|||||||
uint32_t color
|
uint32_t color
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void
|
||||||
|
clear_rect(int x, int y, int w, int h, uint32_t color);
|
||||||
|
|
||||||
|
void
|
||||||
|
mark_dirty_rect(int x, int y, int w, int h);
|
||||||
|
|
||||||
void
|
void
|
||||||
put_char(
|
put_char(
|
||||||
char c,
|
char c,
|
||||||
|
|||||||
+135
-18
@@ -3,12 +3,144 @@
|
|||||||
engine_internal_state_t *internal_state = NULL;
|
engine_internal_state_t *internal_state = NULL;
|
||||||
game_state_t *game_state = NULL;
|
game_state_t *game_state = NULL;
|
||||||
|
|
||||||
|
void
|
||||||
|
mark_dirty_rect(int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
if (w <= 0 || h <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clip rectangle to the framebuffer
|
||||||
|
if (x < 0) {
|
||||||
|
w += x;
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y < 0) {
|
||||||
|
h += y;
|
||||||
|
y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x + w > game_state->width) {
|
||||||
|
w = game_state->width - x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y + h > game_state->height) {
|
||||||
|
h = game_state->height - y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (w <= 0 || h <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Rect rect = {
|
||||||
|
.x = x,
|
||||||
|
.y = y,
|
||||||
|
.w = w,
|
||||||
|
.h = h
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!game_state->framebuffer_dirty) {
|
||||||
|
game_state->dirty_rect = rect;
|
||||||
|
game_state->framebuffer_dirty = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int left = game_state->dirty_rect.x < rect.x
|
||||||
|
? game_state->dirty_rect.x
|
||||||
|
: rect.x;
|
||||||
|
|
||||||
|
int top = game_state->dirty_rect.y < rect.y
|
||||||
|
? game_state->dirty_rect.y
|
||||||
|
: rect.y;
|
||||||
|
|
||||||
|
int old_right =
|
||||||
|
game_state->dirty_rect.x + game_state->dirty_rect.w;
|
||||||
|
|
||||||
|
int new_right = rect.x + rect.w;
|
||||||
|
|
||||||
|
int old_bottom =
|
||||||
|
game_state->dirty_rect.y + game_state->dirty_rect.h;
|
||||||
|
|
||||||
|
int new_bottom = rect.y + rect.h;
|
||||||
|
|
||||||
|
int right = old_right > new_right
|
||||||
|
? old_right
|
||||||
|
: new_right;
|
||||||
|
|
||||||
|
int bottom = old_bottom > new_bottom
|
||||||
|
? old_bottom
|
||||||
|
: new_bottom;
|
||||||
|
|
||||||
|
game_state->dirty_rect = (SDL_Rect) {
|
||||||
|
.x = left,
|
||||||
|
.y = top,
|
||||||
|
.w = right - left,
|
||||||
|
.h = bottom - top
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
upload_dirty_texture(void)
|
||||||
|
{
|
||||||
|
if (!game_state->framebuffer_dirty) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Texture *texture =
|
||||||
|
internal_state->sdl_state->texture;
|
||||||
|
|
||||||
|
SDL_Rect rect = game_state->dirty_rect;
|
||||||
|
|
||||||
|
void *locked_pixels = NULL;
|
||||||
|
int locked_pitch = 0;
|
||||||
|
|
||||||
|
if (!SDL_LockTexture(
|
||||||
|
texture,
|
||||||
|
&rect,
|
||||||
|
&locked_pixels,
|
||||||
|
&locked_pitch
|
||||||
|
)) {
|
||||||
|
SDL_Log(
|
||||||
|
"SDL_LockTexture failed: %s",
|
||||||
|
SDL_GetError()
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t source_pitch =
|
||||||
|
(size_t)game_state->width * sizeof(uint32_t);
|
||||||
|
|
||||||
|
const size_t row_bytes =
|
||||||
|
(size_t)rect.w * sizeof(uint32_t);
|
||||||
|
|
||||||
|
const uint8_t *source =
|
||||||
|
(const uint8_t *)game_state->framebuffer +
|
||||||
|
(size_t)rect.y * source_pitch +
|
||||||
|
(size_t)rect.x * sizeof(uint32_t);
|
||||||
|
|
||||||
|
uint8_t *destination =
|
||||||
|
(uint8_t *)locked_pixels;
|
||||||
|
|
||||||
|
for (int y = 0; y < rect.h; ++y) {
|
||||||
|
memcpy(
|
||||||
|
destination + (size_t)y * locked_pitch,
|
||||||
|
source + (size_t)y * source_pitch,
|
||||||
|
row_bytes
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_UnlockTexture(texture);
|
||||||
|
|
||||||
|
game_state->framebuffer_dirty = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
engine_start() {
|
engine_start() {
|
||||||
// main game loop
|
// main game loop
|
||||||
while(game_state->is_running) {
|
while(game_state->is_running) {
|
||||||
uint64_t start = SDL_GetPerformanceCounter();
|
|
||||||
|
|
||||||
// poll events
|
// poll events
|
||||||
while (SDL_PollEvent(&game_state->event)) {
|
while (SDL_PollEvent(&game_state->event)) {
|
||||||
internal_state->engine_poll_events();
|
internal_state->engine_poll_events();
|
||||||
@@ -18,11 +150,7 @@ engine_start() {
|
|||||||
internal_state->engine_update_framebuffer();
|
internal_state->engine_update_framebuffer();
|
||||||
|
|
||||||
// update the texture with the modified framebuffer
|
// update the texture with the modified framebuffer
|
||||||
SDL_UpdateTexture(
|
upload_dirty_texture();
|
||||||
internal_state->sdl_state->texture,
|
|
||||||
NULL, game_state->framebuffer,
|
|
||||||
internal_state->sdl_state->width * sizeof(uint32_t)
|
|
||||||
);
|
|
||||||
|
|
||||||
SDL_RenderClear(
|
SDL_RenderClear(
|
||||||
internal_state->sdl_state->renderer
|
internal_state->sdl_state->renderer
|
||||||
@@ -37,17 +165,6 @@ engine_start() {
|
|||||||
SDL_RenderPresent(
|
SDL_RenderPresent(
|
||||||
internal_state->sdl_state->renderer
|
internal_state->sdl_state->renderer
|
||||||
);
|
);
|
||||||
|
|
||||||
uint64_t end = SDL_GetPerformanceCounter();
|
|
||||||
|
|
||||||
double elapsed =
|
|
||||||
(double)(end - start) /
|
|
||||||
(double)SDL_GetPerformanceFrequency();
|
|
||||||
|
|
||||||
// cap the framerate at '1.0/TARGET_FRAME' fps
|
|
||||||
if (elapsed < TARGET_FRAME) {
|
|
||||||
SDL_Delay((TARGET_FRAME - elapsed) * 1000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,11 @@ engine_sdl_init_renderer(
|
|||||||
return RCODE_FAILURE;
|
return RCODE_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// enable VSync
|
||||||
|
if (!SDL_SetRenderVSync(state->renderer, 1)) {
|
||||||
|
eprintf("SDL_SetRenderVSync failed: %s\n", SDL_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
return RCODE_SUCCESS;
|
return RCODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,9 +132,16 @@ engine_init(
|
|||||||
) {
|
) {
|
||||||
internal_state = (engine_internal_state_t *)
|
internal_state = (engine_internal_state_t *)
|
||||||
malloc(sizeof(engine_internal_state_t));
|
malloc(sizeof(engine_internal_state_t));
|
||||||
|
if (internal_state == NULL) {
|
||||||
|
return RCODE_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
game_state = (game_state_t *)
|
game_state = (game_state_t *)
|
||||||
malloc(sizeof(game_state_t));
|
malloc(sizeof(game_state_t));
|
||||||
|
if (game_state == NULL) {
|
||||||
|
free(internal_state);
|
||||||
|
return RCODE_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
internal_state->engine_poll_events
|
internal_state->engine_poll_events
|
||||||
= engine_poll_events;
|
= engine_poll_events;
|
||||||
@@ -138,11 +150,22 @@ engine_init(
|
|||||||
= engine_update_framebuffer;
|
= engine_update_framebuffer;
|
||||||
|
|
||||||
internal_state->sdl_state = engine_sdl_init();
|
internal_state->sdl_state = engine_sdl_init();
|
||||||
|
if (internal_state->sdl_state == NULL) {
|
||||||
|
free(internal_state);
|
||||||
|
free(game_state);
|
||||||
|
return RCODE_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
game_state->is_running = true;
|
game_state->is_running = true;
|
||||||
|
game_state->framebuffer_dirty = true;
|
||||||
|
game_state->dirty_rect = (SDL_Rect) {
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.w = game_state->width,
|
||||||
|
.h = game_state->height
|
||||||
|
};
|
||||||
game_state->width = internal_state->sdl_state->width;
|
game_state->width = internal_state->sdl_state->width;
|
||||||
game_state->height = internal_state->sdl_state->height;
|
game_state->height = internal_state->sdl_state->height;
|
||||||
|
|
||||||
return (game_state == NULL || internal_state == NULL)
|
return RCODE_SUCCESS;
|
||||||
? RCODE_FAILURE : RCODE_SUCCESS;
|
|
||||||
}
|
}
|
||||||
+32
-5
@@ -20,6 +20,8 @@ put_pixel(
|
|||||||
} else {
|
} else {
|
||||||
game_state->framebuffer[game_state->width * y + x]
|
game_state->framebuffer[game_state->width * y + x]
|
||||||
= color;
|
= color;
|
||||||
|
|
||||||
|
mark_dirty_rect(x, y, 1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +42,7 @@ put_rect(
|
|||||||
put_pixel(i, j, color);
|
put_pixel(i, j, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mark_dirty_rect(x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill the entire framebuffer with a given color
|
// fill the entire framebuffer with a given color
|
||||||
@@ -47,11 +50,35 @@ void
|
|||||||
clear_framebuffer(
|
clear_framebuffer(
|
||||||
uint32_t color
|
uint32_t color
|
||||||
) {
|
) {
|
||||||
uint16_t w = game_state->width;
|
for (size_t i = 0;
|
||||||
uint16_t h = game_state->height;
|
i < (size_t)game_state->width * game_state->height;
|
||||||
|
++i) {
|
||||||
|
game_state->framebuffer[i] = color;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < w * h; i++) {
|
mark_dirty_rect(
|
||||||
game_state->framebuffer[i] = color;
|
0,
|
||||||
}
|
0,
|
||||||
|
game_state->width,
|
||||||
|
game_state->height
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clear_rect(int x, int y, int w, int h, uint32_t color)
|
||||||
|
{
|
||||||
|
for (int py = y; py < y + h; ++py) {
|
||||||
|
for (int px = x; px < x + w; ++px) {
|
||||||
|
if (px >= 0 &&
|
||||||
|
px < game_state->width &&
|
||||||
|
py >= 0 &&
|
||||||
|
py < game_state->height) {
|
||||||
|
game_state->framebuffer[
|
||||||
|
py * game_state->width + px
|
||||||
|
] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mark_dirty_rect(x, y, w, h);
|
||||||
|
}
|
||||||
|
|||||||
@@ -112,6 +112,8 @@ put_char(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mark_dirty_rect(x, y, size, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#include "engine.h"
|
||||||
|
|
||||||
|
// polling events every frame
|
||||||
|
void
|
||||||
|
client_poll_event()
|
||||||
|
{
|
||||||
|
SDL_Event ev = game_state->event;
|
||||||
|
|
||||||
|
if (ev.type == SDL_EVENT_QUIT) {
|
||||||
|
game_state->is_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev.type == SDL_EVENT_KEY_DOWN) {
|
||||||
|
switch (ev.key.key) {
|
||||||
|
case SDLK_Q:
|
||||||
|
game_state->is_running = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// performed every frame
|
||||||
|
void
|
||||||
|
client_update_framebuffer()
|
||||||
|
{
|
||||||
|
// single green demo pixel
|
||||||
|
game_state->framebuffer[0] = 0x00FF00;
|
||||||
|
|
||||||
|
put_rect(0, 0, 1100, 200, 0xFFFF00);
|
||||||
|
put_string("Hello, traveller. You have come\nto the right place!",
|
||||||
|
20, 20, 2, 2, 3, 0x000000, 0xFFFF00
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
// initialize the engine
|
||||||
|
if (engine_init(
|
||||||
|
client_poll_event,
|
||||||
|
client_update_framebuffer
|
||||||
|
)) {
|
||||||
|
engine_start();
|
||||||
|
engine_stop();
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
+91
-5
@@ -11,7 +11,7 @@ typedef struct {
|
|||||||
int32_t y;
|
int32_t y;
|
||||||
} v2;
|
} v2;
|
||||||
|
|
||||||
#define SNAKE_MAX_LENGTH 64
|
#define SNAKE_MAX_LENGTH 10
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// position of the head of the snake in the framebuffer
|
// position of the head of the snake in the framebuffer
|
||||||
@@ -32,6 +32,9 @@ typedef struct {
|
|||||||
} snake_state_t;
|
} snake_state_t;
|
||||||
|
|
||||||
snake_state_t snake;
|
snake_state_t snake;
|
||||||
|
bool put_string_game_over;
|
||||||
|
bool put_string_win;
|
||||||
|
bool redraw = false;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
is_opposite_direction(v2 a, v2 b)
|
is_opposite_direction(v2 a, v2 b)
|
||||||
@@ -156,11 +159,17 @@ calculate_snake_death_collisions()
|
|||||||
{
|
{
|
||||||
for (int i = 1; i < snake.length; i++) {
|
for (int i = 1; i < snake.length; i++) {
|
||||||
if (v2_eq(snake.body[0], snake.body[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
|
* performed every frame
|
||||||
* runs on a separate worker thread - you can take advantage
|
* runs on a separate worker thread - you can take advantage
|
||||||
@@ -171,7 +180,7 @@ client_update_framebuffer()
|
|||||||
{
|
{
|
||||||
uint64_t now = SDL_GetTicks();
|
uint64_t now = SDL_GetTicks();
|
||||||
|
|
||||||
if (now >= snake.next_move_time) {
|
if (now >= snake.next_move_time && !put_string_game_over) {
|
||||||
|
|
||||||
// ------- business logic --------
|
// ------- business logic --------
|
||||||
|
|
||||||
@@ -183,8 +192,63 @@ client_update_framebuffer()
|
|||||||
|
|
||||||
calculate_snake_death_collisions();
|
calculate_snake_death_collisions();
|
||||||
|
|
||||||
|
evaluate_win();
|
||||||
|
|
||||||
|
v2 old_head = snake.body[0];
|
||||||
|
v2 old_tail = snake.body[snake.length - 1];
|
||||||
|
|
||||||
advance_snake_pos();
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------
|
// -------------------------------
|
||||||
|
|
||||||
snake.next_move_time += snake.move_interval;
|
snake.next_move_time += snake.move_interval;
|
||||||
@@ -193,8 +257,11 @@ client_update_framebuffer()
|
|||||||
snake.next_move_time = now + snake.move_interval;
|
snake.next_move_time = now + snake.move_interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_framebuffer(0x000000);
|
redraw = true;
|
||||||
|
game_state->framebuffer_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (redraw) {
|
||||||
// draw the apple
|
// draw the apple
|
||||||
if (snake.is_apple_alive) {
|
if (snake.is_apple_alive) {
|
||||||
put_rect_v2(
|
put_rect_v2(
|
||||||
@@ -210,6 +277,7 @@ client_update_framebuffer()
|
|||||||
snake.body[0].x, snake.body[0].y,
|
snake.body[0].x, snake.body[0].y,
|
||||||
snake.size, snake.size, 0x00FF00
|
snake.size, snake.size, 0x00FF00
|
||||||
);
|
);
|
||||||
|
|
||||||
// draw the tail
|
// draw the tail
|
||||||
for (int i = 1; i < snake.length; i++) {
|
for (int i = 1; i < snake.length; i++) {
|
||||||
put_rect(
|
put_rect(
|
||||||
@@ -217,6 +285,21 @@ client_update_framebuffer()
|
|||||||
snake.size, snake.size, 0x00AA00
|
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.dir = (v2){1, 0};
|
||||||
snake.length = 1;
|
snake.length = 1;
|
||||||
snake.size = 20;
|
snake.size = 20;
|
||||||
snake.move_interval = 300;
|
snake.move_interval = 50;
|
||||||
snake.next_move_time = snake.move_interval;
|
snake.next_move_time = snake.move_interval;
|
||||||
snake.is_apple_alive = false;
|
snake.is_apple_alive = false;
|
||||||
snake.pending_dir = snake.dir;
|
snake.pending_dir = snake.dir;
|
||||||
snake.direction_pending = false;
|
snake.direction_pending = false;
|
||||||
|
|
||||||
|
put_string_game_over = false;
|
||||||
|
put_string_win = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|||||||
+1
-5
@@ -21,11 +21,7 @@ client_poll_event()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// performed every frame
|
||||||
* performed every frame
|
|
||||||
* runs on a separate worker thread - you can take advantage
|
|
||||||
* of sleep or usleep from <unistd.h> to create delays
|
|
||||||
*/
|
|
||||||
void
|
void
|
||||||
client_update_framebuffer()
|
client_update_framebuffer()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user