diff --git a/Assignment3Project/Assignment3Project/Assignment3Project.vcxproj b/Assignment3Project/Assignment3Project/Assignment3Project.vcxproj index cf9b104..070cef7 100644 --- a/Assignment3Project/Assignment3Project/Assignment3Project.vcxproj +++ b/Assignment3Project/Assignment3Project/Assignment3Project.vcxproj @@ -146,9 +146,12 @@ + + + @@ -156,9 +159,12 @@ + + + diff --git a/Assignment3Project/Assignment3Project/Assignment3Project.vcxproj.filters b/Assignment3Project/Assignment3Project/Assignment3Project.vcxproj.filters index cac8692..573489a 100644 --- a/Assignment3Project/Assignment3Project/Assignment3Project.vcxproj.filters +++ b/Assignment3Project/Assignment3Project/Assignment3Project.vcxproj.filters @@ -63,6 +63,15 @@ Header Files\Engine + + Header Files\Screens + + + Header Files\Assignment3 + + + Header Files\Screens + @@ -89,6 +98,15 @@ Source Files\EngineImplement + + Source Files\ScreensImplement + + + Source Files + + + Source Files\ScreensImplement + diff --git a/Assignment3Project/Assignment3Project/death.wav b/Assignment3Project/Assignment3Project/death.wav new file mode 100644 index 0000000..a3bc1d2 Binary files /dev/null and b/Assignment3Project/Assignment3Project/death.wav differ diff --git a/Assignment3Project/Assignment3Project/enemies.txt b/Assignment3Project/Assignment3Project/enemies.txt index 151b182..b0a658d 100644 --- a/Assignment3Project/Assignment3Project/enemies.txt +++ b/Assignment3Project/Assignment3Project/enemies.txt @@ -1 +1,3 @@ -e,10,240 \ No newline at end of file +e,10,200 +e,20,10 +e,22,50 \ No newline at end of file diff --git a/Assignment3Project/Assignment3Project/enums.h b/Assignment3Project/Assignment3Project/enums.h index f960635..9523b53 100644 --- a/Assignment3Project/Assignment3Project/enums.h +++ b/Assignment3Project/Assignment3Project/enums.h @@ -10,7 +10,8 @@ enum State { Start, Gameplay, - End, + Win, + Lose, Exit }; @@ -30,6 +31,12 @@ enum Behavior { Enemy }; +enum BgLayer { + Front, + Middle, + Back +}; + struct Hitbox { int x; int y; diff --git a/Assignment3Project/Assignment3Project/fire.wav b/Assignment3Project/Assignment3Project/fire.wav new file mode 100644 index 0000000..bedb759 Binary files /dev/null and b/Assignment3Project/Assignment3Project/fire.wav differ diff --git a/Assignment3Project/Assignment3Project/game.cpp b/Assignment3Project/Assignment3Project/game.cpp index 930986f..587e08d 100644 --- a/Assignment3Project/Assignment3Project/game.cpp +++ b/Assignment3Project/Assignment3Project/game.cpp @@ -11,6 +11,7 @@ Game::Game() { void Game::init() { score = 0; state = Start; + sprites.insert(pair("Title", al_load_bitmap("spaceforce.bmp"))); sprites.insert(pair("Ship", al_load_bitmap("placeholder.bmp"))); sprites.insert(pair("Enemy", al_load_bitmap("enemy.bmp"))); sprites.insert(pair("MusicOn", al_load_bitmap("music_on.bmp"))); @@ -18,6 +19,10 @@ void Game::init() { al_reserve_samples(4); samples.insert(pair("Theme", al_load_sample("cheesetheme.wav"))); + samples.insert(pair("Fire", al_load_sample("fire.wav"))); + samples.insert(pair("Hit", al_load_sample("hit.wav"))); + samples.insert(pair("Die", al_load_sample("death.wav"))); + samples.insert(pair("Win", al_load_sample("victory.wav"))); font = al_create_builtin_font(); } @@ -31,6 +36,7 @@ void Game::run() { //Load screens StartScreen start_screen(sprites); GameScreen game_screen(sprites, samples); + ResultScreen result_screen; while (state != Exit) { switch (state) { @@ -44,7 +50,15 @@ void Game::run() { game_screen.run(font); state = game_screen.next_state; break; + case Win: + case Lose: + result_screen.win = (state == Win) ? true : false; + result_screen.score = game_screen.score; + result_screen.run(font); + state = result_screen.next_state; + break; } + } //Garbage collection @@ -56,4 +70,5 @@ void Game::run() { for (it2 = samples.begin(); it2 != samples.end(); it2++) { al_destroy_sample(it2->second); } + al_destroy_font(font); } \ No newline at end of file diff --git a/Assignment3Project/Assignment3Project/game.h b/Assignment3Project/Assignment3Project/game.h index 9d91c12..748ea7b 100644 --- a/Assignment3Project/Assignment3Project/game.h +++ b/Assignment3Project/Assignment3Project/game.h @@ -13,6 +13,7 @@ #include "enums.h" #include "start_screen.h" #include "game_screen.h" +#include "result_screen.h" //Game state machine, contains data global to game class Game { diff --git a/Assignment3Project/Assignment3Project/game_element.h b/Assignment3Project/Assignment3Project/game_element.h index d7baa01..636fa58 100644 --- a/Assignment3Project/Assignment3Project/game_element.h +++ b/Assignment3Project/Assignment3Project/game_element.h @@ -7,7 +7,8 @@ class GameElement { public: float x_pos; float y_pos; - float h_bound; + float h_t_bound; + float h_b_bound; float l_bound; float r_bound; float speed; diff --git a/Assignment3Project/Assignment3Project/game_screen.cpp b/Assignment3Project/Assignment3Project/game_screen.cpp index 301e310..7008edb 100644 --- a/Assignment3Project/Assignment3Project/game_screen.cpp +++ b/Assignment3Project/Assignment3Project/game_screen.cpp @@ -13,6 +13,7 @@ //#include "mappy_A5.h" #include "game_screen.h" +#include "help_screen.h" #define FPS 60 @@ -23,11 +24,16 @@ using std::istringstream; using std::ifstream; using std::map; using std::pair; +using std::rand; enum KEYS { KEYUP, KEYDOWN, KEYLEFT, KEYRIGHT, KEYSPACE, KEYCTRL, KEYH, KEYM, KEYESC }; +enum ACTIONS { + FIRE, MUSIC, HELP +}; + GameScreen::GameScreen(std::map _sprites, std::map _samples) { sprites = _sprites; samples = _samples; @@ -36,9 +42,14 @@ GameScreen::GameScreen(std::map _sprites, std::map //Resets game to default values, and uses new given values void GameScreen::reset() { - objects.player = new Ship(Player); - objects.player->set_sprite(sprites["Ship"]); - objects.player->reset_pos(SCREEN_W / 2, SCREEN_H / 8); + music = true; + win = false; + score = 0; + + Ship player; + player.set_props(sprites["Ship"], Player); + player.reset_pos(SCREEN_W / 2, SCREEN_H / 1.2); + objects.init_player(player); max_bullets = 3; } @@ -75,7 +86,7 @@ void GameScreen::build_enemy_queue() { } enemies_file.close(); -} +} void GameScreen::run(ALLEGRO_FONT* font) { ALLEGRO_EVENT_QUEUE* event_queue = NULL; @@ -91,13 +102,22 @@ void GameScreen::run(ALLEGRO_FONT* font) { NewEnemy next_enemy = enemy_q.back(); enemy_q.pop_back(); - map inputs; - inputs.insert(pair("Fire", InputDelay())); - inputs.insert(pair("Music", InputDelay())); - inputs.insert(pair("Help", InputDelay())); - + InputDelay inputs[3]; + inputs[FIRE].input_hit = false; + inputs[FIRE].delay_sec = 0; + inputs[FIRE].max_delay = 15; + + inputs[MUSIC].input_hit = false; + inputs[MUSIC].delay_sec = 0; + inputs[MUSIC].max_delay = 80; + + inputs[HELP].input_hit = false; + inputs[HELP].delay_sec = 0; + inputs[HELP].max_delay = 80; - map_y = TILE_SIZE * LEVEL_LEN; + int max_map = TILE_SIZE * LEVEL_LEN; + map_y = max_map; + objects.set_background(); redraw(font); al_flip_display(); @@ -105,6 +125,18 @@ void GameScreen::run(ALLEGRO_FONT* font) { bool keys[ALLEGRO_KEY_MAX]; for (int i = 0; i < ALLEGRO_KEY_MAX; i++) keys[i] = false; + map instances; + map::iterator it; + for (it = samples.begin(); it != samples.end(); it++) { + instances.insert(pair(it->first, al_create_sample_instance(it->second))); + al_attach_sample_instance_to_mixer(instances[it->first], al_get_default_mixer()); + } + al_set_sample_instance_playmode(instances["Theme"], ALLEGRO_PLAYMODE_LOOP); + float music_vol = 0.5; + al_set_sample_instance_gain(instances["Theme"], music_vol); + play(instances["Theme"]); + al_set_sample_instance_gain(instances["Hit"], 2.2); + al_start_timer(timer); bool exit_screen = false; while (!exit_screen) { @@ -112,71 +144,91 @@ void GameScreen::run(ALLEGRO_FONT* font) { al_wait_for_event(event_queue, &ev); if (ev.type == ALLEGRO_EVENT_TIMER) { //Check per frame //Music toggle - if (keys[KEYCTRL] && keys[KEYM]) { - music = !music; + if (!inputs[MUSIC].input_hit) { + if (keys[KEYCTRL] && keys[KEYM]) { + if (music) { + al_set_sample_instance_gain(instances["Theme"], 0.0); + } + else { + al_set_sample_instance_gain(instances["Theme"], music_vol); + } + music = !music; + inputs[MUSIC].input_hit = true; + } } //Ship Movement if (keys[KEYUP]) { if (keys[KEYRIGHT]) { - objects.player->move(UR); + objects.player.move(UR); } else if (keys[KEYLEFT]) { - objects.player->move(UL); + objects.player.move(UL); } else { - objects.player->move(U); + objects.player.move(U); } } else if (keys[KEYDOWN]) { if (keys[KEYRIGHT]) { - objects.player->move(DR); + objects.player.move(DR); } else if (keys[KEYLEFT]) { - objects.player->move(DL); + objects.player.move(DL); } else { - objects.player->move(D); + objects.player.move(D); } } else if (keys[KEYLEFT]) { - objects.player->move(L); + objects.player.move(L); } else if (keys[KEYRIGHT]) { - objects.player->move(R); + objects.player.move(R); } //Firing - if (keys[KEYSPACE]) { - if (objects.player_bullets.size() < max_bullets) { - if (!objects.player->fired) { - objects.player_bullets.push_back(&objects.player->fire()); - } - objects.player->fired = true; + if (!inputs[FIRE].input_hit) { + if (keys[KEYSPACE] && objects.player_bullets.size() < max_bullets) { + objects.player_bullets.push_back(objects.player.fire()); + inputs[FIRE].input_hit = true; + play(instances["Fire"]); } } - if (objects.player->fired) { - if (fired_counter >= 20) { - objects.player->fired = false; - fired_counter = 0; - } - else { - fired_counter++; + + //Help menu + if (!inputs[HELP].input_hit) { + if (keys[KEYCTRL] && keys[KEYH]) { + HelpScreen help_screen; + al_clear_to_color(al_map_rgb(0, 0, 0)); + help_screen.run(font); + al_clear_to_color(al_map_rgb(0, 0, 0)); + keys[KEYCTRL] = false; + keys[KEYH] = false; } } + //Move map (HAHAHA THE MAP DIDN'T WORK AND I GAVE UP this is just a glorified timer now) if (map_y > 0) { - map_y -= 10; + map_y -= 2; } - else { + else if(objects.enemies.size() == 0) { + win = true; exit_screen = true; + al_stop_sample_instance(instances["Theme"]); + al_set_sample_instance_gain(instances["Win"], music_vol); + al_play_sample_instance(instances["Win"]); } - if (more_enemies && map_y >= next_enemy.when) { - Ship* new_e = new Ship(next_enemy.e_type); - new_e->set_sprite(sprites["Enemy"]); - new_e->reset_pos(next_enemy.x, 0 - new_e->height + 1); + /* This may be used in the next assignment, this functionality is for scripting enemy appearance + //Check if the next enemy is due + if (more_enemies && (max_map - map_y) >= next_enemy.when) { + //If he is, generate the new ship for the enemy and set the next enemy up + Ship new_e; + new_e.set_props(sprites["Enemy"], next_enemy.e_type); + new_e.reset_pos(next_enemy.x + SCREEN_L_B, 0 - new_e.height + 1); objects.enemies.push_back(new_e); + //Only queue up a new enemy if there is one, if there isn't then set the flag for no more enemies if (enemy_q.size() > 0) { next_enemy = enemy_q.back(); enemy_q.pop_back(); @@ -184,13 +236,35 @@ void GameScreen::run(ALLEGRO_FONT* font) { else { more_enemies = false; } + }*/ + + //Random enemy generation + if (map_y > 20) { //Should only generate if not right near the end + int enemy_chance = rand() % 80; //1 in 20 chance to generate an enemy + if (enemy_chance == 4) { + Ship new_e; + new_e.set_props(sprites["Enemy"], Enemy); + new_e.reset_pos(rand() % ((SCREEN_R_B - (int)new_e.width) - SCREEN_L_B + 1) + SCREEN_L_B, 0 - new_e.height + 1); + objects.enemies.push_back(new_e); + } + } + + if (keys[KEYESC]) { + exit_screen = true; + next_state = Exit; } //Global refresh if (objects.chk_player_col()) { exit_screen = true; + al_stop_sample_instance(instances["Theme"]); + play(instances["Die"]); + } + int points = objects.chk_bullet_col(); + if (points > 0) { + score += points; + play(instances["Hit"]); } - //score += objects.chk_bullet_col(); objects.move_enemies(); al_clear_to_color(al_map_rgb(0, 0, 0)); redraw(font); @@ -252,12 +326,15 @@ void GameScreen::run(ALLEGRO_FONT* font) { break; case ALLEGRO_KEY_SPACE: keys[KEYSPACE] = false; + inputs[FIRE].input_hit = false; break; case ALLEGRO_KEY_M: keys[KEYM] = false; + inputs[MUSIC].input_hit = false; break; case ALLEGRO_KEY_H: keys[KEYH] = false; + inputs[HELP].input_hit = false; break; case ALLEGRO_KEY_ESCAPE: keys[KEYESC] = false; @@ -273,8 +350,8 @@ void GameScreen::run(ALLEGRO_FONT* font) { cont(); } + al_clear_to_color(al_map_rgb(0, 0, 0)); //Garbage collection - //MapFreeMem(); objects.destroy_objects(); al_destroy_event_queue(event_queue); al_destroy_timer(timer); @@ -286,12 +363,19 @@ void GameScreen::redraw(ALLEGRO_FONT* font) { objects.draw_objects(); + //Borders + al_draw_filled_rectangle(SCREEN_L_B - 1, 0, SCREEN_L_B, SCREEN_H, al_map_rgb(255,255,255)); + al_draw_filled_rectangle(SCREEN_R_B, 0, SCREEN_R_B + 1, SCREEN_H, al_map_rgb(255,255,255)); + + //Score ostringstream score_msg; - score_msg << "Score: " << score; - al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_R_B + 2, 0, ALLEGRO_ALIGN_LEFT, score_msg.str().c_str()); + score_msg << "" << score; + al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_R_B + 2, 0, ALLEGRO_ALIGN_LEFT, "Score: "); + al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_R_B + 2, 10, ALLEGRO_ALIGN_LEFT, score_msg.str().c_str()); + //Music string music_img = (music) ? "MusicOn" : "MusicOff"; - al_draw_bitmap(sprites[music_img], SCREEN_R_B + 10, 90, NULL); + al_draw_bitmap(sprites[music_img], SCREEN_R_B + 10, 40, NULL); } void GameScreen::back() { @@ -299,5 +383,5 @@ void GameScreen::back() { } void GameScreen::cont() { - next_state = Start; + next_state = (win) ? Win : Lose; } \ No newline at end of file diff --git a/Assignment3Project/Assignment3Project/game_screen.h b/Assignment3Project/Assignment3Project/game_screen.h index efc6522..65f7d68 100644 --- a/Assignment3Project/Assignment3Project/game_screen.h +++ b/Assignment3Project/Assignment3Project/game_screen.h @@ -16,6 +16,7 @@ public: int score; int level; bool music; + bool win; int map_y; @@ -33,5 +34,4 @@ public: private: void play(ALLEGRO_SAMPLE_INSTANCE* x); void build_enemy_queue(); - void set_delays(std::map inputs); }; \ No newline at end of file diff --git a/Assignment3Project/Assignment3Project/help_screen.cpp b/Assignment3Project/Assignment3Project/help_screen.cpp new file mode 100644 index 0000000..de47d84 --- /dev/null +++ b/Assignment3Project/Assignment3Project/help_screen.cpp @@ -0,0 +1,69 @@ +#include "help_screen.h" + +#include +#include + +using std::vector; +using std::string; + +HelpScreen::HelpScreen() { + vector menu_options; + menu_options.push_back("Continue"); //Continue game + menu.activate(menu_options); +} + +//Run screen +void HelpScreen::run(ALLEGRO_FONT * font) { + ALLEGRO_EVENT_QUEUE* event_queue = NULL; + event_queue = al_create_event_queue(); + al_register_event_source(event_queue, al_get_keyboard_event_source()); + + redraw(font); + menu.draw(300.0, 400.0, 20.0, font); + al_flip_display(); + + bool ctrl = false; + bool exit_screen = false; + while (!exit_screen) { + ALLEGRO_EVENT ev; + al_wait_for_event(event_queue, &ev); + + if (ev.type == ALLEGRO_EVENT_KEY_DOWN) { + switch (ev.keyboard.keycode) { + case ALLEGRO_KEY_SPACE: + //Select item + exit_screen = true; + break; + case ALLEGRO_KEY_ESCAPE: + //Force quit game + exit_screen = true; + break; + } + redraw(font); + al_flip_display(); + } + } + + //Garbage collection + al_destroy_event_queue(event_queue); +} + +void HelpScreen::redraw(ALLEGRO_FONT* font) { + al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 12, SCREEN_H / 1.5 - 10, ALLEGRO_ALIGN_LEFT, "WASD or Arrows - Move ship"); + + al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 12, SCREEN_H / 1.3 - 20, ALLEGRO_ALIGN_LEFT, "Spacebar - Shoot, select menu item"); + + al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 12, SCREEN_H / 2 + 150, ALLEGRO_ALIGN_LEFT, "Esc - Exit Game"); + + al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2 + 113, SCREEN_H / 1.5 - 10, ALLEGRO_ALIGN_LEFT, "Ctrl + H - Open help menu"); + + al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2 + 113, SCREEN_H / 1.3 - 20, ALLEGRO_ALIGN_LEFT, "Ctrl + M - Toggle Music"); + + al_draw_text(font, al_map_rgb(255, 255, 255), 0, SCREEN_H - 10, ALLEGRO_ALIGN_LEFT, "Copyright 2019 Braydon Kains"); +} + +void HelpScreen::back() { +} + +void HelpScreen::cont() { +} \ No newline at end of file diff --git a/Assignment3Project/Assignment3Project/help_screen.h b/Assignment3Project/Assignment3Project/help_screen.h new file mode 100644 index 0000000..d45dcfa --- /dev/null +++ b/Assignment3Project/Assignment3Project/help_screen.h @@ -0,0 +1,18 @@ +#pragma once +#include "screen.h" +#include "cursor.h" +#include + +//Screen to display results upon losing +class HelpScreen : public Screen { +public: + std::map sprites; + Cursor menu; + + HelpScreen(); + + void run(ALLEGRO_FONT* font); + void redraw(ALLEGRO_FONT* font); + void back(); + void cont(); +}; \ No newline at end of file diff --git a/Assignment3Project/Assignment3Project/hit.wav b/Assignment3Project/Assignment3Project/hit.wav new file mode 100644 index 0000000..f117820 Binary files /dev/null and b/Assignment3Project/Assignment3Project/hit.wav differ diff --git a/Assignment3Project/Assignment3Project/object_manager.cpp b/Assignment3Project/Assignment3Project/object_manager.cpp index 9322972..2c711f3 100644 --- a/Assignment3Project/Assignment3Project/object_manager.cpp +++ b/Assignment3Project/Assignment3Project/object_manager.cpp @@ -1,20 +1,21 @@ #include "object_manager.h" +#include using std::vector; - +using std::rand; ObjectManager::ObjectManager() { - + srand(time(NULL)); } -void ObjectManager::initiate(Ship * _player) { +void ObjectManager::init_player(Ship _player) { player = _player; } bool ObjectManager::chk_player_col() { if (enemies.size() > 0) { - for (vector::iterator it = enemies.begin(); it != enemies.end(); it++) { - if (col_eval(player->get_hitbox(), (*it)->get_hitbox())) { + for (vector::iterator it = enemies.begin(); it != enemies.end(); it++) { + if (col_eval(player.get_hitbox(), (*it).get_hitbox())) { return true; } } @@ -25,25 +26,30 @@ bool ObjectManager::chk_player_col() { int ObjectManager::chk_bullet_col() { int points = 0; if (enemies.size() > 0 && player_bullets.size() > 0) { - int i = 0; + int d = 0; vector dead; - for (vector::iterator it = enemies.begin(); it != enemies.end(); it++) { - for (vector::iterator it_b = player_bullets.begin(); it_b != player_bullets.end(); it_b++) { - if (col_eval((*it_b)->get_hitbox(), (*it)->get_hitbox())) { - switch ((*it)->behavior) { + vector kill_bullets; + for (vector::iterator it = enemies.begin(); it != enemies.end(); it++) { + int b = 0; + for (vector::iterator it_b = player_bullets.begin(); it_b != player_bullets.end(); it_b++) { + if (col_eval((*it_b).get_hitbox(), (*it).get_hitbox())) { + switch ((*it).behavior) { default: points += 10; } - delete *it; - dead.push_back(i); + dead.push_back(d); + kill_bullets.push_back(b); } + b++; } - i++; + d++; } //Removed backwards to avoid indexing errors - for (vector::iterator it = dead.end(); it != dead.begin(); it--) { - delete enemies.at(*it); - enemies.erase(enemies.begin() + *it); + for (unsigned int x = dead.size(); x > 0; x--) { + enemies.erase(enemies.begin() + dead.at(x - 1)); + } + for (unsigned int x = kill_bullets.size(); x > 0; x--) { + player_bullets.erase(player_bullets.begin() + kill_bullets.at(x - 1)); } } return points; @@ -51,14 +57,28 @@ int ObjectManager::chk_bullet_col() { void ObjectManager::draw_objects() { - player->draw(); + vector unload; + move_background(); + for (unsigned int k = 0; k < background.size(); k++) { + if (background.at(k).oob) { + unload.push_back(k); + } + else { + background.at(k).draw(); + } + } + for (unsigned int j = unload.size(); j > 0; j--) { + background.erase(background.begin() + unload.at(j - 1)); + } + + player.draw(); if (enemies.size() > 0) { int i = 0; vector oob_ships; - for (vector::iterator it = enemies.begin(); it != enemies.end(); it++) { - if (!(*it)->oob) { - (*it)->draw(); + for (unsigned int k = 0; k < enemies.size(); k++) { + if (!enemies.at(k).oob) { + enemies.at(k).draw(); } else { oob_ships.push_back(i); @@ -66,82 +86,96 @@ void ObjectManager::draw_objects() i++; } //Removed backwards to avoid indexing errors - for (vector::iterator it = oob_ships.end(); it != oob_ships.begin(); it--) { - enemies.erase(enemies.begin() + *it); + for (unsigned int x = oob_ships.size(); x > 0; x--) { + enemies.erase(enemies.begin() + oob_ships.at(x - 1)); } } - bool unload = false; - for (unsigned int i = 0; i < player_bullets.size(); i++) { - if (player_bullets.at(i)->oob) { - unload = true; + unload.clear(); + for (unsigned int k = 0; k < player_bullets.size(); k++) { + if (player_bullets.at(k).oob) { + unload.push_back(k); } else { - player_bullets.at(i)->move(U); - player_bullets.at(i)->draw(); + player_bullets.at(k).move(U); + player_bullets.at(k).draw(); } } - if (unload) { - player_bullets.pop_back(); - } + for (unsigned int j = unload.size(); j > 0; j--) { + player_bullets.erase(player_bullets.begin() + unload.at(j - 1)); + } } void ObjectManager::destroy_objects() { - delete player; + enemies.clear(); + player_bullets.clear(); + enemy_bullets.clear(); +} +void ObjectManager::move_enemies() { if (enemies.size() > 0) { - for (vector::iterator it = enemies.begin(); it != enemies.end(); it++) { - delete *it; - } - enemies.clear(); - } - - if (player_bullets.size() > 0) { - for (vector::iterator it = player_bullets.begin(); it != player_bullets.end(); it++) { - delete *it; + for (vector::iterator it = enemies.begin(); it != enemies.end(); it++) { + (*it).move(D); } - player_bullets.clear(); } +} - if (enemy_bullets.size() > 0) { - for (vector::iterator it = enemy_bullets.begin(); it != enemy_bullets.end(); it++) { - delete *it; +void ObjectManager::set_background() { + for (int i = 0; i < 20; i++) { + Star new_star; + int l = rand() % 2; + BgLayer layer; + switch (l) { + case 0: + layer = Front; + break; + case 1: + layer = Middle; + break; + case 2: + layer = Back; + break; } - enemy_bullets.clear(); + int y = rand() % SCREEN_H; + int x = rand() % (SCREEN_R_B - SCREEN_L_B + 1) + SCREEN_L_B; + new_star.reset_pos(x, y); + new_star.set_layer(layer); + background.push_back(new_star); } } -void ObjectManager::move_enemies() { - if (enemies.size() > 0) { - for (vector::iterator it = enemies.begin(); it != enemies.end(); it++) { - (*it)->move(D); +void ObjectManager::move_background() { + for (unsigned int i = 0; i < background.size(); i++) { + background.at(i).move(D); + } + int generate_chance = rand() % 2; + if (generate_chance) { + Star new_star; + int l = rand() % 2; + BgLayer layer; + switch (l) { + case 0: + layer = Front; + break; + case 1: + layer = Middle; + break; + case 2: + layer = Back; + break; } + int x = rand() % (SCREEN_R_B - SCREEN_L_B + 1) + SCREEN_L_B; + new_star.set_layer(layer); + new_star.reset_pos(x, new_star.h_t_bound); + background.push_back(new_star); } } bool ObjectManager::col_eval(Hitbox h1, Hitbox h2) { - int l1x = h1.x; - int l1y = h1.y; - int r1x = h1.x + h1.width; - int r1y = h1.y + h1.height; - - int l2x = h2.x; - int l2y = h2.y; - int r2x = h2.x + h2.width; - int r2y = h2.y + h2.height; - - /*if (h1.x > (h2.x + h2.width) || h2.x > (h1.x + h1.width)) - return false; - - if (h1.y < (h2.y + h2.height) || h2.y < (h1.y + h1.height)) - return false;*/ - - // If one rectangle is on left side of other - if (l1x > r2x || l2x > r1x) + if (h1.x > (h2.x + h2.width) || h2.x > (h1.x + h1.width)) return false; - // If one rectangle is above other - if (l1y < r2y || l2y < r1y) + if (h1.y > (h2.y + h2.height) || h2.y > (h1.y + h1.height)) return false; return true; diff --git a/Assignment3Project/Assignment3Project/object_manager.h b/Assignment3Project/Assignment3Project/object_manager.h index 9018f14..3b924a9 100644 --- a/Assignment3Project/Assignment3Project/object_manager.h +++ b/Assignment3Project/Assignment3Project/object_manager.h @@ -4,22 +4,26 @@ #include "enums.h" #include "bullet.h" #include "ship.h" +#include "star.h" class ObjectManager { public: - Ship* player; - std::vector enemies; - std::vector player_bullets; - std::vector enemy_bullets; + Ship player; + std::vector enemies; + std::vector player_bullets; + std::vector enemy_bullets; + std::vector background; ObjectManager(); - void initiate(Ship* _player); + void init_player(Ship _player); bool chk_player_col(); int chk_bullet_col(); void draw_objects(); void destroy_objects(); void move_enemies(); + void set_background(); + void move_background(); private: bool col_eval(Hitbox h1, Hitbox h2); diff --git a/Assignment3Project/Assignment3Project/result_screen.cpp b/Assignment3Project/Assignment3Project/result_screen.cpp new file mode 100644 index 0000000..253b7e6 --- /dev/null +++ b/Assignment3Project/Assignment3Project/result_screen.cpp @@ -0,0 +1,91 @@ +#include +#include +#include "result_screen.h" + +using std::string; +using std::vector; +using std::ostringstream; + +ResultScreen::ResultScreen() { + vector menu_options; + menu_options.push_back("Retry"); //Restart game + menu_options.push_back("To Main Menu"); //Go back to main menu + menu_options.push_back("Exit"); //Quit game + menu.activate(menu_options); +} + +void ResultScreen::run(ALLEGRO_FONT* font) { + ALLEGRO_EVENT_QUEUE* event_queue = NULL; + event_queue = al_create_event_queue(); + al_register_event_source(event_queue, al_get_keyboard_event_source()); + + redraw(font); + al_flip_display(); + + bool exit_screen = false; + while (!exit_screen) { + ALLEGRO_EVENT ev; + al_wait_for_event(event_queue, &ev); + + if (ev.type == ALLEGRO_EVENT_KEY_DOWN) { + switch (ev.keyboard.keycode) { + case ALLEGRO_KEY_W: + case ALLEGRO_KEY_UP: + //Move cursor up + menu.up(); + break; + case ALLEGRO_KEY_S: + case ALLEGRO_KEY_DOWN: + //Move cursor down + menu.down(); + break; + case ALLEGRO_KEY_SPACE: + //Select menu item + cont(); + exit_screen = true; + break; + case ALLEGRO_KEY_ESCAPE: + //Force quit game + back(); + exit_screen = true; + break; + } + redraw(font); + al_flip_display(); + } + } + + //Garbage collection + al_clear_to_color(al_map_rgb(0, 0, 0)); + al_destroy_event_queue(event_queue); +} + +void ResultScreen::redraw(ALLEGRO_FONT * font) { + //Determine whether the player receives the bad or good ending; minimum requirement for good ending is 30 catches. + string result_text = (win) ? "You made it literally all the way across space! Wow!" : "Oh no, you died!"; + + //Display score and menu + menu.draw(SCREEN_W / 2 - 40, SCREEN_H / 2 - 30, 20.0, font); + ostringstream score_msg; + score_msg << "Final Score: " << score; + al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2, SCREEN_H / 2 - 90, ALLEGRO_ALIGN_CENTER, score_msg.str().c_str()); + + al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2, SCREEN_H / 2 - 60, ALLEGRO_ALIGN_CENTER, result_text.c_str()); +} + +void ResultScreen::back() { + next_state = Exit; +} + +void ResultScreen::cont() { + string result = menu.get_selected(); + if (result == "Retry") { + next_state = Gameplay; + } + else if (result == "To Main Menu") { + next_state = Start; + } + else { + next_state = Exit; + } +} diff --git a/Assignment3Project/Assignment3Project/result_screen.h b/Assignment3Project/Assignment3Project/result_screen.h new file mode 100644 index 0000000..3c41b8f --- /dev/null +++ b/Assignment3Project/Assignment3Project/result_screen.h @@ -0,0 +1,19 @@ +#pragma once +#include "cursor.h" +#include "screen.h" + +//Screen to display results upon losing +class ResultScreen : public Screen { +public: + int score; + Cursor menu; + std::map sprites; + bool win; + + ResultScreen(); + + void run(ALLEGRO_FONT* font); + void redraw(ALLEGRO_FONT* font); + void back(); + void cont(); +}; \ No newline at end of file diff --git a/Assignment3Project/Assignment3Project/ship.cpp b/Assignment3Project/Assignment3Project/ship.cpp index 6345be0..397ac39 100644 --- a/Assignment3Project/Assignment3Project/ship.cpp +++ b/Assignment3Project/Assignment3Project/ship.cpp @@ -1,15 +1,27 @@ #include "ship.h" -Ship::Ship(Behavior _behavior) { - switch (_behavior) { +Ship::Ship() { +} + +void Ship::reset_pos(float x, float y) { + x_pos = x; + y_pos = y; +} + +void Ship::set_props(ALLEGRO_BITMAP* _sprite, Behavior _behavior) { + sprite = _sprite; + behavior = _behavior; + oob = false; + switch (behavior) { case Enemy: - speed = 0.5; + speed = 1.1; height = 40; width = 40; l_bound = SCREEN_L_B; r_bound = SCREEN_R_B; - h_bound = SCREEN_H; + h_t_bound = 0 - height; + h_b_bound = SCREEN_H + height; break; default: speed = 1.0; @@ -19,19 +31,10 @@ Ship::Ship(Behavior _behavior) { l_bound = SCREEN_L_B; r_bound = SCREEN_R_B; r_bound -= width; - h_bound = SCREEN_H; - h_bound -= height; + h_t_bound = 0; + h_b_bound = SCREEN_H - height; break; - } -} - -void Ship::reset_pos(float x, float y) { - x_pos = x; - y_pos = y; -} - -void Ship::set_sprite(ALLEGRO_BITMAP* _sprite) { - sprite = _sprite; + } } void Ship::draw() { @@ -83,15 +86,15 @@ void Ship::move(Direction dir) { } else oob = true; } - if (y_pos <= 0.0) { + if (y_pos <= h_t_bound) { if (behavior == Player) { - y_pos = 0.0; + y_pos = h_t_bound; } else oob = true; } - else if (y_pos >= h_bound) { + else if (y_pos >= h_b_bound) { if (behavior == Player) { - y_pos = h_bound; + y_pos = h_b_bound; } else oob = true; } diff --git a/Assignment3Project/Assignment3Project/ship.h b/Assignment3Project/Assignment3Project/ship.h index 17eae73..20d9ce9 100644 --- a/Assignment3Project/Assignment3Project/ship.h +++ b/Assignment3Project/Assignment3Project/ship.h @@ -10,7 +10,7 @@ public: bool fired; - Ship(Behavior _behavior); + Ship(); //implementing virtual methods void reset_pos(float x, float y); @@ -19,6 +19,6 @@ public: Hitbox get_hitbox(); //unique to object - void set_sprite(ALLEGRO_BITMAP* _sprite); + void set_props(ALLEGRO_BITMAP* _sprite, Behavior _behavior); Bullet fire(); }; \ No newline at end of file diff --git a/Assignment3Project/Assignment3Project/spaceforce.bmp b/Assignment3Project/Assignment3Project/spaceforce.bmp new file mode 100644 index 0000000..8dfba4d Binary files /dev/null and b/Assignment3Project/Assignment3Project/spaceforce.bmp differ diff --git a/Assignment3Project/Assignment3Project/star.cpp b/Assignment3Project/Assignment3Project/star.cpp new file mode 100644 index 0000000..d5b36ae --- /dev/null +++ b/Assignment3Project/Assignment3Project/star.cpp @@ -0,0 +1,52 @@ +#include "star.h" + +Star::Star() { + oob = false; +} + +void Star::reset_pos(float x, float y) { + x_pos = x; + y_pos = y; +} + +void Star::set_layer(BgLayer _layer) { + layer = _layer; + + switch (layer) { + case Front: + speed = 1.2; + height = 1; + width = 1; + break; + case Middle: + speed = 1.0; + height = 2; + width = 2; + break; + case Back: + speed = 0.4; + height = 4; + width = 4; + break; + } + + h_t_bound = 0 - height; + h_b_bound = SCREEN_H + height; + l_bound = 0; + r_bound = SCREEN_W; +} + +void Star::move(Direction dir) { + y_pos += 4 * speed; + if (y_pos > h_b_bound) oob = true; +} + +void Star::draw() { + al_draw_filled_rectangle(x_pos, y_pos, (x_pos + width), (y_pos + height), al_map_rgb(255, 255, 255)); +} + +Hitbox Star::get_hitbox() { + return Hitbox(); +} + + diff --git a/Assignment3Project/Assignment3Project/star.h b/Assignment3Project/Assignment3Project/star.h new file mode 100644 index 0000000..57ae234 --- /dev/null +++ b/Assignment3Project/Assignment3Project/star.h @@ -0,0 +1,21 @@ +#pragma once +#include "game_element.h" +#include +#include "enums.h" + +//Background elements, used to salvage parallax scrolling attempts +class Star : public GameElement { +public: + BgLayer layer; + + Star(); + + //Implement inhereted virtuals + void reset_pos(float x, float y); + void move(Direction dir); + void draw(); + Hitbox get_hitbox(); + + //Unique to element + void set_layer(BgLayer _layer); +}; \ No newline at end of file diff --git a/Assignment3Project/Assignment3Project/start_screen.cpp b/Assignment3Project/Assignment3Project/start_screen.cpp index cc6506c..114bea8 100644 --- a/Assignment3Project/Assignment3Project/start_screen.cpp +++ b/Assignment3Project/Assignment3Project/start_screen.cpp @@ -37,10 +37,12 @@ void StartScreen::run(ALLEGRO_FONT * font) { if (ev.type == ALLEGRO_EVENT_KEY_DOWN) { switch (ev.keyboard.keycode) { + case ALLEGRO_KEY_W: case ALLEGRO_KEY_UP: //Move cursor up menu.up(); break; + case ALLEGRO_KEY_S: case ALLEGRO_KEY_DOWN: //Move cursor down menu.down(); @@ -66,36 +68,23 @@ void StartScreen::run(ALLEGRO_FONT * font) { } void StartScreen::redraw(ALLEGRO_FONT* font) { - //al_draw_bitmap(sprites["Title"], SCREEN_W / 2 - 240, 20, NULL); //logo + //Logo + al_draw_bitmap(sprites["Title"], SCREEN_W / 2 - 240, 20, NULL); - //Instructions - al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2, SCREEN_H / 2, ALLEGRO_ALIGN_CENTER, "Travel across the reaches of space"); - al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2, SCREEN_H / 2 + 10, ALLEGRO_ALIGN_CENTER, "to kill all the red ships!"); - al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2, SCREEN_H / 2 + 20, ALLEGRO_ALIGN_CENTER, "Red is a bad colour that must be eradicated."); - //al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2, SCREEN_H / 2 + 40, ALLEGRO_ALIGN_CENTER, "idek."); - + al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2, SCREEN_H / 3, ALLEGRO_ALIGN_CENTER, "Journey to the end of space"); + al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2, SCREEN_H / 3 + 10, ALLEGRO_ALIGN_CENTER, "and kill the red ships!"); + al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2, SCREEN_H / 3 + 20, ALLEGRO_ALIGN_CENTER, "Red is a bad colour that must be eradicated."); + //Keys and their associated functions - //al_draw_bitmap(sprites["KeyUp"], SCREEN_W / 8, SCREEN_H / 2 + 60, NULL); - //al_draw_bitmap(sprites["KeyUp"], SCREEN_W / 8 + 34, SCREEN_H / 2 + 60, ALLEGRO_FLIP_VERTICAL); al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 12, SCREEN_H / 1.5 - 10, ALLEGRO_ALIGN_LEFT, "WASD or Arrows - Move ship"); - //al_draw_bitmap(sprites["Spacebar"], SCREEN_W / 8 + 20, SCREEN_H / 2 + 100, NULL); - al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 12, SCREEN_H / 1.3 - 20, ALLEGRO_ALIGN_LEFT, "Spacebar - Shoot"); - //al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 8 + 150, SCREEN_H / 1.3 - 15, ALLEGRO_ALIGN_LEFT, "Place Emplo"); - //al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 8 + 150, SCREEN_H / 1.3 - 25, ALLEGRO_ALIGN_LEFT, "Select Menu Item"); + al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 12, SCREEN_H / 1.3 - 20, ALLEGRO_ALIGN_LEFT, "Spacebar - Shoot, select menu item"); - //al_draw_bitmap(sprites["KeyEsc"], SCREEN_W / 8 + 20, SCREEN_H / 2 + 140, NULL); al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 12, SCREEN_H / 2 + 150, ALLEGRO_ALIGN_LEFT, "Esc - Exit Game"); - //al_draw_bitmap(sprites["KeyCtrl"], SCREEN_W / 2 + 40, SCREEN_H / 2 + 60, NULL); - //al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2 + 70, SCREEN_H / 1.5 - 10, ALLEGRO_ALIGN_LEFT, "+"); - //al_draw_bitmap(sprites["KeyH"], SCREEN_W / 2 + 78, SCREEN_H / 2 + 60, NULL); - al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2 + 113, SCREEN_H / 1.5 - 10, ALLEGRO_ALIGN_LEFT, "Ctrl + H - Help menu"); + al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2 + 113, SCREEN_H / 1.5 - 10, ALLEGRO_ALIGN_LEFT, "Ctrl + H - Open help menu"); - //al_draw_bitmap(sprites["KeyCtrl"], SCREEN_W / 2 + 40, SCREEN_H / 2 + 100, NULL); - //al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2 + 70, SCREEN_H / 2 + 110, ALLEGRO_ALIGN_LEFT, "+"); - //al_draw_bitmap(sprites["KeyM"], SCREEN_W / 2 + 78, SCREEN_H / 2 + 100, NULL); al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_W / 2 + 113, SCREEN_H / 1.3 - 20, ALLEGRO_ALIGN_LEFT, "Ctrl + M - Toggle Music"); al_draw_text(font, al_map_rgb(255, 255, 255), 0, SCREEN_H - 10, ALLEGRO_ALIGN_LEFT, "Copyright 2019 Braydon Kains"); diff --git a/Assignment3Project/Assignment3Project/victory.wav b/Assignment3Project/Assignment3Project/victory.wav new file mode 100644 index 0000000..2efe3a2 Binary files /dev/null and b/Assignment3Project/Assignment3Project/victory.wav differ