Untitled
raw download clone
TEXT
views 15
,
size 33047 b
// [main.c]
// this template is provided for the 2D shooter game.

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#include <allegro5/allegro_audio.h>
#include <allegro5/allegro_acodec.h>
#include <math.h>
#include <time.h>

// If defined, logs will be shown on console and written to file.
// If commented out, logs will not be shown nor be saved.
#define LOG_ENABLED

/* Constants. */

// Frame rate (frame per second)
const int FPS = 60;
// Display (screen) width.
const int SCREEN_W = 800;
// Display (screen) height.
const int SCREEN_H = 600;
// At most 4 audios can be played at a time.
const int RESERVE_SAMPLES = 10;

#define MAX_FRAME 16
//new
//int k;


// Same as:
// const int SCENE_MENU = 1;
// const int SCENE_START = 2;
enum {
	SCENE_MENU = 1,
	SCENE_START = 2,
	// [HACKATHON 3-7]
	// TODO: Declare a new scene id.
	SCENE_SETTINGS = 3,
	SCENE_GAMEOVER = 4
};

/* Input states */

// The active scene id.
int active_scene;
// Keyboard state, whether the key is down or not.
bool key_state[ALLEGRO_KEY_MAX];
// Mouse state, whether the key is down or not.
// 1 is for left, 2 is for right, 3 is for middle.
bool *mouse_state;
// Mouse position.
int mouse_x, mouse_y;
// TODO: More variables to store input states such as joysticks, ...

/* Variables for allegro basic routines. */

ALLEGRO_DISPLAY* game_display;
ALLEGRO_EVENT_QUEUE* game_event_queue;
ALLEGRO_TIMER* game_update_timer;

/* Shared resources*/

ALLEGRO_FONT* font_pirulen_32;
ALLEGRO_FONT* font_pirulen_24;
ALLEGRO_FONT* font_pirulen_18;
// TODO: More shared resources or data that needed to be accessed
// across different scenes.

/* Menu Scene resources*/
ALLEGRO_BITMAP* main_img_background;
// [HACKATHON 3-1]
// TODO: Declare 2 variables for storing settings images.
ALLEGRO_BITMAP* img_settings;
ALLEGRO_BITMAP* img_settings2;
ALLEGRO_SAMPLE* main_bgm;
ALLEGRO_SAMPLE_ID main_bgm_id;

/* Start Scene resources*/
ALLEGRO_BITMAP* start_img_background;
ALLEGRO_BITMAP* start_img_plane;
ALLEGRO_BITMAP* start_img_enemy;
ALLEGRO_SAMPLE* start_bgm;
ALLEGRO_SAMPLE_ID start_bgm_id;
// [HACKATHON 2-1]
// TODO: Declare a variable to store your bullet's image.
ALLEGRO_BITMAP* img_bullet; // = al_load_bitmap("image12.png");
ALLEGRO_SAMPLE* bullet_sound;
ALLEGRO_SAMPLE_ID bullet_sound_id;
//Enemy bullets
ALLEGRO_BITMAP* img_enemy_bullet;
ALLEGRO_BITMAP *explosion[MAX_FRAME];
ALLEGRO_SAMPLE* gameover_bgm;
ALLEGRO_SAMPLE_ID gameover_bgm_id;

typedef struct {
	// The center coordinate of the image.
	float x, y;
	// The width and height of the object.
	float w, h;
	// The velocity in x, y axes.
	float vx, vy;
	// Should we draw this object on the screen.
	bool hidden;
	// The pointer to the object’s image.
	ALLEGRO_BITMAP* img;
} MovableObject;
void draw_movable_object(MovableObject obj);
#define MAX_ENEMY 5
#define SMALL_ENEMY_HEALTH 3
#define MAX_LIVES 3
// [HACKATHON 2-2]
// TODO: Declare the max bullet count that will show on screen.
// You can try max 4 bullets here and see if you needed more.
#define MAX_BULLET 5
#define MAX_ENEMY_BULLET 50

MovableObject plane;
MovableObject enemies[MAX_ENEMY];
// [HACKATHON 2-3]
// TODO: Declare an array to store bullets with size of max bullet count.
MovableObject bullets[MAX_BULLET];
// [HACKATHON 2-4]
// TODO: Set up bullet shooting cool-down variables.
// 1) Declare your shooting cool-down time as constant. (0.2f will be nice)
// 2) Declare your last shoot timestamp.
const float MAX_COOLDOWN = 0.2f;
double last_shoot_timestamp;

MovableObject e_bullets[MAX_ENEMY_BULLET];
const float ENEMY_CD = 0.3f;
double e_last_shoot_timestamp = 0;

MovableObject boom[MAX_FRAME];


/* Declare function prototypes. */

// Initialize allegro5 library
void allegro5_init(void);
// Initialize variables and resources.
// Allows the game to perform any initialization it needs before
// starting to run.
void game_init(void);
// Process events inside the event queue using an infinity loop.
void game_start_event_loop(void);
// Run game logic such as updating the world, checking for collision,
// switching scenes and so on.
// This is called when the game should update its logic.
void game_update(void);
// Draw to display.
// This is called when the game should draw itself.
void game_draw(void);
// Release resources.
// Free the pointers we allocated.
void game_destroy(void);
// Function to change from one scene to another.
void game_change_scene(int next_scene);
// Load resized bitmap and check if failed.
ALLEGRO_BITMAP *load_bitmap_resized(const char *filename, int w, int h);
// [HACKATHON 3-2]
// TODO: Declare a function.
// Determines whether the point (px, py) is in rect (x, y, w, h).
bool pnt_in_rect(int px, int py, int x, int y, int w, int h);
//explode
void explode(int px, int py);

/* Event callbacks. */
void on_key_down(int keycode);
void on_mouse_down(int btn, int x, int y);

/* Declare function prototypes for debugging. */

// Display error message and exit the program, used like 'printf'.
// Write formatted output to stdout and file from the format string.
// If the program crashes unexpectedly, you can inspect "log.txt" for
// further information.
void game_abort(const char* format, ...);
// Log events for later debugging, used like 'printf'.
// Write formatted output to stdout and file from the format string.
// You can inspect "log.txt" for logs in the last run.
void game_log(const char* format, ...);
// Log using va_list.
void game_vlog(const char* format, va_list arg);

int main(int argc, char** argv) {
	// Set random seed for better random outcome.
	srand(time(NULL));
	allegro5_init();
	game_log("Allegro5 initialized");
	game_log("Game begin");
	// Initialize game variables.
	game_init();
	game_log("Game initialized");
	// Draw the first frame.
	game_draw();
	game_log("Game start event loop");
	// This call blocks until the game is finished.
	game_start_event_loop();
	game_log("Game end");
	game_destroy();
	return 0;
}

void allegro5_init(void) {
	if (!al_init())
		game_abort("failed to initialize allegro");

	// Initialize add-ons.
	if (!al_init_primitives_addon())
		game_abort("failed to initialize primitives add-on");
	if (!al_init_font_addon())
		game_abort("failed to initialize font add-on");
	if (!al_init_ttf_addon())
		game_abort("failed to initialize ttf add-on");
	if (!al_init_image_addon())
		game_abort("failed to initialize image add-on");
	if (!al_install_audio())
		game_abort("failed to initialize audio add-on");
	if (!al_init_acodec_addon())
		game_abort("failed to initialize audio codec add-on");
	if (!al_reserve_samples(RESERVE_SAMPLES))
		game_abort("failed to reserve samples");
	if (!al_install_keyboard())
		game_abort("failed to install keyboard");
	if (!al_install_mouse())
		game_abort("failed to install mouse");
	// TODO: Initialize other addons such as video, ...


	// Setup game display.
	game_display = al_create_display(SCREEN_W, SCREEN_H);
	if (!game_display)
		game_abort("failed to create display");
	al_set_window_title(game_display, "I2P(I)_2019 Final Project <107022216>");

	// Setup update timer.
	game_update_timer = al_create_timer(1.0f / FPS);
	if (!game_update_timer)
		game_abort("failed to create timer");

	// Setup event queue.
	game_event_queue = al_create_event_queue();
	if (!game_event_queue)
		game_abort("failed to create event queue");

	// Malloc mouse buttons state according to button counts.
	const unsigned m_buttons = al_get_mouse_num_buttons();
	game_log("There are total %u supported mouse buttons", m_buttons);
	// mouse_state[0] will not be used.
	mouse_state = malloc((m_buttons + 1) * sizeof(bool));
	memset(mouse_state, false, (m_buttons + 1) * sizeof(bool));

	// Register display, timer, keyboard, mouse events to the event queue.
	al_register_event_source(game_event_queue, al_get_display_event_source(game_display));
	al_register_event_source(game_event_queue, al_get_timer_event_source(game_update_timer));
	al_register_event_source(game_event_queue, al_get_keyboard_event_source());
	al_register_event_source(game_event_queue, al_get_mouse_event_source());
	// TODO: Register other event sources such as timer, video, ...

	// Start the timer to update and draw the game.
	al_start_timer(game_update_timer);
}

