examples

Toy examples in single C files.
git clone git://henryandlizzy.uk/examples
Log | Files | Refs

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 }