xlib_playground

Xlib playground for experiments.
Log | Files | Refs

main.c (8022B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <time.h>
      4 #include <string.h>
      5 
      6 #include <X11/Xlib.h>
      7 
      8 #include "obj.h"
      9 
     10 /* macros */
     11 #define INIT_WIDTH 800
     12 #define INIT_HEIGHT 600
     13 #define FPS 60
     14 #define BLOCK_COUNT 3
     15 
     16 
     17 /* variables */
     18 Display     *display;
     19 Window       window;
     20 unsigned int win_width = INIT_WIDTH, win_height = INIT_HEIGHT;
     21 GC           pgc, fgc, bgc;
     22 Atom         wm_delete_window;
     23 Obj          *square;
     24 Obj          *blocks[BLOCK_COUNT];
     25 int          quit = 0;
     26 enum Keys {
     27 	Key_D,
     28 	Key_S,
     29 	Key_A,
     30 	Key_W,
     31 	Key_Space,
     32 	Num_Key, //number of keys in this enum
     33 };
     34 enum Key_State {
     35 	Key_Up,
     36 	Key_Down,
     37 };
     38 int key_state[Num_Key];
     39 enum Next_Menu {
     40 	Start_Menu,
     41 	Game_Play,
     42 	End_Menu,
     43 	Quit,
     44 };
     45 int next_menu = Start_Menu;
     46 
     47 
     48 /* function prototypes */
     49 void setup(void);
     50 void start_menu(void);
     51 void game_init(void);
     52 void game_play(void);
     53 void draw_object(Obj *, GC);
     54 void handle_collision(void);
     55 void handle_inputs(void);
     56 void end_menu(void);
     57 void next_tick(float);
     58 void cleanup(void);
     59 
     60 
     61 void
     62 setup(void)
     63 {
     64 	if ((display = XOpenDisplay(NULL)) == NULL){
     65 	    fprintf(stderr, "ERROR: could not open display\n");
     66 	    exit(1);
     67 	}
     68 	window = XCreateSimpleWindow(
     69 	                    display,
     70 	                    XDefaultRootWindow(display),
     71 	                    0, 0,
     72 	                    win_width, win_height,
     73 	                    0, 0,
     74 						0);
     75 	XStoreName(display, window, "UNKO");
     76 	pgc = XCreateGC(display, window, 0, NULL);
     77 	fgc = XCreateGC(display, window, 0, NULL);
     78 	bgc = XCreateGC(display, window, 0, NULL);
     79 
     80 	wm_delete_window = XInternAtom(display, 
     81 									"WM_DELETE_WINDOW", False);
     82 	XSetWMProtocols(display, window, &wm_delete_window, 1);
     83 
     84 	XSelectInput(display, window,
     85 				ExposureMask|KeyPressMask|KeyReleaseMask);
     86 	
     87 	XSetForeground(display, pgc, 0x00FF00);
     88 	XSetForeground(display, fgc, 0xFFFFFF);
     89 	XSetForeground(display, bgc, 0x0000FF);
     90 	XMapWindow(display, window);
     91 }
     92 
     93 void
     94 start_menu(void)
     95 {
     96 	XEvent event;
     97 	char *menu_char_q = "press q to quit.";
     98 	char *menu_char_s = "press <space> to start.";
     99 
    100 	XClearArea(display, window, 0, 0, win_width, win_height, False);
    101 
    102 	XDrawString(display, window, fgc,
    103 				win_width/2 - strlen(menu_char_q)/2, win_height/2,
    104 				menu_char_q, strlen(menu_char_q));
    105 	XDrawString(display, window, fgc,
    106 				win_width/2 - strlen(menu_char_s)/2, win_height/2 + 20,
    107 				menu_char_s, strlen(menu_char_s));
    108 
    109 	while (next_menu == Start_Menu) {
    110 		XNextEvent(display, &event);
    111 		switch (event.type) {
    112 		case Expose: {
    113 			XDrawString(display, window, fgc,
    114 						win_width/2 - strlen(menu_char_q)/2, win_height/2,
    115 						menu_char_q, strlen(menu_char_q));
    116 			XDrawString(display, window, fgc,
    117 						win_width/2 - strlen(menu_char_s)/2, win_height/2 + 20,
    118 						menu_char_s, strlen(menu_char_s));
    119 			
    120 		} break;
    121 		case KeyPress: {
    122 			switch (XLookupKeysym(&event.xkey, 0)) {
    123 			case 'q':
    124 				next_menu = Quit;
    125 				break;
    126 			case ' ':
    127 				next_menu = Game_Play;
    128 				break;
    129 			default:
    130 				break;
    131 			}
    132 		} break;
    133 		case ClientMessage: {
    134 			if ((Atom) event.xclient.data.l[0] == wm_delete_window) {
    135 				next_menu = Quit;
    136 			}
    137 		} break;
    138 		default:
    139 			break;
    140 		}
    141 	}
    142 }
    143 
    144 void
    145 game_init(void)
    146 {
    147 	if(!square) // not allocated
    148 		if(!(square = obj_create(100, 100, 0, 0, 0, 0, 400, 20, 20))){
    149 			fprintf(stderr, "couldn't create object: square");
    150 			exit(1);
    151 		}
    152 	for (int i = 0; i < BLOCK_COUNT; i++){
    153 		struct timespec t;
    154 		clock_gettime(CLOCK_REALTIME, &t);
    155 		srand(t.tv_nsec);
    156 		if(!blocks[i]) // not allocated
    157 			if(!(blocks[i] = obj_create((i + 1) * 100,
    158 										200,
    159 										0, 0,
    160 										0, 0, 100, 10, 10))){
    161 				fprintf(stderr, "couldn't create object: block");
    162 				exit(1);
    163 			}
    164 	}
    165 	
    166 	square->px = 100;
    167 	square->py = 100;
    168 	square->vx = square->vy = 0;
    169 	square->ax = square->ay = 0;
    170 }
    171 
    172 void
    173 game_play(void)
    174 {
    175 	long t0, t1, dt;
    176 	struct timespec ts;
    177 
    178 	game_init();
    179 
    180 	clock_gettime(CLOCK_MONOTONIC, &ts);
    181 	t0 = ts.tv_nsec;
    182 
    183 	while (next_menu == Game_Play){
    184 		XWindowAttributes window_attributes_return;
    185 		XGetWindowAttributes(display, window, &window_attributes_return);
    186 		win_width = window_attributes_return.width;
    187 		win_height = window_attributes_return.height;
    188 
    189 		clock_gettime(CLOCK_MONOTONIC, &ts);
    190 		t1 = ts.tv_nsec;
    191 		dt = t1 - t0 > 0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000;
    192 		while(dt < 1.0/FPS * 1000 * 1000 * 1000){
    193 			clock_gettime(CLOCK_MONOTONIC, &ts);
    194 			t1 = ts.tv_nsec;
    195 			dt = t1 - t0 > 0 ? t1 - t0 : t1 - t0 + 1000 * 1000 * 1000;
    196 		}
    197 
    198 		//handle_interactions(); //handle interactions between objects
    199 		handle_inputs();
    200 		obj_next_tick(square, 1.0/FPS);
    201 		for (int i = 0; i < BLOCK_COUNT; i++)
    202 			obj_next_tick(blocks[i], 1.0/FPS);
    203 		handle_collision();
    204 
    205 		clock_gettime(CLOCK_MONOTONIC, &ts);
    206 		t0 = ts.tv_nsec;
    207 
    208 		XClearArea(display, window, 0, 0, win_width, win_height, False);
    209 		draw_object(square, pgc);
    210 		for (int i = 0; i < BLOCK_COUNT; i++){
    211 			XSetForeground(display, bgc, 255 << 8 * i);
    212 			draw_object(blocks[i], bgc);
    213 		}
    214 		//XDrawString(display, window, fgc, square->px, square->py, "player", 6);
    215 	}
    216 }
    217 
    218 void
    219 draw_object(Obj *obj, GC gc)
    220 {
    221 	XFillRectangle(display, window, gc, obj->px, obj->py, obj->width, obj->height);
    222 }
    223 
    224 void
    225 end_menu(void)
    226 {
    227 	next_menu = Start_Menu;
    228 }
    229 
    230 void
    231 handle_inputs(void)
    232 {
    233 	while (XPending(display) > 0) {
    234 		XEvent event;
    235 		XNextEvent(display, &event);
    236 		switch (event.type) {
    237 		case KeyPress: {
    238 			switch (XLookupKeysym(&event.xkey, 0)) {
    239 			case 'q':
    240 				next_menu = End_Menu;
    241 				break;
    242 			case 'd':
    243 				key_state[Key_D] = Key_Down;
    244 				break;
    245 			case 'a':
    246 				key_state[Key_A] = Key_Down;
    247 				break;
    248 			case 'w':
    249 				key_state[Key_W] = Key_Down;
    250 				break;
    251 			case 's':
    252 				key_state[Key_S] = Key_Down;
    253 				break;
    254 			case ' ':
    255 				key_state[Key_Space] = Key_Down;
    256 				break;
    257 			default:
    258 				break;
    259 			}
    260 		} break;
    261 		case KeyRelease: {
    262 			switch (XLookupKeysym(&event.xkey, 0)) {
    263 			case 'd':
    264 				key_state[Key_D] = Key_Up;
    265 				break;
    266 			case 'a':
    267 				key_state[Key_A] = Key_Up;
    268 				break;
    269 			case 'w':
    270 				key_state[Key_W] = Key_Up;
    271 				break;
    272 			case 's':
    273 				key_state[Key_S] = Key_Up;
    274 				break;
    275 			case ' ':
    276 				key_state[Key_Space] = Key_Up;
    277 				break;
    278 			default:
    279 				break;
    280 			}
    281 		} break;
    282 		case ClientMessage: {
    283 			if ((Atom) event.xclient.data.l[0] == wm_delete_window) {
    284 				next_menu = Quit;
    285 			}
    286 		} break;
    287 		default:
    288 			break;
    289 		}
    290 	}
    291 
    292 	square->vx = 0;
    293 	if (key_state[Key_D] == Key_Down)
    294 		square->vx += 100;
    295 	else
    296 		square->vx -= 100;
    297 	if (key_state[Key_A] == Key_Down)
    298 		square->vx += -100;
    299 	else
    300 		square->vx -= -100;
    301 
    302 	square->vy = 0;
    303 	if (key_state[Key_S] == Key_Down)
    304 		square->vy += 100;
    305 	else
    306 		square->vy -= 100;
    307 	if (key_state[Key_W] == Key_Down)
    308 		square->vy += -100;
    309 	else
    310 		square->vy -= -100;
    311 }
    312 
    313 void
    314 handle_collision(void)
    315 {
    316 	for (int i = 0; i < BLOCK_COUNT; i++){
    317 		if (blocks[i]->px <= 0){
    318 			blocks[i]->px = 0;
    319 			blocks[i]->vx *= -1;
    320 		}
    321 		if (win_width <= blocks[i]->px + blocks[i]->width){
    322 			blocks[i]->px = win_width - blocks[i]->width;
    323 			blocks[i]->vx *= -1;
    324 		}
    325 
    326 		if (blocks[i]->py <= 0){
    327 			blocks[i]->py = 0;
    328 			blocks[i]->vy *= -1;
    329 		}
    330 		if (win_height <= blocks[i]->py + blocks[i]->height){
    331 			blocks[i]->py = win_height - blocks[i]->height;
    332 			blocks[i]->vy *= -1;
    333 		}
    334 	}
    335 
    336 	if (square->px <= 0){
    337 		square->px = 0;
    338 		square->vx *= -1;
    339 	}
    340 	if (win_width <= square->px + square->width){
    341 		square->px = win_width - square->width;
    342 		square->vx *= -1;
    343 	}
    344 	if (square->py <= 0){
    345 		square->py = 0;
    346 		square->vy *= -1;
    347 	}
    348 	if (win_height <= square->py + square->height){
    349 		square->py = win_height - square->height;
    350 		square->vy *= -1;
    351 	}
    352 
    353 	for (int i = 0; i < BLOCK_COUNT; i++){
    354 		for (int j = i; j < BLOCK_COUNT; j++){
    355 			obj_handle_collision(blocks[i], blocks[j]);
    356 		}
    357 	}
    358 	for (int i = 0; i < BLOCK_COUNT; i++){
    359 		obj_handle_collision(blocks[i], square);
    360 	}
    361 }
    362 
    363 
    364 void
    365 cleanup(void)
    366 {
    367 	XCloseDisplay(display);
    368 }
    369 
    370 int
    371 main(void)
    372 {
    373 	setup();
    374 
    375 	while (next_menu != Quit){
    376 		switch (next_menu){
    377 		case Start_Menu:
    378 			start_menu();
    379 			break;
    380 		case Game_Play:
    381 			game_play();
    382 			break;
    383 		case End_Menu:
    384 			end_menu();
    385 			break;
    386 		default:
    387 			break;
    388 		}
    389 	}
    390 
    391 	cleanup();
    392 	return 0;
    393 }