holy fuck holy shit holy shit fuck it's done

main
Braydon Kains 6 years ago
parent c4124d27d1
commit 30254bb816

@ -146,9 +146,12 @@
<ClInclude Include="game.h" /> <ClInclude Include="game.h" />
<ClInclude Include="game_element.h" /> <ClInclude Include="game_element.h" />
<ClInclude Include="game_screen.h" /> <ClInclude Include="game_screen.h" />
<ClInclude Include="help_screen.h" />
<ClInclude Include="object_manager.h" /> <ClInclude Include="object_manager.h" />
<ClInclude Include="result_screen.h" />
<ClInclude Include="screen.h" /> <ClInclude Include="screen.h" />
<ClInclude Include="ship.h" /> <ClInclude Include="ship.h" />
<ClInclude Include="star.h" />
<ClInclude Include="start_screen.h" /> <ClInclude Include="start_screen.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -156,9 +159,12 @@
<ClCompile Include="cursor.cpp" /> <ClCompile Include="cursor.cpp" />
<ClCompile Include="game.cpp" /> <ClCompile Include="game.cpp" />
<ClCompile Include="game_screen.cpp" /> <ClCompile Include="game_screen.cpp" />
<ClCompile Include="help_screen.cpp" />
<ClCompile Include="main.cpp" /> <ClCompile Include="main.cpp" />
<ClCompile Include="object_manager.cpp" /> <ClCompile Include="object_manager.cpp" />
<ClCompile Include="result_screen.cpp" />
<ClCompile Include="ship.cpp" /> <ClCompile Include="ship.cpp" />
<ClCompile Include="star.cpp" />
<ClCompile Include="start_screen.cpp" /> <ClCompile Include="start_screen.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -63,6 +63,15 @@
<ClInclude Include="object_manager.h"> <ClInclude Include="object_manager.h">
<Filter>Header Files\Engine</Filter> <Filter>Header Files\Engine</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="result_screen.h">
<Filter>Header Files\Screens</Filter>
</ClInclude>
<ClInclude Include="star.h">
<Filter>Header Files\Assignment3</Filter>
</ClInclude>
<ClInclude Include="help_screen.h">
<Filter>Header Files\Screens</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="main.cpp"> <ClCompile Include="main.cpp">
@ -89,6 +98,15 @@
<ClCompile Include="object_manager.cpp"> <ClCompile Include="object_manager.cpp">
<Filter>Source Files\EngineImplement</Filter> <Filter>Source Files\EngineImplement</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="result_screen.cpp">
<Filter>Source Files\ScreensImplement</Filter>
</ClCompile>
<ClCompile Include="star.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="help_screen.cpp">
<Filter>Source Files\ScreensImplement</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Text Include="enemies.txt"> <Text Include="enemies.txt">

@ -1 +1,3 @@
e,10,240 e,10,200
e,20,10
e,22,50

@ -10,7 +10,8 @@
enum State { enum State {
Start, Start,
Gameplay, Gameplay,
End, Win,
Lose,
Exit Exit
}; };
@ -30,6 +31,12 @@ enum Behavior {
Enemy Enemy
}; };
enum BgLayer {
Front,
Middle,
Back
};
struct Hitbox { struct Hitbox {
int x; int x;
int y; int y;

@ -11,6 +11,7 @@ Game::Game() {
void Game::init() { void Game::init() {
score = 0; score = 0;
state = Start; state = Start;
sprites.insert(pair<string, ALLEGRO_BITMAP*>("Title", al_load_bitmap("spaceforce.bmp")));
sprites.insert(pair<string, ALLEGRO_BITMAP*>("Ship", al_load_bitmap("placeholder.bmp"))); sprites.insert(pair<string, ALLEGRO_BITMAP*>("Ship", al_load_bitmap("placeholder.bmp")));
sprites.insert(pair<string, ALLEGRO_BITMAP*>("Enemy", al_load_bitmap("enemy.bmp"))); sprites.insert(pair<string, ALLEGRO_BITMAP*>("Enemy", al_load_bitmap("enemy.bmp")));
sprites.insert(pair<string, ALLEGRO_BITMAP*>("MusicOn", al_load_bitmap("music_on.bmp"))); sprites.insert(pair<string, ALLEGRO_BITMAP*>("MusicOn", al_load_bitmap("music_on.bmp")));
@ -18,6 +19,10 @@ void Game::init() {
al_reserve_samples(4); al_reserve_samples(4);
samples.insert(pair<string, ALLEGRO_SAMPLE*>("Theme", al_load_sample("cheesetheme.wav"))); samples.insert(pair<string, ALLEGRO_SAMPLE*>("Theme", al_load_sample("cheesetheme.wav")));
samples.insert(pair<string, ALLEGRO_SAMPLE*>("Fire", al_load_sample("fire.wav")));
samples.insert(pair<string, ALLEGRO_SAMPLE*>("Hit", al_load_sample("hit.wav")));
samples.insert(pair<string, ALLEGRO_SAMPLE*>("Die", al_load_sample("death.wav")));
samples.insert(pair<string, ALLEGRO_SAMPLE*>("Win", al_load_sample("victory.wav")));
font = al_create_builtin_font(); font = al_create_builtin_font();
} }
@ -31,6 +36,7 @@ void Game::run() {
//Load screens //Load screens
StartScreen start_screen(sprites); StartScreen start_screen(sprites);
GameScreen game_screen(sprites, samples); GameScreen game_screen(sprites, samples);
ResultScreen result_screen;
while (state != Exit) { while (state != Exit) {
switch (state) { switch (state) {
@ -44,7 +50,15 @@ void Game::run() {
game_screen.run(font); game_screen.run(font);
state = game_screen.next_state; state = game_screen.next_state;
break; 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 //Garbage collection
@ -56,4 +70,5 @@ void Game::run() {
for (it2 = samples.begin(); it2 != samples.end(); it2++) { for (it2 = samples.begin(); it2 != samples.end(); it2++) {
al_destroy_sample(it2->second); al_destroy_sample(it2->second);
} }
al_destroy_font(font);
} }

@ -13,6 +13,7 @@
#include "enums.h" #include "enums.h"
#include "start_screen.h" #include "start_screen.h"
#include "game_screen.h" #include "game_screen.h"
#include "result_screen.h"
//Game state machine, contains data global to game //Game state machine, contains data global to game
class Game { class Game {

@ -7,7 +7,8 @@ class GameElement {
public: public:
float x_pos; float x_pos;
float y_pos; float y_pos;
float h_bound; float h_t_bound;
float h_b_bound;
float l_bound; float l_bound;
float r_bound; float r_bound;
float speed; float speed;

@ -13,6 +13,7 @@
//#include "mappy_A5.h" //#include "mappy_A5.h"
#include "game_screen.h" #include "game_screen.h"
#include "help_screen.h"
#define FPS 60 #define FPS 60
@ -23,11 +24,16 @@ using std::istringstream;
using std::ifstream; using std::ifstream;
using std::map; using std::map;
using std::pair; using std::pair;
using std::rand;
enum KEYS { enum KEYS {
KEYUP, KEYDOWN, KEYLEFT, KEYRIGHT, KEYSPACE, KEYCTRL, KEYH, KEYM, KEYESC KEYUP, KEYDOWN, KEYLEFT, KEYRIGHT, KEYSPACE, KEYCTRL, KEYH, KEYM, KEYESC
}; };
enum ACTIONS {
FIRE, MUSIC, HELP
};
GameScreen::GameScreen(std::map<std::string, ALLEGRO_BITMAP*> _sprites, std::map<std::string, ALLEGRO_SAMPLE*> _samples) { GameScreen::GameScreen(std::map<std::string, ALLEGRO_BITMAP*> _sprites, std::map<std::string, ALLEGRO_SAMPLE*> _samples) {
sprites = _sprites; sprites = _sprites;
samples = _samples; samples = _samples;
@ -36,9 +42,14 @@ GameScreen::GameScreen(std::map<std::string, ALLEGRO_BITMAP*> _sprites, std::map
//Resets game to default values, and uses new given values //Resets game to default values, and uses new given values
void GameScreen::reset() { void GameScreen::reset() {
objects.player = new Ship(Player); music = true;
objects.player->set_sprite(sprites["Ship"]); win = false;
objects.player->reset_pos(SCREEN_W / 2, SCREEN_H / 8); 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; max_bullets = 3;
} }
@ -91,13 +102,22 @@ void GameScreen::run(ALLEGRO_FONT* font) {
NewEnemy next_enemy = enemy_q.back(); NewEnemy next_enemy = enemy_q.back();
enemy_q.pop_back(); enemy_q.pop_back();
map<string, InputDelay> inputs; InputDelay inputs[3];
inputs.insert(pair<string, InputDelay>("Fire", InputDelay())); inputs[FIRE].input_hit = false;
inputs.insert(pair<string, InputDelay>("Music", InputDelay())); inputs[FIRE].delay_sec = 0;
inputs.insert(pair<string, InputDelay>("Help", InputDelay())); 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); redraw(font);
al_flip_display(); al_flip_display();
@ -105,6 +125,18 @@ void GameScreen::run(ALLEGRO_FONT* font) {
bool keys[ALLEGRO_KEY_MAX]; bool keys[ALLEGRO_KEY_MAX];
for (int i = 0; i < ALLEGRO_KEY_MAX; i++) keys[i] = false; for (int i = 0; i < ALLEGRO_KEY_MAX; i++) keys[i] = false;
map<string, ALLEGRO_SAMPLE_INSTANCE*> instances;
map<string, ALLEGRO_SAMPLE*>::iterator it;
for (it = samples.begin(); it != samples.end(); it++) {
instances.insert(pair<string, ALLEGRO_SAMPLE_INSTANCE*>(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); al_start_timer(timer);
bool exit_screen = false; bool exit_screen = false;
while (!exit_screen) { while (!exit_screen) {
@ -112,71 +144,91 @@ void GameScreen::run(ALLEGRO_FONT* font) {
al_wait_for_event(event_queue, &ev); al_wait_for_event(event_queue, &ev);
if (ev.type == ALLEGRO_EVENT_TIMER) { //Check per frame if (ev.type == ALLEGRO_EVENT_TIMER) { //Check per frame
//Music toggle //Music toggle
if (keys[KEYCTRL] && keys[KEYM]) { if (!inputs[MUSIC].input_hit) {
music = !music; 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 //Ship Movement
if (keys[KEYUP]) { if (keys[KEYUP]) {
if (keys[KEYRIGHT]) { if (keys[KEYRIGHT]) {
objects.player->move(UR); objects.player.move(UR);
} }
else if (keys[KEYLEFT]) { else if (keys[KEYLEFT]) {
objects.player->move(UL); objects.player.move(UL);
} }
else { else {
objects.player->move(U); objects.player.move(U);
} }
} }
else if (keys[KEYDOWN]) { else if (keys[KEYDOWN]) {
if (keys[KEYRIGHT]) { if (keys[KEYRIGHT]) {
objects.player->move(DR); objects.player.move(DR);
} }
else if (keys[KEYLEFT]) { else if (keys[KEYLEFT]) {
objects.player->move(DL); objects.player.move(DL);
} }
else { else {
objects.player->move(D); objects.player.move(D);
} }
} }
else if (keys[KEYLEFT]) { else if (keys[KEYLEFT]) {
objects.player->move(L); objects.player.move(L);
} }
else if (keys[KEYRIGHT]) { else if (keys[KEYRIGHT]) {
objects.player->move(R); objects.player.move(R);
} }
//Firing //Firing
if (keys[KEYSPACE]) { if (!inputs[FIRE].input_hit) {
if (objects.player_bullets.size() < max_bullets) { if (keys[KEYSPACE] && objects.player_bullets.size() < max_bullets) {
if (!objects.player->fired) { objects.player_bullets.push_back(objects.player.fire());
objects.player_bullets.push_back(&objects.player->fire()); inputs[FIRE].input_hit = true;
} play(instances["Fire"]);
objects.player->fired = true;
} }
} }
if (objects.player->fired) {
if (fired_counter >= 20) { //Help menu
objects.player->fired = false; if (!inputs[HELP].input_hit) {
fired_counter = 0; if (keys[KEYCTRL] && keys[KEYH]) {
} HelpScreen help_screen;
else { al_clear_to_color(al_map_rgb(0, 0, 0));
fired_counter++; 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) { if (map_y > 0) {
map_y -= 10; map_y -= 2;
} }
else { else if(objects.enemies.size() == 0) {
win = true;
exit_screen = 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) { /* This may be used in the next assignment, this functionality is for scripting enemy appearance
Ship* new_e = new Ship(next_enemy.e_type); //Check if the next enemy is due
new_e->set_sprite(sprites["Enemy"]); if (more_enemies && (max_map - map_y) >= next_enemy.when) {
new_e->reset_pos(next_enemy.x, 0 - new_e->height + 1); //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); 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) { if (enemy_q.size() > 0) {
next_enemy = enemy_q.back(); next_enemy = enemy_q.back();
enemy_q.pop_back(); enemy_q.pop_back();
@ -184,13 +236,35 @@ void GameScreen::run(ALLEGRO_FONT* font) {
else { else {
more_enemies = false; 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 //Global refresh
if (objects.chk_player_col()) { if (objects.chk_player_col()) {
exit_screen = true; 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(); objects.move_enemies();
al_clear_to_color(al_map_rgb(0, 0, 0)); al_clear_to_color(al_map_rgb(0, 0, 0));
redraw(font); redraw(font);
@ -252,12 +326,15 @@ void GameScreen::run(ALLEGRO_FONT* font) {
break; break;
case ALLEGRO_KEY_SPACE: case ALLEGRO_KEY_SPACE:
keys[KEYSPACE] = false; keys[KEYSPACE] = false;
inputs[FIRE].input_hit = false;
break; break;
case ALLEGRO_KEY_M: case ALLEGRO_KEY_M:
keys[KEYM] = false; keys[KEYM] = false;
inputs[MUSIC].input_hit = false;
break; break;
case ALLEGRO_KEY_H: case ALLEGRO_KEY_H:
keys[KEYH] = false; keys[KEYH] = false;
inputs[HELP].input_hit = false;
break; break;
case ALLEGRO_KEY_ESCAPE: case ALLEGRO_KEY_ESCAPE:
keys[KEYESC] = false; keys[KEYESC] = false;
@ -273,8 +350,8 @@ void GameScreen::run(ALLEGRO_FONT* font) {
cont(); cont();
} }
al_clear_to_color(al_map_rgb(0, 0, 0));
//Garbage collection //Garbage collection
//MapFreeMem();
objects.destroy_objects(); objects.destroy_objects();
al_destroy_event_queue(event_queue); al_destroy_event_queue(event_queue);
al_destroy_timer(timer); al_destroy_timer(timer);
@ -286,12 +363,19 @@ void GameScreen::redraw(ALLEGRO_FONT* font) {
objects.draw_objects(); 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; ostringstream score_msg;
score_msg << "Score: " << score; score_msg << "" << score;
al_draw_text(font, al_map_rgb(255, 255, 255), SCREEN_R_B + 2, 0, ALLEGRO_ALIGN_LEFT, score_msg.str().c_str()); 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"; 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() { void GameScreen::back() {
@ -299,5 +383,5 @@ void GameScreen::back() {
} }
void GameScreen::cont() { void GameScreen::cont() {
next_state = Start; next_state = (win) ? Win : Lose;
} }

@ -16,6 +16,7 @@ public:
int score; int score;
int level; int level;
bool music; bool music;
bool win;
int map_y; int map_y;
@ -33,5 +34,4 @@ public:
private: private:
void play(ALLEGRO_SAMPLE_INSTANCE* x); void play(ALLEGRO_SAMPLE_INSTANCE* x);
void build_enemy_queue(); void build_enemy_queue();
void set_delays(std::map<std::string, InputDelay> inputs);
}; };

@ -0,0 +1,69 @@
#include "help_screen.h"
#include <vector>
#include <string>
using std::vector;
using std::string;
HelpScreen::HelpScreen() {
vector<string> 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() {
}

@ -0,0 +1,18 @@
#pragma once
#include "screen.h"
#include "cursor.h"
#include <string>
//Screen to display results upon losing
class HelpScreen : public Screen {
public:
std::map<std::string, ALLEGRO_BITMAP*> sprites;
Cursor<std::string> menu;
HelpScreen();
void run(ALLEGRO_FONT* font);
void redraw(ALLEGRO_FONT* font);
void back();
void cont();
};

@ -1,20 +1,21 @@
#include "object_manager.h" #include "object_manager.h"
#include <ctime>
using std::vector; using std::vector;
using std::rand;
ObjectManager::ObjectManager() { ObjectManager::ObjectManager() {
srand(time(NULL));
} }
void ObjectManager::initiate(Ship * _player) { void ObjectManager::init_player(Ship _player) {
player = _player; player = _player;
} }
bool ObjectManager::chk_player_col() { bool ObjectManager::chk_player_col() {
if (enemies.size() > 0) { if (enemies.size() > 0) {
for (vector<Ship*>::iterator it = enemies.begin(); it != enemies.end(); it++) { for (vector<Ship>::iterator it = enemies.begin(); it != enemies.end(); it++) {
if (col_eval(player->get_hitbox(), (*it)->get_hitbox())) { if (col_eval(player.get_hitbox(), (*it).get_hitbox())) {
return true; return true;
} }
} }
@ -25,25 +26,30 @@ bool ObjectManager::chk_player_col() {
int ObjectManager::chk_bullet_col() { int ObjectManager::chk_bullet_col() {
int points = 0; int points = 0;
if (enemies.size() > 0 && player_bullets.size() > 0) { if (enemies.size() > 0 && player_bullets.size() > 0) {
int i = 0; int d = 0;
vector<int> dead; vector<int> dead;
for (vector<Ship*>::iterator it = enemies.begin(); it != enemies.end(); it++) { vector<int> kill_bullets;
for (vector<Bullet*>::iterator it_b = player_bullets.begin(); it_b != player_bullets.end(); it_b++) { for (vector<Ship>::iterator it = enemies.begin(); it != enemies.end(); it++) {
if (col_eval((*it_b)->get_hitbox(), (*it)->get_hitbox())) { int b = 0;
switch ((*it)->behavior) { for (vector<Bullet>::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: default:
points += 10; points += 10;
} }
delete *it; dead.push_back(d);
dead.push_back(i); kill_bullets.push_back(b);
} }
b++;
} }
i++; d++;
} }
//Removed backwards to avoid indexing errors //Removed backwards to avoid indexing errors
for (vector<int>::iterator it = dead.end(); it != dead.begin(); it--) { for (unsigned int x = dead.size(); x > 0; x--) {
delete enemies.at(*it); enemies.erase(enemies.begin() + dead.at(x - 1));
enemies.erase(enemies.begin() + *it); }
for (unsigned int x = kill_bullets.size(); x > 0; x--) {
player_bullets.erase(player_bullets.begin() + kill_bullets.at(x - 1));
} }
} }
return points; return points;
@ -51,14 +57,28 @@ int ObjectManager::chk_bullet_col() {
void ObjectManager::draw_objects() void ObjectManager::draw_objects()
{ {
player->draw(); vector<int> 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) { if (enemies.size() > 0) {
int i = 0; int i = 0;
vector<int> oob_ships; vector<int> oob_ships;
for (vector<Ship*>::iterator it = enemies.begin(); it != enemies.end(); it++) { for (unsigned int k = 0; k < enemies.size(); k++) {
if (!(*it)->oob) { if (!enemies.at(k).oob) {
(*it)->draw(); enemies.at(k).draw();
} }
else { else {
oob_ships.push_back(i); oob_ships.push_back(i);
@ -66,82 +86,96 @@ void ObjectManager::draw_objects()
i++; i++;
} }
//Removed backwards to avoid indexing errors //Removed backwards to avoid indexing errors
for (vector<int>::iterator it = oob_ships.end(); it != oob_ships.begin(); it--) { for (unsigned int x = oob_ships.size(); x > 0; x--) {
enemies.erase(enemies.begin() + *it); enemies.erase(enemies.begin() + oob_ships.at(x - 1));
} }
} }
bool unload = false; unload.clear();
for (unsigned int i = 0; i < player_bullets.size(); i++) { for (unsigned int k = 0; k < player_bullets.size(); k++) {
if (player_bullets.at(i)->oob) { if (player_bullets.at(k).oob) {
unload = true; unload.push_back(k);
} }
else { else {
player_bullets.at(i)->move(U); player_bullets.at(k).move(U);
player_bullets.at(i)->draw(); player_bullets.at(k).draw();
} }
} }
if (unload) { for (unsigned int j = unload.size(); j > 0; j--) {
player_bullets.pop_back(); player_bullets.erase(player_bullets.begin() + unload.at(j - 1));
} }
} }
void ObjectManager::destroy_objects() { void ObjectManager::destroy_objects() {
delete player; enemies.clear();
player_bullets.clear();
enemy_bullets.clear();
}
void ObjectManager::move_enemies() {
if (enemies.size() > 0) { if (enemies.size() > 0) {
for (vector<Ship*>::iterator it = enemies.begin(); it != enemies.end(); it++) { for (vector<Ship>::iterator it = enemies.begin(); it != enemies.end(); it++) {
delete *it; (*it).move(D);
} }
enemies.clear();
}
if (player_bullets.size() > 0) {
for (vector<Bullet*>::iterator it = player_bullets.begin(); it != player_bullets.end(); it++) {
delete *it;
}
player_bullets.clear();
} }
}
if (enemy_bullets.size() > 0) { void ObjectManager::set_background() {
for (vector<Bullet*>::iterator it = enemy_bullets.begin(); it != enemy_bullets.end(); it++) { for (int i = 0; i < 20; i++) {
delete *it; 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() { void ObjectManager::move_background() {
if (enemies.size() > 0) { for (unsigned int i = 0; i < background.size(); i++) {
for (vector<Ship*>::iterator it = enemies.begin(); it != enemies.end(); it++) { background.at(i).move(D);
(*it)->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) { bool ObjectManager::col_eval(Hitbox h1, Hitbox h2) {
int l1x = h1.x; if (h1.x > (h2.x + h2.width) || h2.x > (h1.x + h1.width))
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)
return false; return false;
// If one rectangle is above other if (h1.y > (h2.y + h2.height) || h2.y > (h1.y + h1.height))
if (l1y < r2y || l2y < r1y)
return false; return false;
return true; return true;

@ -4,22 +4,26 @@
#include "enums.h" #include "enums.h"
#include "bullet.h" #include "bullet.h"
#include "ship.h" #include "ship.h"
#include "star.h"
class ObjectManager { class ObjectManager {
public: public:
Ship* player; Ship player;
std::vector<Ship*> enemies; std::vector<Ship> enemies;
std::vector<Bullet*> player_bullets; std::vector<Bullet> player_bullets;
std::vector<Bullet*> enemy_bullets; std::vector<Bullet> enemy_bullets;
std::vector<Star> background;
ObjectManager(); ObjectManager();
void initiate(Ship* _player); void init_player(Ship _player);
bool chk_player_col(); bool chk_player_col();
int chk_bullet_col(); int chk_bullet_col();
void draw_objects(); void draw_objects();
void destroy_objects(); void destroy_objects();
void move_enemies(); void move_enemies();
void set_background();
void move_background();
private: private:
bool col_eval(Hitbox h1, Hitbox h2); bool col_eval(Hitbox h1, Hitbox h2);

@ -0,0 +1,91 @@
#include <vector>
#include <sstream>
#include "result_screen.h"
using std::string;
using std::vector;
using std::ostringstream;
ResultScreen::ResultScreen() {
vector<string> 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;
}
}

@ -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<std::string> menu;
std::map<std::string, ALLEGRO_BITMAP*> sprites;
bool win;
ResultScreen();
void run(ALLEGRO_FONT* font);
void redraw(ALLEGRO_FONT* font);
void back();
void cont();
};

@ -1,15 +1,27 @@
#include "ship.h" #include "ship.h"
Ship::Ship(Behavior _behavior) { Ship::Ship() {
switch (_behavior) { }
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: case Enemy:
speed = 0.5; speed = 1.1;
height = 40; height = 40;
width = 40; width = 40;
l_bound = SCREEN_L_B; l_bound = SCREEN_L_B;
r_bound = SCREEN_R_B; r_bound = SCREEN_R_B;
h_bound = SCREEN_H; h_t_bound = 0 - height;
h_b_bound = SCREEN_H + height;
break; break;
default: default:
speed = 1.0; speed = 1.0;
@ -19,21 +31,12 @@ Ship::Ship(Behavior _behavior) {
l_bound = SCREEN_L_B; l_bound = SCREEN_L_B;
r_bound = SCREEN_R_B; r_bound = SCREEN_R_B;
r_bound -= width; r_bound -= width;
h_bound = SCREEN_H; h_t_bound = 0;
h_bound -= height; h_b_bound = SCREEN_H - height;
break; 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() { void Ship::draw() {
al_draw_bitmap(sprite, x_pos, y_pos, (behavior == Player) ? NULL : ALLEGRO_FLIP_VERTICAL); al_draw_bitmap(sprite, x_pos, y_pos, (behavior == Player) ? NULL : ALLEGRO_FLIP_VERTICAL);
} }
@ -83,15 +86,15 @@ void Ship::move(Direction dir) {
} }
else oob = true; else oob = true;
} }
if (y_pos <= 0.0) { if (y_pos <= h_t_bound) {
if (behavior == Player) { if (behavior == Player) {
y_pos = 0.0; y_pos = h_t_bound;
} }
else oob = true; else oob = true;
} }
else if (y_pos >= h_bound) { else if (y_pos >= h_b_bound) {
if (behavior == Player) { if (behavior == Player) {
y_pos = h_bound; y_pos = h_b_bound;
} }
else oob = true; else oob = true;
} }

@ -10,7 +10,7 @@ public:
bool fired; bool fired;
Ship(Behavior _behavior); Ship();
//implementing virtual methods //implementing virtual methods
void reset_pos(float x, float y); void reset_pos(float x, float y);
@ -19,6 +19,6 @@ public:
Hitbox get_hitbox(); Hitbox get_hitbox();
//unique to object //unique to object
void set_sprite(ALLEGRO_BITMAP* _sprite); void set_props(ALLEGRO_BITMAP* _sprite, Behavior _behavior);
Bullet fire(); Bullet fire();
}; };

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

@ -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();
}

@ -0,0 +1,21 @@
#pragma once
#include "game_element.h"
#include <allegro5/allegro_primitives.h>
#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);
};

@ -37,10 +37,12 @@ void StartScreen::run(ALLEGRO_FONT * font) {
if (ev.type == ALLEGRO_EVENT_KEY_DOWN) { if (ev.type == ALLEGRO_EVENT_KEY_DOWN) {
switch (ev.keyboard.keycode) { switch (ev.keyboard.keycode) {
case ALLEGRO_KEY_W:
case ALLEGRO_KEY_UP: case ALLEGRO_KEY_UP:
//Move cursor up //Move cursor up
menu.up(); menu.up();
break; break;
case ALLEGRO_KEY_S:
case ALLEGRO_KEY_DOWN: case ALLEGRO_KEY_DOWN:
//Move cursor down //Move cursor down
menu.down(); menu.down();
@ -66,36 +68,23 @@ void StartScreen::run(ALLEGRO_FONT * font) {
} }
void StartScreen::redraw(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 //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 / 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 / 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 / 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 / 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 / 3 + 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.");
//Keys and their associated functions //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_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, 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");
//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_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_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 + 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 + 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_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), 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"); al_draw_text(font, al_map_rgb(255, 255, 255), 0, SCREEN_H - 10, ALLEGRO_ALIGN_LEFT, "Copyright 2019 Braydon Kains");

Loading…
Cancel
Save