7
#define SDL_MAIN_USE_CALLBACKS 1
9
#include <SDL3/SDL_main.h>
14
#define STEP_RATE_IN_MILLISECONDS 125
15
#define SNAKE_BLOCK_SIZE_IN_PIXELS 24
16
#define SDL_WINDOW_WIDTH (SNAKE_BLOCK_SIZE_IN_PIXELS * SNAKE_GAME_WIDTH)
17
#define SDL_WINDOW_HEIGHT (SNAKE_BLOCK_SIZE_IN_PIXELS * SNAKE_GAME_HEIGHT)
22
SDL_Renderer *renderer;
23
SDL_TimerID step_timer;
24
SnakeContext snake_ctx;
27
static Uint32 sdl_timer_callback_(void *payload, SDL_TimerID timer_id, Uint32 interval)
33
ue.type = SDL_EVENT_USER;
37
e.type = SDL_EVENT_USER;
43
static int handle_key_event_(SnakeContext *ctx, SDL_Scancode key_code)
47
case SDL_SCANCODE_ESCAPE:
49
return SDL_APP_SUCCESS;
52
snake_initialize(ctx, SDL_rand);
55
case SDL_SCANCODE_RIGHT:
56
snake_redir(ctx, SNAKE_DIR_RIGHT);
59
snake_redir(ctx, SNAKE_DIR_UP);
61
case SDL_SCANCODE_LEFT:
62
snake_redir(ctx, SNAKE_DIR_LEFT);
64
case SDL_SCANCODE_DOWN:
65
snake_redir(ctx, SNAKE_DIR_DOWN);
70
return SDL_APP_CONTINUE;
73
static void set_rect_xy_(SDL_FRect *r, short x, short y)
75
r->x = (float)(x * SNAKE_BLOCK_SIZE_IN_PIXELS);
76
r->y = (float)(y * SNAKE_BLOCK_SIZE_IN_PIXELS);
79
SDL_AppResult SDL_AppIterate(void *appstate)
87
as = (AppState *)appstate;
89
r.w = r.h = SNAKE_BLOCK_SIZE_IN_PIXELS;
90
SDL_SetRenderDrawColor(as->renderer, 0, 0, 0, 255);
91
SDL_RenderClear(as->renderer);
92
for (i = 0; i < SNAKE_GAME_WIDTH; i++) {
93
for (j = 0; j < SNAKE_GAME_HEIGHT; j++) {
94
ct = snake_cell_at(ctx, i, j);
95
if (ct == SNAKE_CELL_NOTHING)
97
set_rect_xy_(&r, i, j);
98
if (ct == SNAKE_CELL_FOOD)
99
SDL_SetRenderDrawColor(as->renderer, 0, 0, 128, 255);
101
SDL_SetRenderDrawColor(as->renderer, 0, 128, 0, 255);
102
SDL_RenderFillRect(as->renderer, &r);
105
SDL_SetRenderDrawColor(as->renderer, 255, 255, 0, 255);
106
set_rect_xy_(&r, ctx->head_xpos, ctx->head_ypos);
107
SDL_RenderFillRect(as->renderer, &r);
108
SDL_RenderPresent(as->renderer);
109
return SDL_APP_CONTINUE;
112
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
116
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
117
return SDL_APP_FAILURE;
119
SDL_SetHint("SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR", "0");
120
AppState *as = malloc(sizeof(AppState));
123
if (SDL_CreateWindowAndRenderer("examples/game/snake", SDL_WINDOW_WIDTH, SDL_WINDOW_HEIGHT, 0, &as->window, &as->renderer) == -1) {
124
return SDL_APP_FAILURE;
126
snake_initialize(&as->snake_ctx, SDL_rand);
127
as->step_timer = SDL_AddTimer(
128
STEP_RATE_IN_MILLISECONDS,
131
if (as->step_timer == 0) {
132
return SDL_APP_FAILURE;
134
return SDL_APP_CONTINUE;
137
SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
139
SnakeContext *ctx = &((AppState *)appstate)->snake_ctx;
140
switch (event->type) {
142
return SDL_APP_SUCCESS;
144
snake_step(ctx, SDL_rand);
146
case SDL_EVENT_KEY_DOWN:
147
return handle_key_event_(ctx, event->key.scancode);
149
return SDL_APP_CONTINUE;
152
void SDL_AppQuit(void *appstate)
154
if (appstate != NULL) {
155
AppState *as = (AppState *)appstate;
156
SDL_RemoveTimer(as->step_timer);
157
SDL_DestroyRenderer(as->renderer);
158
SDL_DestroyWindow(as->window);