void game_init(void) {
	/* Shared resources*/
	font_pirulen_32 = al_load_font("pirulen.ttf", 32, 0);
	if (!font_pirulen_32)
		game_abort("failed to load font: pirulen.ttf with size 32");

	font_pirulen_24 = al_load_font("pirulen.ttf", 24, 0);
	if (!font_pirulen_24)
		game_abort("failed to load font: pirulen.ttf with size 24");

	font_pirulen_18 = al_load_font("pirulen.ttf", 18, 0);
	if (!font_pirulen_18)
		game_abort("failed to load font: pirulen.ttf with size 18");

	/* Menu Scene resources*/
	main_img_background = load_bitmap_resized("main-bg.jpg", SCREEN_W, SCREEN_H);

	main_bgm = al_load_sample("main bgm.ogg");
	if (!main_bgm)
		game_abort("failed to load audio: main bgm.ogg");

	gameover_bgm = al_load_sample("gameover bgm.ogg");
	if (!gameover_bgm)
		game_abort("failed to load audio: gameover bgm.ogg");
	// [HACKATHON 3-4]
	// TODO: Load settings images.
	// Don't forget to check their return values.
	img_settings = al_load_bitmap("settings.png");
	if (!img_settings)
		game_abort("failed to load image: settings.png");
	img_settings2 = al_load_bitmap("settings2.png");
	if (!img_settings2)
		game_abort("failed to load image: settings2.png");

	/* Start Scene resources*/
	start_img_background = load_bitmap_resized("start-bg.jpg", SCREEN_W, SCREEN_H);
	if (!start_img_background)
		game_abort("failed to load image: start-bg.jpg");

	start_img_plane = al_load_bitmap("plane.png");
	if (!start_img_plane)
		game_abort("failed to load image: plane.png");

	start_img_enemy = al_load_bitmap("smallfighter0006.png");
	if (!start_img_enemy)
		game_abort("failed to load image: smallfighter0006.png");

	start_bgm = al_load_sample("ingame bgm.ogg");
	if (!start_bgm)
		game_abort("failed to load audio: ingame bgm.ogg");

	// [HACKATHON 2-5]
	// TODO: Initialize bullets.
	// 1) Search for a bullet image online and put it in your project.
	//    You can use the image we provided.
	// 2) Load it in by 'al_load_bitmap' or 'load_bitmap_resized'.
	// 3) If you use 'al_load_bitmap', don't forget to check its return value.
	img_bullet = al_load_bitmap("bullet.png");
	if (!img_bullet)
		game_abort("failed to load image: bullet.png");
	//new
	bullet_sound = al_load_sample("bullet sound.ogg");
	if (!bullet_sound)
		game_abort("failed to load audio: bullet sound.ogg");

	img_enemy_bullet = al_load_bitmap("enemy_bullet.png");
	if (!img_enemy_bullet)
		game_abort("failed to load image: enemy_bullet.png");

	explosion[0] = al_load_bitmap("exp001.png");
	if (!explosion[0])
		game_abort("failed to load image: exp001.png");
	explosion[1] = al_load_bitmap("exp002.png");
	if (!explosion[1])
		game_abort("failed to load image: exp002.png");
	explosion[2] = al_load_bitmap("exp003.png");
	if (!explosion[2])
		game_abort("failed to load image: exp003.png");
	explosion[3] = al_load_bitmap("exp004.png");
	if (!explosion[3])
		game_abort("failed to load image: exp004.png");
	explosion[4] = al_load_bitmap("exp005.png");
	if (!explosion[4])
		game_abort("failed to load image: exp005.png");
	explosion[5] = al_load_bitmap("exp006.png");
	if (!explosion[5])
		game_abort("failed to load image: exp006.png");
	explosion[6] = al_load_bitmap("exp007.png");
	if (!explosion[6])
		game_abort("failed to load image: exp007.png");
	explosion[7] = al_load_bitmap("exp008.png");
	if (!explosion[7])
		game_abort("failed to load image: exp008.png");
	explosion[8] = al_load_bitmap("exp009.png");
	if (!explosion[8])
		game_abort("failed to load image: exp009.png");
	explosion[9] = al_load_bitmap("exp010.png");
	if (!explosion[9])
		game_abort("failed to load image: exp010.png");
	explosion[10] = al_load_bitmap("exp011.png");
	if (!explosion[10])
		game_abort("failed to load image: exp011.png");
	explosion[11] = al_load_bitmap("exp012.png");
	if (!explosion[11])
		game_abort("failed to load image: exp012.png");
	explosion[12] = al_load_bitmap("exp013.png");
	if (!explosion[12])
		game_abort("failed to load image: exp013.png");
	explosion[13] = al_load_bitmap("exp014.png");
	if (!explosion[13])
		game_abort("failed to load image: exp014.png");
	explosion[14] = al_load_bitmap("exp015.png");
	if (!explosion[14])
		game_abort("failed to load image: exp015.png");
	explosion[15] = al_load_bitmap("exp016.png");
	if (!explosion[15])
		game_abort("failed to load image: exp016.png");

	// Change to first scene.
	game_change_scene(SCENE_MENU);
}
int initial_rand;
void game_start_event_loop(void) {
	bool done = false;
	ALLEGRO_EVENT event;
	int redraws = 0;
	//new
	for (int i = 0; i < MAX_ENEMY; i++) {
		initial_rand = rand() % 8;
		//initial velocity
		if (initial_rand == 0) {
			enemies[i].vx = 0;
			enemies[i].vy = 1;
		}
		if (initial_rand == 1) {
			enemies[i].vx = 0;
			enemies[i].vy = -1;
		}
		if (initial_rand == 2) {
			enemies[i].vx = 1;
			enemies[i].vy = 0;
		}
		if (initial_rand == 3) {
			enemies[i].vx = -1;
			enemies[i].vy = 0;
		}
		if (initial_rand == 4) {
			enemies[i].vx = 1;
			enemies[i].vy = 1;
		}
		if (initial_rand == 5) {
			enemies[i].vx = 1;
			enemies[i].vy = -1;
		}
		if (initial_rand == 6) {
			enemies[i].vx = -1;
			enemies[i].vy = 1;
		}
		if (initial_rand == 7) {
			enemies[i].vx = -1;
			enemies[i].vy = -1;
		}
	}
	while (!done) {
		al_wait_for_event(game_event_queue, &event);
		if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
			// Event for clicking the window close button.
			game_log("Window close button clicked");
			done = true;
		}
		else if (event.type == ALLEGRO_EVENT_TIMER) {
			// Event for redrawing the display.
			if (event.timer.source == game_update_timer)
				// The redraw timer has ticked.
				redraws++;
		}
		else if (event.type == ALLEGRO_EVENT_KEY_DOWN) {
			// Event for keyboard key down.
			game_log("Key with keycode %d down", event.keyboard.keycode);
			key_state[event.keyboard.keycode] = true;
			on_key_down(event.keyboard.keycode);
		}
		else if (event.type == ALLEGRO_EVENT_KEY_UP) {
			// Event for keyboard key up.
			game_log("Key with keycode %d up", event.keyboard.keycode);
			key_state[event.keyboard.keycode] = false;
		}
		else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
			// Event for mouse key down.
			game_log("Mouse button %d down at (%d, %d)", event.mouse.button, event.mouse.x, event.mouse.y);
			mouse_state[event.mouse.button] = true;
			on_mouse_down(event.mouse.button, event.mouse.x, event.mouse.y);
		}
		else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) {
			// Event for mouse key up.
			game_log("Mouse button %d up at (%d, %d)", event.mouse.button, event.mouse.x, event.mouse.y);
			mouse_state[event.mouse.button] = false;
		}
		else if (event.type == ALLEGRO_EVENT_MOUSE_AXES) {
			if (event.mouse.dx != 0 || event.mouse.dy != 0) {
				// Event for mouse move.
				game_log("Mouse move to (%d, %d)", event.mouse.x, event.mouse.y);
				mouse_x = event.mouse.x;
				mouse_y = event.mouse.y;
			}
			else if (event.mouse.dz != 0) {
				// Event for mouse scroll.
				game_log("Mouse scroll at (%d, %d) with delta %d", event.mouse.x, event.mouse.y, event.mouse.dz);
			}
		}
		// TODO: Process more events and call callbacks by adding more
		// entries inside Scene.
		
		// Redraw
		if (redraws > 0 && al_is_event_queue_empty(game_event_queue)) {
			// if (redraws > 1)
			// 	game_log("%d frame(s) dropped", redraws - 1);
			// Update and draw the next frame.
			game_update();
			game_draw();
			redraws = 0;
		}
	}
}
//new
int sml_health[MAX_ENEMY] = { 0 };
int dead = 0;
int hit = 0;
int curFrame = 0;
int frameCount = 0;
int frameDelay = 3;
int i;


void game_update(void) {

	if (active_scene == SCENE_START) {
		plane.vx = plane.vy = 0;
		if (key_state[ALLEGRO_KEY_UP] || key_state[ALLEGRO_KEY_W])
			plane.vy -= 1;
		if (key_state[ALLEGRO_KEY_DOWN] || key_state[ALLEGRO_KEY_S])
			plane.vy += 1;
		if (key_state[ALLEGRO_KEY_LEFT] || key_state[ALLEGRO_KEY_A])
			plane.vx -= 1;
		if (key_state[ALLEGRO_KEY_RIGHT] || key_state[ALLEGRO_KEY_D])
			plane.vx += 1;
		// 0.71 is (1/sqrt(2)).
		plane.y += plane.vy * 4 * (plane.vx ? 0.71f : 1);
		plane.x += plane.vx * 4 * (plane.vy ? 0.71f : 1);
		// [HACKATHON 1-1]
		// TODO: Limit the plane's collision box inside the frame.
		//  (x, y axes can be separate.)
		if (plane.x - plane.w / 2 < 0)
			plane.x = plane.w / 2;
		else if (plane.x + plane.w / 2 > SCREEN_W)
			plane.x = SCREEN_W - plane.w / 2;
		if (plane.y - plane.h / 2 < 0)
			plane.y = plane.h / 2;
		else if (plane.y + plane.h / 2 > SCREEN_H)
			plane.y = SCREEN_H - plane.h / 2;
		// [HACKATHON 2-7]
		// TODO: Update bullet coordinates.
		// 1) For each bullets, if it's not hidden, update x, y
		// according to vx, vy.
		// 2) If the bullet is out of the screen, hide it.
		// Uncomment and fill in the code below.
		int i,j;
		for (i = 0; i < MAX_BULLET; i++) {
			if (bullets[i].y < 0)
				continue;
			bullets[i].x += 0;
			bullets[i].y -= 10;
			if (bullets[i].y < 0)
				bullets[i].hidden = true;
		}
		//new
		//Update enemies' bullet coordinates.
		for (i = 0; i < MAX_ENEMY_BULLET; i++)
		{
			if (e_bullets[i].hidden == true)
				continue;
			e_bullets[i].x += 0;
			e_bullets[i].y += e_bullets[i].vy;
			if (e_bullets[i].y > SCREEN_H - e_bullets[i].h / 2)
				e_bullets[i].hidden = true;
		}
		//enemies' movement
		
		for (i = 0; i < MAX_ENEMY; i++){
			int ran = rand() % 25;
			//change
			if (ran == 0) {
				if (rand() % 8 == 0) {
					enemies[i].vx = 0;
					enemies[i].vy = 1;
				}
				if (rand() % 8 == 1) {
					enemies[i].vx = 0;
					enemies[i].vy = -1;
				}
				if (rand() % 8 == 2) {
					enemies[i].vx = 1;
					enemies[i].vy = 0;
				}
				if (rand() % 8 == 3) {
					enemies[i].vx = -1;
					enemies[i].vy = 0;
				}
				if (rand() % 8 == 4) {
					enemies[i].vx = 1;
					enemies[i].vy = 1;
				}
				if (rand() % 8 == 5) {
					enemies[i].vx = 1;
					enemies[i].vy = -1;
				}
				if (rand() % 8 == 6) {
					enemies[i].vx = -1;
					enemies[i].vy = 1;
				}
				if (rand() % 8 == 7) {
					enemies[i].vx = -1;
					enemies[i].vy = -1;
				}
			}
			if (enemies[i].x < enemies[i].w / 2)
			{
				enemies[i].x = enemies[i].w / 2;
				enemies[i].vx = 1;
			}
			else if (enemies[i].x > SCREEN_W - enemies[i].w / 2)
			{
				enemies[i].x = SCREEN_W - enemies[i].w / 2;
				enemies[i].vx = -1;
			}
			if (enemies[i].y < enemies[i].h / 2) {
				enemies[i].y = enemies[i].h / 2;
				enemies[i].vy = 1;
			}
			else if (enemies[i].y > SCREEN_H - enemies[i].h / 2) {
				enemies[i].y = SCREEN_H - enemies[i].h / 2;
				enemies[i].vy = -1;
			}
			enemies[i].x += enemies[i].vx;
			enemies[i].y += enemies[i].vy;
		}
		// [HACKATHON 2-8]
		// TODO: Shoot if key is down and cool-down is over.
		// 1) Get the time now using 'al_get_time'.
		// 2) If Space key is down in 'key_state' and the time
		//    between now and last shoot is not less that cool
		//    down time.
		// 3) Loop through the bullet array and find one that is hidden.
		//    (This part can be optimized.)
		// 4) The bullet will be found if your array is large enough.
		// 5) Set the last shoot time to now.
		// 6) Set hidden to false (recycle the bullet) and set its x, y to the
		//    front part of your plane.
		double now = al_get_time();
		if (key_state[ALLEGRO_KEY_SPACE] && now - last_shoot_timestamp >= MAX_COOLDOWN) {
			for (i = 0; i < MAX_BULLET;i++) {
		        if (bullets[i].hidden == true)
		            break;
		    }
			if (i < MAX_BULLET) {
				last_shoot_timestamp = now;
				bullets[i].hidden = false;
				bullets[i].x = plane.x;
				bullets[i].y = plane.y;
				al_play_sample(bullet_sound, 1, 0, 1, ALLEGRO_PLAYMODE_ONCE, &bullet_sound_id);
		    }
		}
		//new
		//enemy shots
		int ran2 = rand() % 3;
		if (now - e_last_shoot_timestamp >= ENEMY_CD)
		{
			for (i = 0; i < MAX_ENEMY_BULLET; i++)
			{
				if (e_bullets[i].hidden)
					break;
			}
			if (i < MAX_ENEMY_BULLET)
			{
				e_last_shoot_timestamp = now;
				e_bullets[i].hidden = false;
				for (j = 0; j < MAX_ENEMY; j++)
				{
					if (!enemies[j].hidden)
					{
						if (j == ran2)
						{
							e_bullets[i].x = enemies[j].x;
							e_bullets[i].y = enemies[j].y + enemies[j].h / 2;
							al_play_sample(bullet_sound, 1, 0, 1, ALLEGRO_PLAYMODE_ONCE, &bullet_sound_id);
						}
					}
				}
			}
		}

		//hits		
		if (!plane.hidden)
		{
			for (i = 0; i < MAX_ENEMY; i++)
			{
				if (sml_health[i] == SMALL_ENEMY_HEALTH)
				{
					enemies[i].hidden = true;
					enemies[i].x = enemies[i].w / 2;
					enemies[i].y = SCREEN_H - enemies[i].h / 2;
					dead += 1;
					game_log("kill count: %d", dead);
					sml_health[i] += 1;
					for (j = 0; j < MAX_ENEMY_BULLET; j++)
					{
						e_bullets[j].vy += 0.4;
					}
				}
				for (j = 0; j < MAX_BULLET; j++)
				{
					if (pnt_in_rect(bullets[j].x, bullets[j].y - bullets[j].h / 2, enemies[i].x - enemies[i].w / 2, enemies[i].y - enemies[i].h / 2, enemies[i].w, enemies[i].h))
					{
						explode(bullets[j].x, bullets[j].y + bullets[j].h / 2);
						bullets[j].hidden = true;
						bullets[j].x = plane.x;
						bullets[j].y = SCREEN_H - bullets[j].h / 2;
						sml_health[i] += 1;
						game_log("hit enemy %d, total life loss %d", i, sml_health[i]);

						//curFrame = 0;
						//boom[curFrame].hidden = false;
						//boom[curFrame].x = enemies[i].x;
						//boom[curFrame].y = enemies[i].y;
						//boom[curFrame].hidden = true;



					}
				}
			}
			//hit by enemy bullet.
			for (i = 0; i < MAX_ENEMY_BULLET; i++)
			{
				if (pnt_in_rect(e_bullets[i].x, e_bullets[i].y + e_bullets[i].h / 2, plane.x - plane.w / 2, plane.y - plane.h / 2, plane.w, plane.h))
				{

					e_bullets[i].hidden = true;
					e_bullets[i].x = SCREEN_W - e_bullets[i].w / 2;
					e_bullets[i].y = SCREEN_H - e_bullets[i].h / 2;
					hit += 1;
					game_log("you got hit");

				}
			}
		}
		//no enemies
		if (dead > 0 && dead % MAX_ENEMY == 0)
		{
			for (i = 0; i < MAX_ENEMY; i++)
			{
				if (enemies[i].hidden)
				{
					enemies[i].hidden = false;
					enemies[i].x = enemies[i].w / 2 + (float)rand() / RAND_MAX * (SCREEN_W - enemies[i].w);
					enemies[i].y = -enemies[i].h/2;
					sml_health[i] = 0;
				}
			}
		}

		//gameover scene
		if (hit == MAX_LIVES)
		{
			game_change_scene(SCENE_GAMEOVER);
			for (i = 0; i < MAX_ENEMY; i++)
			{
				enemies[i].hidden = false;
			}
		}
	}
}

