SDL

Форк
0
161 строка · 4.6 Кб
1
/*
2
 * This example code implements a Snake game that showcases some of the
3
 * functionalities of SDL, such as timer callbacks and event handling.
4
 *
5
 * This code is public domain. Feel free to use it for any purpose!
6
 */
7
#define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */
8
#include <SDL3/SDL.h>
9
#include <SDL3/SDL_main.h>
10
#include <stdlib.h> /* malloc(), free() */
11

12
#include "snake.h"
13

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)
18

19
typedef struct
20
{
21
    SDL_Window *window;
22
    SDL_Renderer *renderer;
23
    SDL_TimerID step_timer;
24
    SnakeContext snake_ctx;
25
} AppState;
26

27
static Uint32 sdl_timer_callback_(void *payload, SDL_TimerID timer_id, Uint32 interval)
28
{
29
    SDL_Event e;
30
    SDL_UserEvent ue;
31
    /* NOTE: snake_step is not called here directly for multithreaded concerns. */
32
    (void)payload;
33
    ue.type = SDL_EVENT_USER;
34
    ue.code = 0;
35
    ue.data1 = NULL;
36
    ue.data2 = NULL;
37
    e.type = SDL_EVENT_USER;
38
    e.user = ue;
39
    SDL_PushEvent(&e);
40
    return interval;
41
}
42

43
static int handle_key_event_(SnakeContext *ctx, SDL_Scancode key_code)
44
{
45
    switch (key_code) {
46
    /* Quit. */
47
    case SDL_SCANCODE_ESCAPE:
48
    case SDL_SCANCODE_Q:
49
        return SDL_APP_SUCCESS;
50
    /* Restart the game as if the program was launched. */
51
    case SDL_SCANCODE_R:
52
        snake_initialize(ctx, SDL_rand);
53
        break;
54
    /* Decide new direction of the snake. */
55
    case SDL_SCANCODE_RIGHT:
56
        snake_redir(ctx, SNAKE_DIR_RIGHT);
57
        break;
58
    case SDL_SCANCODE_UP:
59
        snake_redir(ctx, SNAKE_DIR_UP);
60
        break;
61
    case SDL_SCANCODE_LEFT:
62
        snake_redir(ctx, SNAKE_DIR_LEFT);
63
        break;
64
    case SDL_SCANCODE_DOWN:
65
        snake_redir(ctx, SNAKE_DIR_DOWN);
66
        break;
67
    default:
68
        break;
69
    }
70
    return SDL_APP_CONTINUE;
71
}
72

73
static void set_rect_xy_(SDL_FRect *r, short x, short y)
74
{
75
    r->x = (float)(x * SNAKE_BLOCK_SIZE_IN_PIXELS);
76
    r->y = (float)(y * SNAKE_BLOCK_SIZE_IN_PIXELS);
77
}
78

79
SDL_AppResult SDL_AppIterate(void *appstate)
80
{
81
    AppState *as;
82
    SnakeContext *ctx;
83
    SDL_FRect r;
84
    unsigned i;
85
    unsigned j;
86
    int ct;
87
    as = (AppState *)appstate;
88
    ctx = &as->snake_ctx;
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)
96
                continue;
97
            set_rect_xy_(&r, i, j);
98
            if (ct == SNAKE_CELL_FOOD)
99
                SDL_SetRenderDrawColor(as->renderer, 0, 0, 128, 255);
100
            else /* body */
101
                SDL_SetRenderDrawColor(as->renderer, 0, 128, 0, 255);
102
            SDL_RenderFillRect(as->renderer, &r);
103
        }
104
    }
105
    SDL_SetRenderDrawColor(as->renderer, 255, 255, 0, 255); /*head*/
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;
110
}
111

112
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
113
{
114
    (void)argc;
115
    (void)argv;
116
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) {
117
        return SDL_APP_FAILURE;
118
    }
119
    SDL_SetHint("SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR", "0");
120
    AppState *as = malloc(sizeof(AppState));
121
    *appstate = as;
122
    as->step_timer = 0;
123
    if (SDL_CreateWindowAndRenderer("examples/game/snake", SDL_WINDOW_WIDTH, SDL_WINDOW_HEIGHT, 0, &as->window, &as->renderer) == -1) {
124
        return SDL_APP_FAILURE;
125
    }
126
    snake_initialize(&as->snake_ctx, SDL_rand);
127
    as->step_timer = SDL_AddTimer(
128
        STEP_RATE_IN_MILLISECONDS,
129
        sdl_timer_callback_,
130
        NULL);
131
    if (as->step_timer == 0) {
132
        return SDL_APP_FAILURE;
133
    }
134
    return SDL_APP_CONTINUE;
135
}
136

137
SDL_AppResult SDL_AppEvent(void *appstate, const SDL_Event *event)
138
{
139
    SnakeContext *ctx = &((AppState *)appstate)->snake_ctx;
140
    switch (event->type) {
141
    case SDL_EVENT_QUIT:
142
        return SDL_APP_SUCCESS;
143
    case SDL_EVENT_USER:
144
        snake_step(ctx, SDL_rand);
145
        break;
146
    case SDL_EVENT_KEY_DOWN:
147
        return handle_key_event_(ctx, event->key.scancode);
148
    }
149
    return SDL_APP_CONTINUE;
150
}
151

152
void SDL_AppQuit(void *appstate)
153
{
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);
159
        free(as);
160
    }
161
}
162

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.