You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
393 lines
10 KiB
C++
393 lines
10 KiB
C++
6 years ago
|
#pragma once
|
||
|
#include <allegro5/allegro.h>
|
||
|
#include <allegro5/allegro_image.h>
|
||
|
#include <allegro5/allegro_audio.h>
|
||
|
#include <allegro5/allegro_acodec.h>
|
||
|
#include <vector>
|
||
|
#include <string>
|
||
|
#include <sstream>
|
||
6 years ago
|
#include <fstream>
|
||
6 years ago
|
#include <map>
|
||
|
#include <ctime>
|
||
|
|
||
6 years ago
|
//#include "mappy_A5.h" I couldn't get this to work
|
||
6 years ago
|
|
||
6 years ago
|
#include "game_screen.h"
|
||
6 years ago
|
#include "help_screen.h"
|
||
6 years ago
|
|
||
|
#define FPS 60
|
||
|
|
||
|
using std::vector;
|
||
|
using std::string;
|
||
|
using std::ostringstream;
|
||
6 years ago
|
using std::istringstream;
|
||
|
using std::ifstream;
|
||
6 years ago
|
using std::map;
|
||
|
using std::pair;
|
||
6 years ago
|
using std::rand;
|
||
6 years ago
|
|
||
6 years ago
|
//Keys that will be listener for in events
|
||
6 years ago
|
enum KEYS {
|
||
6 years ago
|
KEYUP, KEYDOWN, KEYLEFT, KEYRIGHT, KEYSPACE, KEYCTRL, KEYH, KEYM, KEYESC
|
||
6 years ago
|
};
|
||
|
|
||
6 years ago
|
//Actions to manage
|
||
6 years ago
|
enum ACTIONS {
|
||
|
FIRE, MUSIC, HELP
|
||
|
};
|
||
|
|
||
6 years ago
|
GameScreen::GameScreen(std::map<std::string, ALLEGRO_BITMAP*> _sprites, std::map<std::string, ALLEGRO_SAMPLE*> _samples) {
|
||
|
sprites = _sprites;
|
||
|
samples = _samples;
|
||
|
srand(time(NULL)); //Seed random number generator with current time so sequence is unique each run
|
||
|
}
|
||
|
|
||
|
//Resets game to default values, and uses new given values
|
||
6 years ago
|
void GameScreen::reset() {
|
||
6 years ago
|
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);
|
||
6 years ago
|
max_bullets = 3;
|
||
6 years ago
|
}
|
||
|
|
||
|
//If a sample needs to be played while it is still being played, it will be stopped first.
|
||
|
//Admittedly this was a hack solution to the fact that my sound effect samples are too long.
|
||
|
//In future projects I will use a better program for sound effect creation that does not have a large minimum length for audio export.
|
||
6 years ago
|
void GameScreen::play(ALLEGRO_SAMPLE_INSTANCE* x) {
|
||
6 years ago
|
if (al_get_sample_instance_playing(x)) {
|
||
|
al_stop_sample_instance(x);
|
||
|
}
|
||
|
al_play_sample_instance(x);
|
||
|
}
|
||
|
|
||
6 years ago
|
//Builds enemy queue out of enemies txt file, possibly used later
|
||
6 years ago
|
void GameScreen::build_enemy_queue() {
|
||
|
string line;
|
||
|
ifstream enemies_file("enemies.txt");
|
||
|
|
||
|
if (enemies_file.is_open()) {
|
||
|
while (getline(enemies_file, line)) {
|
||
|
NewEnemy next;
|
||
|
istringstream curr_line(line);
|
||
|
string element;
|
||
|
//Get enemy type (when there's other types of enemies I'll fix this)
|
||
|
getline(curr_line, element, ',');
|
||
|
next.e_type = Enemy;
|
||
|
//Get appearance time
|
||
|
getline(curr_line, element, ',');
|
||
|
next.when = stoi(element);
|
||
|
//Get position
|
||
|
getline(curr_line, element, ',');
|
||
|
next.x = stoi(element);
|
||
|
enemy_q.push_back(next);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
enemies_file.close();
|
||
6 years ago
|
}
|
||
6 years ago
|
|
||
6 years ago
|
void GameScreen::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());
|
||
|
|
||
|
ALLEGRO_TIMER* timer = NULL;
|
||
6 years ago
|
timer = al_create_timer(1.0 / FPS);
|
||
6 years ago
|
al_register_event_source(event_queue, al_get_timer_event_source(timer));
|
||
|
|
||
6 years ago
|
build_enemy_queue();
|
||
|
bool more_enemies = true;
|
||
|
NewEnemy next_enemy = enemy_q.back();
|
||
|
enemy_q.pop_back();
|
||
|
|
||
6 years ago
|
//Sets input delay structs
|
||
6 years ago
|
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;
|
||
6 years ago
|
|
||
6 years ago
|
//Sets tilemap size and background data
|
||
6 years ago
|
int max_map = TILE_SIZE * LEVEL_LEN;
|
||
|
map_y = max_map;
|
||
|
objects.set_background();
|
||
6 years ago
|
|
||
6 years ago
|
redraw(font);
|
||
|
al_flip_display();
|
||
6 years ago
|
|
||
6 years ago
|
//key tracking array
|
||
6 years ago
|
bool keys[ALLEGRO_KEY_MAX];
|
||
|
for (int i = 0; i < ALLEGRO_KEY_MAX; i++) keys[i] = false;
|
||
|
|
||
6 years ago
|
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);
|
||
|
|
||
6 years ago
|
al_start_timer(timer);
|
||
6 years ago
|
bool exit_screen = false;
|
||
6 years ago
|
while (!exit_screen) {
|
||
|
ALLEGRO_EVENT ev;
|
||
|
al_wait_for_event(event_queue, &ev);
|
||
6 years ago
|
if (ev.type == ALLEGRO_EVENT_TIMER) { //Check per frame
|
||
6 years ago
|
//Music toggle
|
||
6 years ago
|
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;
|
||
|
}
|
||
6 years ago
|
}
|
||
|
|
||
6 years ago
|
//Ship Movement
|
||
6 years ago
|
if (keys[KEYUP]) {
|
||
6 years ago
|
if (keys[KEYRIGHT]) {
|
||
6 years ago
|
objects.player.move(UR);
|
||
6 years ago
|
}
|
||
|
else if (keys[KEYLEFT]) {
|
||
6 years ago
|
objects.player.move(UL);
|
||
6 years ago
|
}
|
||
|
else {
|
||
6 years ago
|
objects.player.move(U);
|
||
6 years ago
|
}
|
||
6 years ago
|
}
|
||
6 years ago
|
else if (keys[KEYDOWN]) {
|
||
|
if (keys[KEYRIGHT]) {
|
||
6 years ago
|
objects.player.move(DR);
|
||
6 years ago
|
}
|
||
|
else if (keys[KEYLEFT]) {
|
||
6 years ago
|
objects.player.move(DL);
|
||
6 years ago
|
}
|
||
|
else {
|
||
6 years ago
|
objects.player.move(D);
|
||
6 years ago
|
}
|
||
|
}
|
||
|
else if (keys[KEYLEFT]) {
|
||
6 years ago
|
objects.player.move(L);
|
||
6 years ago
|
}
|
||
|
else if (keys[KEYRIGHT]) {
|
||
6 years ago
|
objects.player.move(R);
|
||
6 years ago
|
}
|
||
|
|
||
6 years ago
|
//Firing
|
||
6 years ago
|
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"]);
|
||
6 years ago
|
}
|
||
|
}
|
||
6 years ago
|
|
||
|
//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;
|
||
6 years ago
|
}
|
||
|
}
|
||
|
|
||
6 years ago
|
//Move map (HAHAHA THE MAP DIDN'T WORK AND I GAVE UP this is just a glorified timer now)
|
||
6 years ago
|
if (map_y > 0) {
|
||
6 years ago
|
map_y -= 2;
|
||
6 years ago
|
}
|
||
6 years ago
|
else if(objects.enemies.size() == 0) {
|
||
|
win = true;
|
||
6 years ago
|
exit_screen = true;
|
||
6 years ago
|
al_stop_sample_instance(instances["Theme"]);
|
||
|
al_set_sample_instance_gain(instances["Win"], music_vol);
|
||
|
al_play_sample_instance(instances["Win"]);
|
||
6 years ago
|
}
|
||
|
|
||
6 years ago
|
/* 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);
|
||
6 years ago
|
objects.enemies.push_back(new_e);
|
||
6 years ago
|
//Only queue up a new enemy if there is one, if there isn't then set the flag for no more enemies
|
||
6 years ago
|
if (enemy_q.size() > 0) {
|
||
|
next_enemy = enemy_q.back();
|
||
|
enemy_q.pop_back();
|
||
|
}
|
||
|
else {
|
||
|
more_enemies = false;
|
||
|
}
|
||
6 years ago
|
}*/
|
||
|
|
||
|
//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;
|
||
6 years ago
|
}
|
||
|
|
||
6 years ago
|
//Global refresh
|
||
6 years ago
|
if (objects.chk_player_col()) {
|
||
6 years ago
|
exit_screen = true;
|
||
6 years ago
|
al_stop_sample_instance(instances["Theme"]);
|
||
|
play(instances["Die"]);
|
||
|
}
|
||
|
int points = objects.chk_bullet_col();
|
||
|
if (points > 0) {
|
||
|
score += points;
|
||
|
play(instances["Hit"]);
|
||
6 years ago
|
}
|
||
6 years ago
|
objects.move_enemies();
|
||
6 years ago
|
al_clear_to_color(al_map_rgb(0, 0, 0));
|
||
|
redraw(font);
|
||
|
al_flip_display();
|
||
6 years ago
|
}
|
||
|
if (ev.type == ALLEGRO_EVENT_KEY_DOWN) {
|
||
|
switch (ev.keyboard.keycode) {
|
||
6 years ago
|
case ALLEGRO_KEY_S:
|
||
6 years ago
|
case ALLEGRO_KEY_DOWN:
|
||
|
keys[KEYDOWN] = true;
|
||
|
break;
|
||
6 years ago
|
case ALLEGRO_KEY_W:
|
||
6 years ago
|
case ALLEGRO_KEY_UP:
|
||
|
keys[KEYUP] = true;
|
||
|
break;
|
||
6 years ago
|
case ALLEGRO_KEY_D:
|
||
6 years ago
|
case ALLEGRO_KEY_RIGHT:
|
||
|
keys[KEYRIGHT] = true;
|
||
|
break;
|
||
6 years ago
|
case ALLEGRO_KEY_A:
|
||
6 years ago
|
case ALLEGRO_KEY_LEFT:
|
||
|
keys[KEYLEFT] = true;
|
||
|
break;
|
||
6 years ago
|
case ALLEGRO_KEY_SPACE:
|
||
|
keys[KEYSPACE] = true;
|
||
|
break;
|
||
|
case ALLEGRO_KEY_M:
|
||
|
keys[KEYM] = true;
|
||
|
break;
|
||
|
case ALLEGRO_KEY_H:
|
||
|
keys[KEYH] = true;
|
||
|
break;
|
||
|
case ALLEGRO_KEY_ESCAPE:
|
||
|
keys[KEYESC] = true;
|
||
|
break;
|
||
|
case ALLEGRO_KEY_LCTRL:
|
||
|
case ALLEGRO_KEY_RCTRL:
|
||
|
keys[KEYCTRL] = true;
|
||
|
break;
|
||
|
}
|
||
6 years ago
|
}
|
||
|
else if (ev.type == ALLEGRO_EVENT_KEY_UP) {
|
||
|
switch (ev.keyboard.keycode) {
|
||
6 years ago
|
case ALLEGRO_KEY_S:
|
||
6 years ago
|
case ALLEGRO_KEY_DOWN:
|
||
|
keys[KEYDOWN] = false;
|
||
|
break;
|
||
6 years ago
|
case ALLEGRO_KEY_W:
|
||
6 years ago
|
case ALLEGRO_KEY_UP:
|
||
|
keys[KEYUP] = false;
|
||
|
break;
|
||
6 years ago
|
case ALLEGRO_KEY_D:
|
||
6 years ago
|
case ALLEGRO_KEY_RIGHT:
|
||
|
keys[KEYRIGHT] = false;
|
||
|
break;
|
||
6 years ago
|
case ALLEGRO_KEY_A:
|
||
6 years ago
|
case ALLEGRO_KEY_LEFT:
|
||
|
keys[KEYLEFT] = false;
|
||
|
break;
|
||
|
case ALLEGRO_KEY_SPACE:
|
||
|
keys[KEYSPACE] = false;
|
||
6 years ago
|
inputs[FIRE].input_hit = false;
|
||
6 years ago
|
break;
|
||
|
case ALLEGRO_KEY_M:
|
||
|
keys[KEYM] = false;
|
||
6 years ago
|
inputs[MUSIC].input_hit = false;
|
||
6 years ago
|
break;
|
||
|
case ALLEGRO_KEY_H:
|
||
|
keys[KEYH] = false;
|
||
6 years ago
|
inputs[HELP].input_hit = false;
|
||
6 years ago
|
break;
|
||
|
case ALLEGRO_KEY_ESCAPE:
|
||
|
keys[KEYESC] = false;
|
||
|
break;
|
||
|
case ALLEGRO_KEY_LCTRL:
|
||
|
case ALLEGRO_KEY_RCTRL:
|
||
|
keys[KEYCTRL] = false;
|
||
|
break;
|
||
6 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
if (next_state != Exit) { //If the game loop was exited naturally rather than forced by Esc
|
||
|
cont();
|
||
|
}
|
||
|
|
||
6 years ago
|
al_clear_to_color(al_map_rgb(0, 0, 0));
|
||
6 years ago
|
//Garbage collection
|
||
6 years ago
|
objects.destroy_objects();
|
||
6 years ago
|
al_destroy_event_queue(event_queue);
|
||
|
al_destroy_timer(timer);
|
||
|
}
|
||
|
|
||
|
//Redraw all elements of the screen
|
||
|
void GameScreen::redraw(ALLEGRO_FONT* font) {
|
||
6 years ago
|
//MapDrawBG(0, map_y, 0, SCREEN_L_B, SCREEN_W - 80, SCREEN_H);
|
||
6 years ago
|
|
||
|
objects.draw_objects();
|
||
6 years ago
|
|
||
6 years ago
|
//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
|
||
6 years ago
|
ostringstream score_msg;
|
||
6 years ago
|
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());
|
||
6 years ago
|
|
||
6 years ago
|
//Music
|
||
6 years ago
|
string music_img = (music) ? "MusicOn" : "MusicOff";
|
||
6 years ago
|
al_draw_bitmap(sprites[music_img], SCREEN_R_B + 10, 40, NULL);
|
||
6 years ago
|
}
|
||
|
|
||
|
void GameScreen::back() {
|
||
|
next_state = Exit;
|
||
|
}
|
||
|
|
||
|
void GameScreen::cont() {
|
||
6 years ago
|
next_state = (win) ? Win : Lose;
|
||
6 years ago
|
}
|