void game_draw(void) {
	if (active_scene == SCENE_MENU) {
		al_draw_bitmap(main_img_background, 0, 0, 0);
		al_draw_text(font_pirulen_32, al_map_rgb(255, 255, 255), SCREEN_W / 2, 30, ALLEGRO_ALIGN_CENTER, "Space Shooter");
		al_draw_text(font_pirulen_24, al_map_rgb(255, 255, 255), 20, SCREEN_H - 50, 0, "Press enter key to start");
		// [HACKATHON 3-5]
		// TODO: Draw settings images.
		// The settings icon should be located at (x, y, w, h) =
		// (SCREEN_W - 48, 10, 38, 38).
		// Change its image according to your mouse position.
		if (pnt_in_rect(mouse_x, mouse_y, SCREEN_W - 48, 10, 38, 38))
			al_draw_bitmap(img_settings2, SCREEN_W - 48, 10, 0);
		else
			al_draw_bitmap(img_settings, SCREEN_W - 48, 10, 0);
	}
	else if (active_scene == SCENE_START) {
		int i;
		al_draw_bitmap(start_img_background, 0, 0, 0);
		// [HACKATHON 2-9]
		// TODO: Draw all bullets in your bullet array.
		for (i = 0; i < MAX_BULLET; i++)
			draw_movable_object(bullets[i]);
		draw_movable_object(plane);
		for (i = 0; i < MAX_ENEMY; i++)
			draw_movable_object(enemies[i]);
		//new
		//draw enemies' bullet
		for (i = 0; i < MAX_ENEMY_BULLET; i++)
			draw_movable_object(e_bullets[i]);
		//draw kill count	
		al_draw_textf(font_pirulen_18, al_map_rgb(255, 255, 255), SCREEN_W - 220, SCREEN_H - 50, 0, "Kill count: %d", dead);
		al_draw_textf(font_pirulen_18, al_map_rgb(255, 255, 255), 20, SCREEN_H - 50, 0, "Lives: %d", MAX_LIVES-hit);
		//draw explosion
		for (i = 0; i < MAX_FRAME; i++)
			draw_movable_object(boom[i]);
	}
	// [HACKATHON 3-9]
	// TODO: If active_scene is SCENE_SETTINGS.
	// Draw anything you want, or simply clear the display.
	else if (active_scene == SCENE_SETTINGS) {
		al_clear_to_color(al_map_rgb(200, 200, 230));
		al_draw_text(font_pirulen_32, al_map_rgb(0, 0, 0), SCREEN_W / 2, SCREEN_H / 2, ALLEGRO_ALIGN_CENTER, "CLICK TO EXIT SETTING");
	}
	//new
	// Draw game over scene.
	else if (active_scene == SCENE_GAMEOVER){
		al_clear_to_color(al_map_rgb(255, 255, 255));
		al_draw_text(font_pirulen_32, al_map_rgb(0, 0, 0), SCREEN_W / 2, SCREEN_H / 2 - 100, ALLEGRO_ALIGN_CENTER, "GAME OVER");
		al_draw_textf(font_pirulen_18, al_map_rgb(0, 0, 0), SCREEN_W / 2, SCREEN_H / 2 - 50, ALLEGRO_ALIGN_CENTER, "total kill: %d, good job!", dead);
		al_draw_text(font_pirulen_24, al_map_rgb(0, 0, 0), SCREEN_W / 2, SCREEN_H - 50, ALLEGRO_ALIGN_CENTER, "PRESS ENTER KEY TO MENU");
	}
	al_flip_display();
}

