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 }