sdl.cpp (7976B)
1 #include <SDL2/SDL.h> 2 3 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) 4 #define ARRAY_SSIZE(a) ((ssize_t)ARRAY_SIZE(a)) 5 6 extern "C" char const* __asan_default_options() { return "detect_leaks=0"; } 7 8 int screen_width = 800; 9 int screen_height = 450; 10 11 SDL_Renderer* renderer; 12 SDL_Window* window; 13 14 void initSDL(void) 15 { 16 int rendererFlags, windowFlags; 17 18 rendererFlags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC; 19 20 windowFlags = 0; 21 22 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < 0) 23 { 24 printf("Couldn't initialize SDL: %s\n", SDL_GetError()); 25 exit(1); 26 } 27 28 window = SDL_CreateWindow("Pong", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_width, screen_height, windowFlags); 29 30 if (!window) 31 { 32 printf("Failed to open %d x %d window: %s\n", screen_width, screen_height, SDL_GetError()); 33 exit(1); 34 } 35 36 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); 37 38 renderer = SDL_CreateRenderer(window, -1, rendererFlags); 39 40 if (!renderer) 41 { 42 printf("Failed to create renderer: %s\n", SDL_GetError()); 43 exit(1); 44 } 45 } 46 47 static struct rgb 48 { 49 unsigned char r,g,b; 50 } player_colours[] = { 51 {255,0,0}, 52 {0,255,0}, 53 {32,32,255}, 54 {192,192,0}, 55 {192,0,192}, 56 {0,192,255}, 57 }; 58 59 struct coord 60 { 61 int x, y; 62 coord operator -() const { return {-x, -y}; } 63 coord operator +(coord rhs) const { return {x+rhs.x, y+rhs.y}; } 64 coord operator -(coord rhs) const { return {x-rhs.x, y-rhs.y}; } 65 coord operator *(int rhs) const { return {x*rhs, y*rhs}; } 66 coord operator /(int rhs) const { return {x/rhs, y/rhs}; } 67 coord& operator +=(coord rhs) { return *this = *this + rhs; } 68 coord& operator -=(coord rhs) { return *this = *this - rhs; } 69 explicit operator bool() const { return x or y; } 70 }; 71 72 static struct player 73 { 74 SDL_GameController* controller; 75 struct coord pos, vel; 76 unsigned cooldown; 77 int shooting; 78 unsigned health; 79 } players[ARRAY_SIZE(player_colours)]; 80 81 struct bullet 82 { 83 struct player* player; 84 struct coord pos, vel, control; 85 unsigned ttl; 86 }; 87 88 struct bullet bullets[128]; 89 90 int clamp(int v, int l, int h) 91 { 92 if (v < l) 93 v = l; 94 else if (v > h) 95 v = h; 96 return v; 97 } 98 99 void shoot(struct player* p) 100 { 101 p->cooldown = 30; 102 for (unsigned i = 0; i < ARRAY_SIZE(bullets); ++i) 103 { 104 struct bullet* b = bullets + i; 105 if (b->player) 106 continue; 107 b->player = p; 108 b->ttl = 4*60; 109 b->pos = p->pos; 110 b->vel = p->vel*2; 111 return; 112 } 113 } 114 115 int abs(int v) 116 { 117 return v < 0 ? -v : v; 118 } 119 120 int colliding(struct coord a, struct coord b, int r) 121 { 122 a -= b; 123 a.x = abs(a.x) < r; 124 a.y = abs(a.y) < r; 125 return a.x && a.y; 126 } 127 128 void simulate(void) 129 { 130 for (unsigned i = 0; i < ARRAY_SIZE(bullets); ++i) 131 { 132 struct bullet* b = bullets + i; 133 if (!b->player) 134 continue; 135 struct player* p = NULL; 136 for (unsigned i = 0; i < ARRAY_SIZE(player_colours); ++i) 137 { 138 if (players + i == b->player) 139 continue; 140 if (!players[i].controller) 141 continue; 142 if (!colliding(players[i].pos, b->pos, (2 + 5 + players[i].health) << 13)) 143 continue; 144 p = players + i; 145 break; 146 } 147 if (!p) 148 continue; 149 p->health -= !!p->health; 150 p->pos += b->vel * 10; 151 b->player = NULL; 152 } 153 154 for (unsigned i = 0; i < ARRAY_SIZE(player_colours); ++i) 155 { 156 struct player* const p = players + i; 157 if (!p->controller) 158 continue; 159 p->pos += p->vel; 160 p->pos.x = clamp(p->pos.x, -(screen_width << 12), screen_width << 12); 161 p->pos.y = clamp(p->pos.y, -(screen_height << 12), screen_height << 12); 162 if (!p->cooldown) 163 { 164 if (p->shooting) 165 shoot(p); 166 } 167 else 168 --p->cooldown; 169 } 170 for (unsigned i = 0; i < ARRAY_SIZE(bullets); ++i) 171 { 172 struct bullet* b = bullets + i; 173 if (!b->player) 174 continue; 175 b->pos += b->vel; 176 if (b->ttl--) 177 continue; 178 b->player = NULL; 179 } 180 } 181 182 void prepareScene(void) 183 { 184 SDL_SetRenderDrawColor(renderer, 32, 32, 32, 255); 185 SDL_RenderClear(renderer); 186 187 for (unsigned i = 0; i < ARRAY_SIZE(bullets); ++i) 188 { 189 struct bullet const* b = bullets + i; 190 if (!b->player) 191 continue; 192 struct rgb c = player_colours[b->player - players]; 193 coord pos{screen_width / 2 + (b->pos.x >> 13), screen_height / 2 + (b->pos.y >> 13)}; 194 SDL_Rect rect{pos.x - 3, pos.y - 3, 6, 6}; 195 SDL_SetRenderDrawColor(renderer, c.r, c.g, c.b, 255); 196 SDL_RenderDrawRect(renderer, &rect); 197 if (auto vel = b->vel / 512) 198 SDL_RenderDrawLine(renderer, pos.x, pos.y, pos.x + vel.x, pos.y + vel.y); 199 } 200 201 for (unsigned i = 0; i < ARRAY_SIZE(player_colours); ++i) 202 { 203 struct player const* const p = players + i; 204 struct rgb const c = player_colours[i]; 205 if (!p->controller) 206 continue; 207 SDL_SetRenderDrawColor(renderer, c.r, c.g, c.b, 255); 208 int size = 5 + p->health; 209 coord pos{screen_width / 2 + (p->pos.x >> 13), screen_height / 2 + (p->pos.y >> 13)}; 210 SDL_Rect rect{pos.x - size, pos.y - size, 2*size, 2*size}; 211 SDL_RenderDrawRect(renderer, &rect); 212 if (auto vel = p->vel / 512) 213 SDL_RenderDrawLine(renderer, pos.x, pos.y, pos.x + vel.x, pos.y + vel.y); 214 } 215 } 216 217 void presentScene(void) 218 { 219 SDL_RenderPresent(renderer); 220 } 221 222 char run = 1; 223 224 void key(SDL_KeyboardEvent* e) 225 { 226 switch (e->keysym.sym) 227 { 228 case SDLK_ESCAPE: 229 run = 0; 230 return; 231 } 232 } 233 234 void con_add(SDL_ControllerDeviceEvent* e) 235 { 236 char const* name = SDL_GameControllerNameForIndex(e->which); 237 unsigned i = 0; 238 for (i = 0; i < ARRAY_SIZE(players); ++i) 239 if (!players[i].controller) 240 goto allocated; 241 printf("Controller %d '%s' has no free slot\n", e->which, name); 242 return; 243 allocated: 244 players[i].controller = SDL_GameControllerOpen(i); 245 SDL_GameControllerSetPlayerIndex(players[i].controller, i); 246 players[i].vel = (struct coord){0, 0}; 247 players[i].pos = (struct coord){(((int)i-3)*100) << 13, 0}; 248 players[i].health = 10; 249 printf("Controller %d %p '%s' added as player %d\n", e->which, players[i].controller, name, i); 250 } 251 252 void con_del(SDL_ControllerDeviceEvent* e) 253 { 254 SDL_GameController* c = SDL_GameControllerFromInstanceID(e->which); 255 if (!c) 256 { 257 printf("Controller %d disconnected\n", e->which); 258 return; 259 } 260 261 for (unsigned i = 0; i < ARRAY_SIZE(players); ++i) 262 if (players[i].controller == c) 263 { 264 players[i].controller = NULL; 265 printf("Controller %d %p disconnected, player %d removed\n", e->which, c, i); 266 break; 267 } 268 269 SDL_GameControllerClose(c); 270 } 271 272 void button(SDL_ControllerButtonEvent* e) 273 { 274 SDL_GameController* c = SDL_GameControllerFromInstanceID(e->which); 275 int pid = SDL_GameControllerGetPlayerIndex(c); 276 if (pid < 0 || pid >= ARRAY_SSIZE(players)) 277 return; 278 279 switch (e->button) 280 { 281 case SDL_CONTROLLER_BUTTON_A: 282 players[pid].shooting = e->state; 283 return; 284 } 285 286 if (e->state) 287 printf("D[%d] P[%d] B[%u] %u\n", e->which, pid, e->button, e->state); 288 289 } 290 291 void axis(SDL_ControllerAxisEvent* e) 292 { 293 SDL_GameController* c = SDL_GameControllerFromInstanceID(e->which); 294 int pid = SDL_GameControllerGetPlayerIndex(c); 295 if (pid < 0 || pid >= ARRAY_SSIZE(players)) 296 return; 297 struct player* p = players + pid; 298 if (!p->controller) 299 return; 300 switch (e->axis) 301 { 302 case SDL_CONTROLLER_AXIS_LEFTX: 303 p->vel.x = e->value >> 1; 304 return; 305 case SDL_CONTROLLER_AXIS_LEFTY: 306 p->vel.y = e->value >> 1; 307 return; 308 default: 309 printf("D[%d] P[%d] A[%u] %d\n", e->which, pid, e->axis, e->value); 310 } 311 } 312 313 void window_event(SDL_WindowEvent const* e) 314 { 315 switch (e->event) 316 { 317 case SDL_WINDOWEVENT_SIZE_CHANGED: 318 screen_width = e->data1; 319 screen_height = e->data2; 320 return; 321 } 322 } 323 324 void doInput() 325 { 326 SDL_Event event; 327 while (SDL_PollEvent(&event)) 328 { 329 switch (event.type) 330 { 331 case SDL_QUIT: 332 run = 0; 333 break; 334 case SDL_KEYDOWN: 335 key(&event.key); 336 break; 337 case SDL_CONTROLLERDEVICEADDED: 338 con_add(&event.cdevice); 339 break; 340 case SDL_CONTROLLERDEVICEREMOVED: 341 con_del(&event.cdevice); 342 break; 343 case SDL_CONTROLLERBUTTONDOWN: 344 case SDL_CONTROLLERBUTTONUP: 345 button(&event.cbutton); 346 break; 347 348 case SDL_CONTROLLERAXISMOTION: 349 axis(&event.caxis); 350 break; 351 352 case SDL_WINDOWEVENT: 353 window_event(&event.window); 354 break; 355 356 default: 357 break; 358 } 359 } 360 } 361 362 int main() 363 { 364 initSDL(); 365 while (run) 366 { 367 doInput(); 368 simulate(); 369 prepareScene(); 370 presentScene(); 371 //SDL_Delay(16); 372 } 373 SDL_Quit(); 374 }