void game_destroy(void) {
	// Destroy everything you have created.
	// Free the memories allocated by malloc or allegro functions.
	// Destroy shared resources.
	al_destroy_font(font_pirulen_32);
	al_destroy_font(font_pirulen_24);
	al_destroy_font(font_pirulen_18);

	/* Menu Scene resources*/
	al_destroy_bitmap(main_img_background);
	al_destroy_sample(main_bgm);
	// [HACKATHON 3-6]
	// TODO: Destroy the 2 settings images.
	al_destroy_bitmap(img_settings);
	al_destroy_bitmap(img_settings2);

	/* Start Scene resources*/
	al_destroy_bitmap(start_img_background);
	al_destroy_bitmap(start_img_plane);
	al_destroy_bitmap(start_img_enemy);
	al_destroy_sample(start_bgm);
	// [HACKATHON 2-10]
	// TODO: Destroy your bullet image.
	al_destroy_bitmap(img_bullet);
	al_destroy_sample(bullet_sound);
	al_destroy_bitmap(img_enemy_bullet);
	al_destroy_timer(game_update_timer);
	al_destroy_event_queue(game_event_queue);
	al_destroy_display(game_display);
	al_destroy_sample(gameover_bgm);

	for (int i = 0; i < MAX_FRAME; i++)
	{
		al_destroy_bitmap(explosion[i]);
	}

	free(mouse_state);
}

