Advertisement
Guest User

Untitled

a guest
Dec 14th, 2019
592
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.22 KB | None | 0 0
  1. // [main.c]
  2. // this template is provided for the 2D shooter game.
  3.  
  4. #define _CRT_SECURE_NO_DEPRECATE
  5. #include <stdio.h>
  6. #include <allegro5/allegro.h>
  7. #include <allegro5/allegro_primitives.h>
  8. #include <allegro5/allegro_image.h>
  9. #include <allegro5/allegro_font.h>
  10. #include <allegro5/allegro_ttf.h>
  11. #include <allegro5/allegro_audio.h>
  12. #include <allegro5/allegro_acodec.h>
  13. #include <math.h>
  14.  
  15. // If defined, logs will be shown on console and written to file.
  16. // If commented out, logs will not be shown nor be saved.
  17. #define LOG_ENABLED
  18.  
  19. /* Constants. */
  20.  
  21. // Frame rate (frame per second)
  22. const int FPS = 60;
  23. // Display (screen) width.
  24. const int SCREEN_W = 800;
  25. // Display (screen) height.
  26. const int SCREEN_H = 600;
  27. // At most 4 audios can be played at a time.
  28. const int RESERVE_SAMPLES = 4;
  29. // Same as:
  30. // const int SCENE_MENU = 1;
  31. // const int SCENE_START = 2;
  32. enum {
  33. SCENE_MENU = 1,
  34. SCENE_START = 2,
  35. SCENE_SETTING = 3
  36. // [HACKATHON 3-7]
  37. // TODO: Declare a new scene id.
  38. // , SCENE_SETTINGS = 3
  39. };
  40.  
  41. /* Input states */
  42.  
  43. // The active scene id.
  44. int active_scene;
  45. // Keyboard state, whether the key is down or not.
  46. bool key_state[ALLEGRO_KEY_MAX];
  47. // Mouse state, whether the key is down or not.
  48. // 1 is for left, 2 is for right, 3 is for middle.
  49. bool *mouse_state;
  50. // Mouse position.
  51. int mouse_x, mouse_y;
  52. // TODO: More variables to store input states such as joysticks, ...
  53.  
  54. /* Variables for allegro basic routines. */
  55.  
  56. ALLEGRO_DISPLAY* game_display;
  57. ALLEGRO_EVENT_QUEUE* game_event_queue;
  58. ALLEGRO_TIMER* game_update_timer;
  59.  
  60. /* Shared resources*/
  61.  
  62. ALLEGRO_FONT* font_pirulen_32;
  63. ALLEGRO_FONT* font_pirulen_24;
  64. // TODO: More shared resources or data that needed to be accessed
  65. // across different scenes.
  66.  
  67. /* Menu Scene resources*/
  68. ALLEGRO_BITMAP* main_img_background;
  69. ALLEGRO_BITMAP* setting_img;
  70. ALLEGRO_BITMAP* setting_img2;
  71. // [HACKATHON 3-1]
  72. // TODO: Declare 2 variables for storing settings images.
  73. // Uncomment and fill in the code below.
  74. //??? img_settings;
  75. //??? img_settings2;
  76. ALLEGRO_SAMPLE* main_bgm;
  77. ALLEGRO_SAMPLE_ID main_bgm_id;
  78.  
  79. /* Start Scene resources*/
  80. ALLEGRO_BITMAP* start_img_background;
  81. ALLEGRO_BITMAP* start_img_plane;
  82. ALLEGRO_BITMAP* start_img_enemy;
  83. ALLEGRO_BITMAP* img_bullet;
  84. ALLEGRO_SAMPLE* start_bgm;
  85. ALLEGRO_SAMPLE_ID start_bgm_id;
  86. // [HACKATHON 2-1]
  87. // TODO: Declare a variable to store your bullet's image.
  88. // Uncomment and fill in the code below.
  89. //??? img_bullet;
  90.  
  91. typedef struct {
  92. // The center coordinate of the image.
  93. float x, y;
  94. // The width and height of the object.
  95. float w, h;
  96. // The velocity in x, y axes.
  97. float vx, vy;
  98. // Should we draw this object on the screen.
  99. bool hidden;
  100. // The pointer to the object¡¦s image.
  101. ALLEGRO_BITMAP* img;
  102. } MovableObject;
  103. void draw_movable_object(MovableObject obj);
  104. #define MAX_ENEMY 3
  105. // [HACKATHON 2-2]
  106. // TODO: Declare the max bullet count that will show on screen.
  107. // You can try max 4 bullets here and see if you needed more.
  108. // Uncomment and fill in the code below.
  109. #define MAX_BULLET 5
  110. MovableObject plane;
  111. MovableObject enemies[MAX_ENEMY];
  112. MovableObject bullets[MAX_BULLET];
  113. // [HACKATHON 2-3]
  114. // TODO: Declare an array to store bullets with size of max bullet count.
  115. // Uncomment and fill in the code below.
  116. //??? bullets[???];
  117. // [HACKATHON 2-4]
  118. // TODO: Set up bullet shooting cool-down variables.
  119. // 1) Declare your shooting cool-down time as constant. (0.2f will be nice)
  120. // 2) Declare your last shoot timestamp.
  121. // Uncomment and fill in the code below.
  122. const float MAX_COOLDOWN = 0.2f;
  123. double last_shoot_timestamp;
  124.  
  125. /* Declare function prototypes. */
  126.  
  127. // Initialize allegro5 library
  128. void allegro5_init(void);
  129. // Initialize variables and resources.
  130. // Allows the game to perform any initialization it needs before
  131. // starting to run.
  132. void game_init(void);
  133. // Process events inside the event queue using an infinity loop.
  134. void game_start_event_loop(void);
  135. // Run game logic such as updating the world, checking for collision,
  136. // switching scenes and so on.
  137. // This is called when the game should update its logic.
  138. void game_update(void);
  139. // Draw to display.
  140. // This is called when the game should draw itself.
  141. void game_draw(void);
  142. // Release resources.
  143. // Free the pointers we allocated.
  144. void game_destroy(void);
  145. // Function to change from one scene to another.
  146. void game_change_scene(int next_scene);
  147. // Load resized bitmap and check if failed.
  148. ALLEGRO_BITMAP *load_bitmap_resized(const char *filename, int w, int h);
  149. // [HACKATHON 3-2]
  150. // TODO: Declare a function.
  151. // Determines whether the point (px, py) is in rect (x, y, w, h).
  152. // Uncomment the code below.
  153. bool pnt_in_rect(int px, int py, int x, int y, int w, int h);
  154.  
  155. /* Event callbacks. */
  156. void on_key_down(int keycode);
  157. void on_mouse_down(int btn, int x, int y);
  158.  
  159. /* Declare function prototypes for debugging. */
  160.  
  161. // Display error message and exit the program, used like 'printf'.
  162. // Write formatted output to stdout and file from the format string.
  163. // If the program crashes unexpectedly, you can inspect "log.txt" for
  164. // further information.
  165. void game_abort(const char* format, ...);
  166. // Log events for later debugging, used like 'printf'.
  167. // Write formatted output to stdout and file from the format string.
  168. // You can inspect "log.txt" for logs in the last run.
  169. void game_log(const char* format, ...);
  170. // Log using va_list.
  171. void game_vlog(const char* format, va_list arg);
  172.  
  173. int main(int argc, char** argv) {
  174. // Set random seed for better random outcome.
  175. srand(time(NULL));
  176. allegro5_init();
  177. game_log("Allegro5 initialized");
  178. game_log("Game begin");
  179. // Initialize game variables.
  180. game_init();
  181. game_log("Game initialized");
  182. // Draw the first frame.
  183. game_draw();
  184. game_log("Game start event loop");
  185. // This call blocks until the game is finished.
  186. game_start_event_loop();
  187. game_log("Game end");
  188. game_destroy();
  189. return 0;
  190. }
  191.  
  192. void allegro5_init(void) {
  193. if (!al_init())
  194. game_abort("failed to initialize allegro");
  195.  
  196. // Initialize add-ons.
  197. if (!al_init_primitives_addon())
  198. game_abort("failed to initialize primitives add-on");
  199. if (!al_init_font_addon())
  200. game_abort("failed to initialize font add-on");
  201. if (!al_init_ttf_addon())
  202. game_abort("failed to initialize ttf add-on");
  203. if (!al_init_image_addon())
  204. game_abort("failed to initialize image add-on");
  205. if (!al_install_audio())
  206. game_abort("failed to initialize audio add-on");
  207. if (!al_init_acodec_addon())
  208. game_abort("failed to initialize audio codec add-on");
  209. if (!al_reserve_samples(RESERVE_SAMPLES))
  210. game_abort("failed to reserve samples");
  211. if (!al_install_keyboard())
  212. game_abort("failed to install keyboard");
  213. if (!al_install_mouse())
  214. game_abort("failed to install mouse");
  215. // TODO: Initialize other addons such as video, ...
  216.  
  217. // Setup game display.
  218. game_display = al_create_display(SCREEN_W, SCREEN_H);
  219. if (!game_display)
  220. game_abort("failed to create display");
  221. al_set_window_title(game_display, "I2P(I)_2019 Final Project <student_id>");
  222.  
  223. // Setup update timer.
  224. game_update_timer = al_create_timer(1.0f / FPS);
  225. if (!game_update_timer)
  226. game_abort("failed to create timer");
  227.  
  228. // Setup event queue.
  229. game_event_queue = al_create_event_queue();
  230. if (!game_event_queue)
  231. game_abort("failed to create event queue");
  232.  
  233. // Malloc mouse buttons state according to button counts.
  234. const unsigned m_buttons = al_get_mouse_num_buttons();
  235. game_log("There are total %u supported mouse buttons", m_buttons);
  236. // mouse_state[0] will not be used.
  237. mouse_state = malloc((m_buttons + 1) * sizeof(bool));
  238. memset(mouse_state, false, (m_buttons + 1) * sizeof(bool));
  239.  
  240. // Register display, timer, keyboard, mouse events to the event queue.
  241. al_register_event_source(game_event_queue, al_get_display_event_source(game_display));
  242. al_register_event_source(game_event_queue, al_get_timer_event_source(game_update_timer));
  243. al_register_event_source(game_event_queue, al_get_keyboard_event_source());
  244. al_register_event_source(game_event_queue, al_get_mouse_event_source());
  245. // TODO: Register other event sources such as timer, video, ...
  246.  
  247. // Start the timer to update and draw the game.
  248. al_start_timer(game_update_timer);
  249. }
  250.  
  251. void game_init(void) {
  252. /* Shared resources*/
  253. font_pirulen_32 = al_load_font("pirulen.ttf", 32, 0);
  254. if (!font_pirulen_32)
  255. game_abort("failed to load font: pirulen.ttf with size 32");
  256.  
  257. font_pirulen_24 = al_load_font("pirulen.ttf", 24, 0);
  258. if (!font_pirulen_24)
  259. game_abort("failed to load font: pirulen.ttf with size 24");
  260.  
  261. /* Menu Scene resources*/
  262. main_img_background = load_bitmap_resized("main-bg.jpg", SCREEN_W, SCREEN_H);
  263.  
  264. main_bgm = al_load_sample("S31-Night Prowler.ogg");
  265. if (!main_bgm)
  266. game_abort("failed to load audio: S31-Night Prowler.ogg");
  267. setting_img = al_load_bitmap("settings.png");
  268. if(!setting_img)
  269. game_abort("failed to load setting img");
  270. setting_img2 = al_load_bitmap("settings2.png");
  271. if(!setting_img)
  272. game_abort("failed to load setting img2");
  273. // [HACKATHON 3-4]
  274. // TODO: Load settings images.
  275. // Don't forget to check their return values.
  276. // Uncomment and fill in the code below.
  277. //img_settings = ???("settings.png");
  278. //if (!???)
  279. // game_abort("failed to load image: settings.png");
  280. //img_settings2 = ???("settings2.png");
  281. //if (!???)
  282. // game_abort("failed to load image: settings2.png");
  283.  
  284. /* Start Scene resources*/
  285. start_img_background = load_bitmap_resized("start-bg.jpg", SCREEN_W, SCREEN_H);
  286.  
  287. start_img_plane = al_load_bitmap("plane.png");
  288. if (!start_img_plane)
  289. game_abort("failed to load image: plane.png");
  290.  
  291. start_img_enemy = al_load_bitmap("smallfighter0006.png");
  292. if (!start_img_enemy)
  293. game_abort("failed to load image: smallfighter0006.png");
  294.  
  295. start_bgm = al_load_sample("mythica.ogg");
  296. if (!start_bgm)
  297. game_abort("failed to load audio: mythica.ogg");
  298. img_bullet = al_load_bitmap("image12.png");
  299. if (!img_bullet)
  300. game_abort("failed to load bullet img");
  301.  
  302. // [HACKATHON 2-5]
  303. // TODO: Initialize bullets.
  304. // 1) Search for a bullet image online and put it in your project.
  305. // You can use the image we provided.
  306. // 2) Load it in by 'al_load_bitmap' or 'load_bitmap_resized'.
  307. // 3) If you use 'al_load_bitmap', don't forget to check its return value.
  308. // Uncomment and fill in the code below.
  309. //img_bullet = ???("image12.png");
  310. //if (!img_bullet)
  311. // game_abort("failed to load image: image12.png");
  312.  
  313. // Change to first scene.
  314. game_change_scene(SCENE_MENU);
  315. }
  316.  
  317. void game_start_event_loop(void) {
  318. bool done = false;
  319. ALLEGRO_EVENT event;
  320. int redraws = 0;
  321. while (!done) {
  322. al_wait_for_event(game_event_queue, &event);
  323. if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
  324. // Event for clicking the window close button.
  325. game_log("Window close button clicked");
  326. done = true;
  327. } else if (event.type == ALLEGRO_EVENT_TIMER) {
  328. // Event for redrawing the display.
  329. if (event.timer.source == game_update_timer)
  330. // The redraw timer has ticked.
  331. redraws++;
  332. } else if (event.type == ALLEGRO_EVENT_KEY_DOWN) {
  333. // Event for keyboard key down.
  334. game_log("Key with keycode %d down", event.keyboard.keycode);
  335. key_state[event.keyboard.keycode] = true;
  336. on_key_down(event.keyboard.keycode);
  337. } else if (event.type == ALLEGRO_EVENT_KEY_UP) {
  338. // Event for keyboard key up.
  339. game_log("Key with keycode %d up", event.keyboard.keycode);
  340. key_state[event.keyboard.keycode] = false;
  341. } else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
  342. // Event for mouse key down.
  343. game_log("Mouse button %d down at (%d, %d)", event.mouse.button, event.mouse.x, event.mouse.y);
  344. mouse_state[event.mouse.button] = true;
  345. on_mouse_down(event.mouse.button, event.mouse.x, event.mouse.y);
  346. } else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) {
  347. // Event for mouse key up.
  348. game_log("Mouse button %d up at (%d, %d)", event.mouse.button, event.mouse.x, event.mouse.y);
  349. mouse_state[event.mouse.button] = false;
  350. } else if (event.type == ALLEGRO_EVENT_MOUSE_AXES) {
  351. if (event.mouse.dx != 0 || event.mouse.dy != 0) {
  352. // Event for mouse move.
  353. game_log("Mouse move to (%d, %d)", event.mouse.x, event.mouse.y);
  354. mouse_x = event.mouse.x;
  355. mouse_y = event.mouse.y;
  356. } else if (event.mouse.dz != 0) {
  357. // Event for mouse scroll.
  358. game_log("Mouse scroll at (%d, %d) with delta %d", event.mouse.x, event.mouse.y, event.mouse.dz);
  359. }
  360. }
  361. // TODO: Process more events and call callbacks by adding more
  362. // entries inside Scene.
  363.  
  364. // Redraw
  365. if (redraws > 0 && al_is_event_queue_empty(game_event_queue)) {
  366. // if (redraws > 1)
  367. // game_log("%d frame(s) dropped", redraws - 1);
  368. // Update and draw the next frame.
  369. game_update();
  370. game_draw();
  371. redraws = 0;
  372. }
  373. }
  374. }
  375.  
  376. void game_update(void) {
  377. if (active_scene == SCENE_START) {
  378. plane.vx = plane.vy = 0;
  379. if (key_state[ALLEGRO_KEY_UP] || key_state[ALLEGRO_KEY_W])
  380. plane.vy -= 1;
  381. if (key_state[ALLEGRO_KEY_DOWN] || key_state[ALLEGRO_KEY_S])
  382. plane.vy += 1;
  383. if (key_state[ALLEGRO_KEY_LEFT] || key_state[ALLEGRO_KEY_A])
  384. plane.vx -= 1;
  385. if (key_state[ALLEGRO_KEY_RIGHT] || key_state[ALLEGRO_KEY_D])
  386. plane.vx += 1;
  387. // 0.71 is (1/sqrt(2)).
  388. plane.y += plane.vy * 4 * (plane.vx ? 0.71f : 1);
  389. plane.x += plane.vx * 4 * (plane.vy ? 0.71f : 1);
  390. // [HACKATHON 1-1]
  391. // TODO: Limit the plane's collision box inside the frame.
  392. // (x, y axes can be separated.)
  393. // Uncomment and fill in the code below.
  394. if (plane.x < 20)
  395. plane.x = 20;
  396. else if (plane.x > SCREEN_W-20)
  397. plane.x = SCREEN_W-20;
  398. if (plane.y < 20)
  399. plane.y = 20;
  400. else if (plane.y > SCREEN_H-20)
  401. plane.y = SCREEN_H-20;
  402.  
  403. // [HACKATHON 2-7]
  404. // TODO: Update bullet coordinates.
  405. // 1) For each bullets, if it's not hidden, update x, y
  406. // according to vx, vy.
  407. // 2) If the bullet is out of the screen, hide it.
  408. // Uncomment and fill in the code below.
  409. int i;
  410. for (i=0;i<MAX_BULLET;i++) {
  411. if (bullets[i].hidden = false)
  412. continue;
  413. bullets[i].x += bullets[i].vx;
  414. bullets[i].y += bullets[i].vy;
  415. if (bullets[i].y < 0)
  416. bullets[i].hidden = true;
  417. }
  418.  
  419. // [HACKATHON 2-8]
  420. // TODO: Shoot if key is down and cool-down is over.
  421. // 1) Get the time now using 'al_get_time'.
  422. // 2) If Space key is down in 'key_state' and the time
  423. // between now and last shoot is not less that cool
  424. // down time.
  425. // 3) Loop through the bullet array and find one that is hidden.
  426. // (This part can be optimized.)
  427. // 4) The bullet will be found if your array is large enough.
  428. // 5) Set the last shoot time to now.
  429. // 6) Set hidden to false (recycle the bullet) and set its x, y to the
  430. // front part of your plane.
  431. // Uncomment and fill in the code below.
  432. double now = al_get_time();
  433. if (key_state[ALLEGRO_KEY_SPACE] && now - last_shoot_timestamp >= MAX_COOLDOWN) {
  434. for (i = 0; i<MAX_BULLET;i++) {
  435. if (bullets[i].hidden == true)
  436. break;
  437. }
  438. if (i < MAX_BULLET) {
  439. last_shoot_timestamp = now;
  440. bullets[i].hidden = false;
  441. bullets[i].x = plane.x;
  442. bullets[i].y = plane.y -20;
  443. }
  444. }
  445. }
  446. }
  447.  
  448. void game_draw(void) {
  449. if (active_scene == SCENE_MENU) {
  450. al_draw_bitmap(main_img_background, 0, 0, 0);
  451. al_draw_text(font_pirulen_32, al_map_rgb(255, 255, 255), SCREEN_W / 2, 30, ALLEGRO_ALIGN_CENTER, "Space Shooter");
  452. al_draw_text(font_pirulen_24, al_map_rgb(255, 255, 255), 20, SCREEN_H - 50, 0, "Press enter key to start");
  453. al_draw_bitmap(setting_img,10,10,0);
  454. // [HACKATHON 3-5]
  455. // TODO: Draw settings images.
  456. // The settings icon should be located at (x, y, w, h) =
  457. // (SCREEN_W - 48, 10, 38, 38).
  458. // Change its image according to your mouse position.
  459. // Uncomment and fill in the code below.
  460. //if (pnt_in_rect(mouse_x, mouse_y, ???, ???, ???, ???))
  461. // ???(img_settings2, ???, ???, 0);
  462. //else
  463. // ???(img_settings, ???, ???, 0);
  464. } else if (active_scene == SCENE_START) {
  465. int i;
  466. al_draw_bitmap(start_img_background, 0, 0, 0);
  467. al_draw_bitmap(setting_img,10,10,0);
  468. // [HACKATHON 2-9]
  469. // TODO: Draw all bullets in your bullet array.
  470. // Uncomment and fill in the code below.
  471. for (i=0;i<MAX_BULLET;i++)
  472. draw_movable_object(bullets[i]);
  473. draw_movable_object(plane);
  474. for (i = 0; i < MAX_ENEMY; i++)
  475. draw_movable_object(enemies[i]);
  476. }
  477. // [HACKATHON 3-9]
  478. // TODO: If active_scene is SCENE_SETTINGS.
  479. // Draw anything you want, or simply clear the display.
  480. else if (active_scene == SCENE_SETTING) {
  481. al_clear_to_color(al_map_rgb(0, 0, 0));
  482. al_draw_bitmap(setting_img,10,10,0);
  483. }
  484. al_flip_display();
  485. }
  486.  
  487. void game_destroy(void) {
  488. // Destroy everything you have created.
  489. // Free the memories allocated by malloc or allegro functions.
  490. // Destroy shared resources.
  491. al_destroy_font(font_pirulen_32);
  492. al_destroy_font(font_pirulen_24);
  493.  
  494. /* Menu Scene resources*/
  495. al_destroy_bitmap(main_img_background);
  496. al_destroy_sample(main_bgm);
  497. // [HACKATHON 3-6]
  498. // TODO: Destroy the 2 settings images.
  499. // Uncomment and fill in the code below.
  500. //???(img_settings);
  501. //???(img_settings2);
  502.  
  503. /* Start Scene resources*/
  504. al_destroy_bitmap(start_img_background);
  505. al_destroy_bitmap(start_img_plane);
  506. al_destroy_bitmap(start_img_enemy);
  507. al_destroy_sample(start_bgm);
  508. al_destroy_sample(img_bullet);
  509. // [HACKATHON 2-10]
  510. // TODO: Destroy your bullet image.
  511. // Uncomment and fill in the code below.
  512. //???(img_bullet);
  513.  
  514. al_destroy_timer(game_update_timer);
  515. al_destroy_event_queue(game_event_queue);
  516. al_destroy_display(game_display);
  517. free(mouse_state);
  518. }
  519.  
  520. void game_change_scene(int next_scene) {
  521. game_log("Change scene from %d to %d", active_scene, next_scene);
  522. // TODO: Destroy resources initialized when creating scene.
  523. if (active_scene == SCENE_MENU) {
  524. al_stop_sample(&main_bgm_id);
  525. game_log("stop audio (bgm)");
  526. } else if (active_scene == SCENE_START) {
  527. al_stop_sample(&start_bgm_id);
  528. game_log("stop audio (bgm)");
  529. }
  530. active_scene = next_scene;
  531. // TODO: Allocate resources before entering scene.
  532. if (active_scene == SCENE_MENU) {
  533. if (!al_play_sample(main_bgm, 1, 0.0, 1.0, ALLEGRO_PLAYMODE_LOOP, &main_bgm_id))
  534. game_abort("failed to play audio (bgm)");
  535. } else if (active_scene == SCENE_START) {
  536. int i;
  537. plane.img = start_img_plane;
  538. plane.x = 400;
  539. plane.y = 500;
  540. plane.w = al_get_bitmap_width(plane.img);
  541. plane.h = al_get_bitmap_height(plane.img);
  542. for (i = 0; i < MAX_ENEMY; i++) {
  543. enemies[i].img = start_img_enemy;
  544. enemies[i].w = al_get_bitmap_width(start_img_enemy);
  545. enemies[i].h = al_get_bitmap_height(start_img_enemy);
  546. enemies[i].x = enemies[i].w / 2 + (float)rand() / RAND_MAX * (SCREEN_W - enemies[i].w);
  547. enemies[i].y = 80;
  548. }
  549. // [HACKATHON 2-6]
  550. // TODO: Initialize bullets.
  551. // For each bullets in array, set their w and h to the size of
  552. // the image, and set their img to bullet image, hidden to true,
  553. // (vx, vy) to (0, -3).
  554. // Uncomment and fill in the code below.
  555. for (i=0;i<MAX_BULLET;i++) {
  556. bullets[i].w = al_get_bitmap_width(img_bullet);
  557. bullets[i].h = al_get_bitmap_height(img_bullet);
  558. bullets[i].img = img_bullet;
  559. bullets[i].vx = 0;
  560. bullets[i].vy = -3;
  561. bullets[i].hidden = true;
  562. }
  563. if (!al_play_sample(start_bgm, 1, 0.0, 1.0, ALLEGRO_PLAYMODE_LOOP, &start_bgm_id))
  564. game_abort("failed to play audio (bgm)");
  565. }
  566. }
  567.  
  568. void on_key_down(int keycode) {
  569. if (active_scene == SCENE_MENU) {
  570. if (keycode == ALLEGRO_KEY_ENTER)
  571. game_change_scene(SCENE_START);
  572. }
  573. }
  574.  
  575. void on_mouse_down(int btn, int x, int y) {
  576. // [HACKATHON 3-8]
  577. // TODO: When settings clicked, switch to settings scene.
  578. // Uncomment and fill in the code below.
  579. if (active_scene == SCENE_START||active_scene == SCENE_MENU) {
  580. if (btn == 1) {
  581. if (pnt_in_rect(x,y, 11, 11, 37, 37))
  582. game_change_scene(SCENE_SETTING);
  583. }
  584. }
  585. else if(active_scene == SCENE_SETTING){
  586. if (btn == 1) {
  587. if (pnt_in_rect(x,y, 11, 11, 37, 37))
  588. game_change_scene(SCENE_MENU);
  589. }
  590. }
  591. }
  592.  
  593. void draw_movable_object(MovableObject obj) {
  594. if (obj.hidden)
  595. return;
  596. al_draw_bitmap(obj.img, round(obj.x - obj.w / 2), round(obj.y - obj.h / 2), 0);
  597. }
  598.  
  599. ALLEGRO_BITMAP *load_bitmap_resized(const char *filename, int w, int h) {
  600. ALLEGRO_BITMAP* loaded_bmp = al_load_bitmap(filename);
  601. if (!loaded_bmp)
  602. game_abort("failed to load image: %s", filename);
  603. ALLEGRO_BITMAP *resized_bmp = al_create_bitmap(w, h);
  604. ALLEGRO_BITMAP *prev_target = al_get_target_bitmap();
  605.  
  606. if (!resized_bmp)
  607. game_abort("failed to create bitmap when creating resized image: %s", filename);
  608. al_set_target_bitmap(resized_bmp);
  609. al_draw_scaled_bitmap(loaded_bmp, 0, 0,
  610. al_get_bitmap_width(loaded_bmp),
  611. al_get_bitmap_height(loaded_bmp),
  612. 0, 0, w, h, 0);
  613. al_set_target_bitmap(prev_target);
  614. al_destroy_bitmap(loaded_bmp);
  615.  
  616. game_log("resized image: %s", filename);
  617.  
  618. return resized_bmp;
  619. }
  620.  
  621. // [HACKATHON 3-3]
  622. // TODO: Define bool pnt_in_rect(int px, int py, int x, int y, int w, int h)
  623. // Uncomment and fill in the code below.
  624. bool pnt_in_rect(int px, int py, int x, int y, int w, int h) {
  625. if((x<px)&&(px<x+w)&&(py>y)&&(py<y+h)) return true;
  626. return false;
  627. }
  628.  
  629.  
  630. // +=================================================================+
  631. // | Code below is for debugging purpose, it's fine to remove it. |
  632. // | Deleting the code below and removing all calls to the functions |
  633. // | doesn't affect the game. |
  634. // +=================================================================+
  635.  
  636. void game_abort(const char* format, ...) {
  637. va_list arg;
  638. va_start(arg, format);
  639. game_vlog(format, arg);
  640. va_end(arg);
  641. fprintf(stderr, "error occured, exiting after 2 secs");
  642. // Wait 2 secs before exiting.
  643. al_rest(2);
  644. // Force exit program.
  645. exit(1);
  646. }
  647.  
  648. void game_log(const char* format, ...) {
  649. #ifdef LOG_ENABLED
  650. va_list arg;
  651. va_start(arg, format);
  652. game_vlog(format, arg);
  653. va_end(arg);
  654. #endif
  655. }
  656.  
  657. void game_vlog(const char* format, va_list arg) {
  658. #ifdef LOG_ENABLED
  659. static bool clear_file = true;
  660. vprintf(format, arg);
  661. printf("\n");
  662. // Write log to file for later debugging.
  663. FILE* pFile = fopen("log.txt", clear_file ? "w" : "a");
  664. if (pFile) {
  665. vfprintf(pFile, format, arg);
  666. fprintf(pFile, "\n");
  667. fclose(pFile);
  668. }
  669. clear_file = false;
  670. #endif
  671. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement