void update_explosions(void) { struct explosion *p; for (p = explosions; p != &explosions[MAX_EXPLOSIONS]; p++) { if (p->used) { if (++p->t >= p->ttl) p->used = 0; else update_explosion(p); } } }
int main(int argc, char const *argv[]) { const int FPS = 60; const int MAX_BULLETS = 10; const int MAX_ASTEROIDS = 10; const int MAX_EXPLOSIONS = 10; srand(time(NULL)); int done = 0; int redraw = 1; if(!al_init()) { al_show_native_message_box(NULL, "Error", "Error", "Could not initialize Allegro 5.", 0, ALLEGRO_MESSAGEBOX_ERROR); return -1; } ALLEGRO_DISPLAY *display = al_create_display(screen_width, screen_height); if(!display) { al_show_native_message_box(NULL, "Error", "Error", "Could not create display.", 0, ALLEGRO_MESSAGEBOX_ERROR); return -1; } ALLEGRO_EVENT_QUEUE *event_queue = al_create_event_queue(); if(!event_queue) { al_show_native_message_box(display, "Error", "Error", "Could not create event queue.", 0, ALLEGRO_MESSAGEBOX_ERROR); return -1; } ALLEGRO_TIMER *timer = al_create_timer(1.0/FPS); if(!timer) { al_show_native_message_box(display, "Error", "Error", "Could not create timer.", 0, ALLEGRO_MESSAGEBOX_ERROR); return -1; } if(!al_install_keyboard()) { al_show_native_message_box(display, "Error", "Error", "Could not install keyboard.", 0, ALLEGRO_MESSAGEBOX_ERROR); return -1; } if(!al_install_mouse()) { al_show_native_message_box(display, "Error", "Error", "Could not install mouse.", 0, ALLEGRO_MESSAGEBOX_ERROR); return -1; } if(!al_init_image_addon()) { al_show_native_message_box(display, "Error", "Error", "Could not initialize image addon.", 0, ALLEGRO_MESSAGEBOX_ERROR); return -1; } if(!al_init_primitives_addon()) { al_show_native_message_box(display, "Error", "Error", "Could not initialize primitives addon.", 0, ALLEGRO_MESSAGEBOX_ERROR); } al_init_font_addon(); // for whatever reason this function is void returning if(!al_init_ttf_addon()) { al_show_native_message_box(display, "Error", "Error", "Could not initialize ttf addon.", 0, ALLEGRO_MESSAGEBOX_ERROR); } al_hide_mouse_cursor(display); al_register_event_source(event_queue, al_get_mouse_event_source()); al_register_event_source(event_queue, al_get_keyboard_event_source()); al_register_event_source(event_queue, al_get_display_event_source(display)); al_register_event_source(event_queue, al_get_timer_event_source(timer)); ALLEGRO_FONT *font18 = al_load_font("Arial.ttf", 18, 0); int prev_x = screen_width, prev_y = screen_height; int fps_counter = 0; int fps_counter2 = 0; int i, j, k; struct spaceship ship; init_ship(&ship); struct bullet bullets[MAX_BULLETS]; for(i = 0; i < MAX_BULLETS; i++) { init_bullet(&bullets[i]); } struct asteroid asteroids[MAX_ASTEROIDS]; for(i = 0; i < MAX_ASTEROIDS; i++) { init_asteroid(&asteroids[i]); } struct explosion explosions[MAX_EXPLOSIONS]; for(i = 0; i < MAX_EXPLOSIONS; i++) { init_explosion(&explosions[i]); } al_start_timer(timer); while(!done) { ALLEGRO_EVENT event; al_wait_for_event(event_queue, &event); if(event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { done = 1; } if(event.type == ALLEGRO_EVENT_KEY_DOWN) { switch(event.keyboard.keycode) { case ALLEGRO_KEY_Q: done = 1; break; case ALLEGRO_KEY_ESCAPE: done = 1; break; } } if(event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { if(event.mouse.button & 1) { for(i = 0; i < MAX_BULLETS; i++) { if(!bullets[i].live) { fire_bullet(&bullets[i], ship); break; } } } } if(event.type == ALLEGRO_EVENT_MOUSE_AXES || event.type == ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY) { set_ship_coordinates(&ship, event.mouse.x, event.mouse.y); } if(event.type == ALLEGRO_EVENT_TIMER) { if(ship.x > prev_x) { ship.sprite.dir_horizontal = RIGHT; } else if(ship.x == prev_x) { ship.sprite.dir_horizontal = CENTER; } else if(ship.x < prev_x) { ship.sprite.dir_horizontal = LEFT; } if(ship.y > prev_y) { ship.sprite.dir_vertical = BACK; } else if(ship.y == prev_y) { ship.sprite.dir_vertical = NEUTRAL; } else if(ship.y < prev_y) { ship.sprite.dir_vertical = FORWARD; } if(++fps_counter >= FPS / 5) { fps_counter = 0; prev_x = ship.x; prev_y = ship.y; } if(++fps_counter2 >= 2 * FPS) { for(i = 0; i < MAX_ASTEROIDS; i++) { if(!asteroids[i].live) { start_asteroid(&asteroids[i]); break; } } fps_counter2 = 0; } for(i = 0; i < MAX_BULLETS; i++) { if(bullets[i].live) { update_bullet(&bullets[i]); } } for(i = 0; i < MAX_ASTEROIDS; i++) { if(asteroids[i].live) { update_asteroid(&asteroids[i], &ship); } } for(i = 0; i < MAX_EXPLOSIONS; i++) { if(explosions[i].live) { update_explosion(&explosions[i]); } } update_ship_boundaries(&ship); for(i = 0; i < MAX_BULLETS; i++) { if(bullets[i].live) { for(j = 0; j < MAX_ASTEROIDS; j++) { if(asteroids[j].live) { if(bullet_and_asteroid_collision(bullets[i], asteroids[j])) { bullets[i].live = 0; asteroids[j].live = 0; ship.score += 20; for(k = 0; k < MAX_EXPLOSIONS; k++) { if(!explosions[k].live) { start_explosion(&explosions[k], bullets[i].x, bullets[i].y); break; } } } } } } } for(i = 0; i < MAX_ASTEROIDS; i++) { if(asteroids[i].live) { if(ship_and_asteroid_collision(ship, asteroids[i])) { asteroids[i].live = 0; for(k = 0; k < MAX_EXPLOSIONS; k++) { if(!explosions[k].live) { start_explosion(&explosions[k], ship.x, ship.y); break; } } ship.lives--; } } } if(!ship.lives) { done = true; } redraw = 1; } if(redraw) { redraw = 0; draw_ship_sprite(ship.sprite, ship.x, ship.y); for(i = 0; i < MAX_BULLETS; i++) { if(bullets[i].live) { draw_bullet(bullets[i]); } } for(i = 0; i < MAX_ASTEROIDS; i++) { if(asteroids[i].live) { draw_asteroid(asteroids[i]); } } for(i = 0; i < MAX_EXPLOSIONS; i++) { if(explosions[i].live) { draw_explosion(explosions[i]); } } al_draw_textf(font18, al_map_rgb(255, 255, 255), 50, 5, 0, "Score: %d ", ship.score); // I have no idea why it doesn't print the S... al_draw_textf(font18, al_map_rgb(255, 255, 255), 50, 25, 0, "Lives: %d", ship.lives); al_flip_display(); al_clear_to_color(al_map_rgb(0, 0, 0)); } } for(i = 0; i < MAX_ASTEROIDS; i++) { destroy_asteroid(&asteroids[i]); } for(i = 0; i < MAX_EXPLOSIONS; i++) { destroy_explosion(&explosions[i]); } destroy_sprite(&ship.sprite); al_destroy_display(display); al_destroy_event_queue(event_queue); al_destroy_timer(timer); al_destroy_font(font18); return 0; }
// modify_scene modifies the global variables g_projectiles and g_explosions // during the course of an attack sequence. It takes a parameter dt which // represents the amount of time between frames. // Return: the number of items left to animate. int modify_scene(float dt) { int i, j, num_impacted; float t; struct Projectile *p; struct Explosion *e; struct Tank *tank; Vector v; float d; // Go through all the explosions and update them according to the // amount of time passed. for(j = 0; j < g_num_explosions; j++) { e = &g_explosions[j]; t = update_explosion(e, dt); } // Go through all the projectiles and handle the ones that have not yet // been impacted. for(j = 0, num_impacted = 0; j < g_num_projectiles; j++) { p = &g_projectiles[j]; if(p->o.state != STATE_IMPACTED) { t = update_projectile(p, dt); if(p->o.state == STATE_IMPACTED) { printf("Projectile %d has impacted.\n", j); // If the projectile has impacted, an explosion needs to be // created which is appropriate to the projectile which has // impacted, and which takes on properties of the former // projectile. e = new_explosion(p); // Now, using the remaining time that did not get used on the // projectile, update the new explosion. t = update_explosion(e, dt - t); // And play a sound to match sx3_play_sound(SX3_AUDIO_EXPLOSION); } } if(p->o.state == STATE_IMPACTED) num_impacted++; } // FIX ME!! These two checks don't work properly if we have a low // framerate. for(j = 0; j < g_num_explosions; j++) { e = &g_explosions[j]; for(i = 0; i < g_num_tanks; i++) { tank = &g_tanks[i]; // Don't check this tank if it's already been hit // FIX ME!! This should be on a per-projectile/explosion basis if(tank->s.temp_damage != 0.0) continue; // Find the distance between the tank and the explosion, and test vv_cpy(v, tank->o.props.position); vv_sub(v, e->props.position); d = v_mag(v); if(d < tank->o.props.radius + e->props.radius) { // A tank has been hit! sx3_play_sound(SX3_AUDIO_HIT); printf("Tank %d hit by explosion %d\n", i, j); // FIX ME!! This should not be constant damage. tank->s.temp_damage = 20.0; } } } for(j = 0; j < g_num_projectiles; j++) { p = &g_projectiles[j]; if(p->o.state == STATE_IMPACTED) continue; for(i = 0; i < g_num_tanks; i++) { tank = &g_tanks[i]; // Don't check this tank if it's already been hit // FIX ME!! This should be on a per-projectile/explosion basis if(tank->s.temp_damage != 0.0) continue; // Find the distance between the tank and the projectiles, and test vv_cpy(v, tank->o.props.position); vv_sub(v, p->o.props.position); d = v_mag(v); if(d < tank->o.props.radius + p->o.props.radius) { // A tank has been hit! sx3_play_sound(SX3_AUDIO_HIT); printf("Tank %d hit by projectile %d\n", i, j); // FIX ME!! This should not be constant damage. tank->s.temp_damage = 40.0; } } } return g_num_explosions + g_num_projectiles - num_impacted; }