void game_change_scene(int next_scene) {
	game_log("Change scene from %d to %d", active_scene, next_scene);
	// TODO: Destroy resources initialized when creating scene.
	if (active_scene == SCENE_MENU) {
		al_stop_sample(&main_bgm_id);
		game_log("stop audio (bgm)");
	}
	else if (active_scene == SCENE_START) {
		al_stop_sample(&start_bgm_id);
		game_log("stop audio (bgm)");
	}
	else if (active_scene == SCENE_GAMEOVER) {
		al_stop_sample(&gameover_bgm_id);
		game_log("stop audio (bgm)");
	}
	active_scene = next_scene;
	// TODO: Allocate resources before entering scene.
	if (active_scene == SCENE_MENU) {
		if (!al_play_sample(main_bgm, 1, 0.0, 1.0, ALLEGRO_PLAYMODE_LOOP, &main_bgm_id))
			game_abort("failed to play audio (bgm)");
	}
	else if (active_scene == SCENE_START) {
		int i;
		plane.img = start_img_plane;
		plane.x = 400;
		plane.y = 500;
		plane.w = al_get_bitmap_width(plane.img);
		plane.h = al_get_bitmap_height(plane.img);
		for (i = 0; i < MAX_ENEMY; i++) {
			enemies[i].img = start_img_enemy;
			enemies[i].w = al_get_bitmap_width(start_img_enemy);
			enemies[i].h = al_get_bitmap_height(start_img_enemy);
			enemies[i].x = enemies[i].w / 2 + (float)rand() / RAND_MAX * (SCREEN_W - enemies[i].w);
			enemies[i].y = 80;
		}
		// [HACKATHON 2-6]
		// TODO: Initialize bullets.
		// For each bullets in array, set their w and h to the size of
		// the image, and set their img to bullet image, hidden to true,
		// (vx, vy) to (0, -3).
		for (i = 0; i < MAX_BULLET; i++) {
			bullets[i].w = al_get_bitmap_width(img_bullet);
			bullets[i].h = al_get_bitmap_height(img_bullet);
			bullets[i].img = img_bullet;
			bullets[i].vx = 0;
			bullets[i].vy = -3;
			bullets[i].hidden = true;
		}
		if (!al_play_sample(start_bgm, 1, 0.0, 1.0, ALLEGRO_PLAYMODE_LOOP, &start_bgm_id))
			game_abort("failed to play audio (bgm)");
		//new
		//Initialize enemy bullets.
		for (i = 0; i < MAX_ENEMY_BULLET; i++)
		{
			e_bullets[i].w = al_get_bitmap_width(img_enemy_bullet);
			e_bullets[i].h = al_get_bitmap_height(img_enemy_bullet);
			e_bullets[i].img = img_enemy_bullet;
			e_bullets[i].vx = 0;
			e_bullets[i].vy = 6;
			e_bullets[i].hidden = true;
		}

		//Initialize boom.
		for (i = 0; i < MAX_FRAME; i++)
		{
			boom[i].w = al_get_bitmap_width(explosion[i]);
			boom[i].h = al_get_bitmap_height(explosion[i]);
			boom[i].img = explosion[i];
			boom[i].hidden = true;
		}
	}
	else if (active_scene == SCENE_GAMEOVER) {
		if (!al_play_sample(gameover_bgm, 1, 0.0, 1.0, ALLEGRO_PLAYMODE_LOOP, &gameover_bgm_id))
			game_abort("failed to play audio (bgm)");
	}
}

void on_key_down(int keycode) {
	if (active_scene == SCENE_MENU) {
		if (keycode == ALLEGRO_KEY_ENTER)
			game_change_scene(SCENE_START);
	}
	if (active_scene == SCENE_GAMEOVER) {
		if (keycode == ALLEGRO_KEY_ENTER)
		{
			game_change_scene(SCENE_MENU);
			dead = 0;
			hit = 0;
			int i;
			for (i = 0; i < MAX_ENEMY; i++)
			{
				sml_health[i] = 0;
			}
		}
	}
}

void on_mouse_down(int btn, int x, int y) {
	// [HACKATHON 3-8]
	// TODO: When settings clicked, switch to settings scene.
	if (active_scene == SCENE_MENU) {
		if (btn == 1) {
			if (pnt_in_rect(x, y, SCREEN_W - 48, 10, 38, 38))
				game_change_scene(SCENE_SETTINGS);
		}
	}
	if (active_scene == SCENE_SETTINGS) {
		if (btn == 1) {
			if (pnt_in_rect(x, y, SCREEN_W/2 - 350, SCREEN_H/2-25, 700, 50))
				game_change_scene(SCENE_MENU);
		}
	}
}

void draw_movable_object(MovableObject obj) {
	if (obj.hidden)
		return;
	al_draw_bitmap(obj.img, round(obj.x - obj.w / 2), round(obj.y - obj.h / 2), 0);
}

ALLEGRO_BITMAP *load_bitmap_resized(const char *filename, int w, int h) {
	ALLEGRO_BITMAP* loaded_bmp = al_load_bitmap(filename);
	if (!loaded_bmp)
		game_abort("failed to load image: %s", filename);
	ALLEGRO_BITMAP *resized_bmp = al_create_bitmap(w, h);
	ALLEGRO_BITMAP *prev_target = al_get_target_bitmap();

	if (!resized_bmp)
		game_abort("failed to create bitmap when creating resized image: %s", filename);
	al_set_target_bitmap(resized_bmp);
	al_draw_scaled_bitmap(loaded_bmp, 0, 0,
		al_get_bitmap_width(loaded_bmp),
		al_get_bitmap_height(loaded_bmp),
		0, 0, w, h, 0);
	al_set_target_bitmap(prev_target);
	al_destroy_bitmap(loaded_bmp);

	game_log("resized image: %s", filename);

	return resized_bmp;
}

// [HACKATHON 3-3] SCREEN_W - 48, 10, 38, 38
// TODO: Define bool pnt_in_rect(int px, int py, int x, int y, int w, int h)
bool pnt_in_rect(int px, int py, int x, int y, int w, int h) {
	if (px > x && py > y && px < x + w && py < y + h)
		return true;
	else
		return false;
}

void explode(int px, int py)
{
	while (curFrame < MAX_FRAME && frameCount < frameDelay)
	{
		frameCount++;
		/*if (frameCount >= frameDelay)
		{
			boom[curFrame].hidden = false;
			boom[curFrame].x = px;
			boom[curFrame].y = py;
			curFrame++;
		}*/
		boom[curFrame].hidden = true;
	}
	frameCount = 0;
}


// +=================================================================+
// | Code below is for debugging purpose, it's fine to remove it.    |
// | Deleting the code below and removing all calls to the functions |
// | doesn't affect the game.                                        |
// +=================================================================+

void game_abort(const char* format, ...) {
	va_list arg;
	va_start(arg, format);
	game_vlog(format, arg);
	va_end(arg);
	fprintf(stderr, "error occured, exiting after 2 secs");
	// Wait 2 secs before exiting.
	al_rest(2);
	// Force exit program.
	exit(1);
}

void game_log(const char* format, ...) {
#ifdef LOG_ENABLED
	va_list arg;
	va_start(arg, format);
	game_vlog(format, arg);
	va_end(arg);
#endif
}

void game_vlog(const char* format, va_list arg) {
#ifdef LOG_ENABLED
	static bool clear_file = true;
	vprintf(format, arg);
	printf("\n");
	// Write log to file for later debugging.
	FILE* pFile = fopen("log.txt", clear_file ? "w" : "a");
	if (pFile) {
		vfprintf(pFile, format, arg);
		fprintf(pFile, "\n");
		fclose(pFile);
	}
	clear_file = false;
#endif
}
close fullscreen
Login or Register to edit or fork this paste. It's free.