Helios Lyons 201239214

Dependencies:   mbed

Brief

My aim for this project was to create a FRDM K64F adapted version of the classic Space Invaders by Tomohiro Nishikado. The game itself has a number of clear features to implement;

  • Left to right movement for the player 'canon'
  • A fixed amount of player lives
  • Firing mechanics for both canon and invaders (hence collision systems)
  • Random firing from remaining invaders
  • Wave based combat

My own addition to these established ideas was Boss waves, featuring a single, larger sprite which fires at a faster interval than previous waves. The addition of a movement system using a basic for loop, as opposed to a velocity based system, will enhance the nostalgic feel of the game.

https://os.mbed.com/media/uploads/helioslyons/screenshot_2020-05-27_at_06.12.00.png

Gameplay

Movement is controlled with the joystick, moving the canon left or right. Fire by pressing A. Invaders spawn at set positions, but randomly fire at a set interval, which is higher for boss waves. Time is taken during each wave, and displayed at wave intervals, and if the play wins.

Controls are shown on the Gamepad below: (attribution: Craig A. Evans, ELEC2645 University of Leeds)

https://os.mbed.com/media/uploads/helioslyons/screenshot_2020-05-27_at_06.20.18.png

Committer:
helioslyons
Date:
Wed May 27 05:07:34 2020 +0000
Revision:
11:1fd8fca23375
Parent:
10:19b250c7de5e
Helios A. Lyons 201239214;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
helioslyons 4:c644522ff9d9 1 #include "Army.h"
helioslyons 5:72f59786b695 2 #include "Invader.h"
helioslyons 8:ec4199484adf 3 #include "mbed.h"
helioslyons 8:ec4199484adf 4 #include "N5110.h"
helioslyons 8:ec4199484adf 5 #include "Gamepad.h"
helioslyons 9:6a245c8ce08e 6
helioslyons 9:6a245c8ce08e 7 #include <cstdlib>
helioslyons 4:c644522ff9d9 8 #include <vector>
helioslyons 11:1fd8fca23375 9 #include <algorithm>
helioslyons 11:1fd8fca23375 10 #include <functional>
helioslyons 11:1fd8fca23375 11
helioslyons 11:1fd8fca23375 12
helioslyons 11:1fd8fca23375 13 using namespace std;
helioslyons 11:1fd8fca23375 14
helioslyons 11:1fd8fca23375 15 std::vector<std::vector<Invader*> > invaders;
helioslyons 4:c644522ff9d9 16
helioslyons 4:c644522ff9d9 17 Army::Army()
helioslyons 4:c644522ff9d9 18 {
helioslyons 6:e3a1bfbb1627 19
helioslyons 4:c644522ff9d9 20 }
helioslyons 6:e3a1bfbb1627 21
helioslyons 4:c644522ff9d9 22 Army::~Army()
helioslyons 4:c644522ff9d9 23 {
helioslyons 6:e3a1bfbb1627 24
helioslyons 4:c644522ff9d9 25 }
helioslyons 6:e3a1bfbb1627 26
helioslyons 11:1fd8fca23375 27 void Army::create_army(int rows, int columns, int speed, bool ifboss, int bossNum)
helioslyons 6:e3a1bfbb1627 28 {
helioslyons 11:1fd8fca23375 29 _rows = rows; // assign variables
helioslyons 11:1fd8fca23375 30 _columns = columns;
helioslyons 11:1fd8fca23375 31 _boss = ifboss;
helioslyons 11:1fd8fca23375 32
helioslyons 11:1fd8fca23375 33 invaders.clear(); // free memory from previous instances of the vector
helioslyons 11:1fd8fca23375 34 invaders.resize(_rows); // clear contents and resize to given # of rows, columns
helioslyons 11:1fd8fca23375 35 for (size_t i = 0; i < _rows; ++i) { invaders[i].resize(_columns); }
helioslyons 11:1fd8fca23375 36
helioslyons 11:1fd8fca23375 37 int vector_width = _columns*8 + _columns; // calculate parameters of the vector
helioslyons 11:1fd8fca23375 38 int temp_x = WIDTH/2 - vector_width/2; // as a table, to allow proper Invader
helioslyons 11:1fd8fca23375 39 int start_y = HEIGHT/2 - 20; // distribution
helioslyons 11:1fd8fca23375 40 _inc = 6;
helioslyons 6:e3a1bfbb1627 41
helioslyons 11:1fd8fca23375 42 for (int i = 0; i < _rows; i++) { // nested 'for' looped through the vector
helioslyons 11:1fd8fca23375 43 int start_x = temp_x; // reset x position at each row
helioslyons 11:1fd8fca23375 44 if (i > 0) {start_y += 9;} // increment y position from 2nd row onward
helioslyons 11:1fd8fca23375 45
helioslyons 11:1fd8fca23375 46 for (int n = 0; n < _columns; n++) { // iterate through columns
helioslyons 11:1fd8fca23375 47 invaders[i][n] = new Invader(); // instantiate a new Invader pointer
helioslyons 11:1fd8fca23375 48 if (_boss) { // change sprite value if boss wave
helioslyons 11:1fd8fca23375 49 int bossSprite = bossNum + 3;
helioslyons 11:1fd8fca23375 50 invaders[i][n]->init(bossSprite,bossNum*2,1); //
helioslyons 11:1fd8fca23375 51 invaders[i][n]->set_pos(start_x,start_y);
helioslyons 11:1fd8fca23375 52 }
helioslyons 11:1fd8fca23375 53 else {
helioslyons 11:1fd8fca23375 54 invaders[i][n]->init(i+1,1,0); // initialise with sprite, HP, speed, and boss boolean
helioslyons 11:1fd8fca23375 55 invaders[i][n]->set_pos(start_x,start_y);
helioslyons 11:1fd8fca23375 56 int rowWidth = invaders[i][n]->get_width();
helioslyons 11:1fd8fca23375 57 start_x += rowWidth + 2; // increment x position
helioslyons 11:1fd8fca23375 58 }
helioslyons 11:1fd8fca23375 59 }
helioslyons 6:e3a1bfbb1627 60 }
helioslyons 6:e3a1bfbb1627 61 }
helioslyons 6:e3a1bfbb1627 62
helioslyons 11:1fd8fca23375 63 bool Army::end() // find # of dead invaders and compare to expected result
helioslyons 6:e3a1bfbb1627 64 {
helioslyons 11:1fd8fca23375 65 int sum = 0;
helioslyons 11:1fd8fca23375 66 for (int i = 0; i < _rows; i++) { // iterate through Invader vector
helioslyons 11:1fd8fca23375 67 for (int n = 0; n < _columns; n++) { // and get death state for each
helioslyons 11:1fd8fca23375 68 bool inv_death = invaders[i][n]->get_death();
helioslyons 11:1fd8fca23375 69 if (inv_death) {sum++;} // add to sum
helioslyons 7:5fe9ac6522c5 70 }
helioslyons 7:5fe9ac6522c5 71 }
helioslyons 11:1fd8fca23375 72
helioslyons 11:1fd8fca23375 73 if (sum == _rows*_columns) { // check sum vs. total number of invaders
helioslyons 11:1fd8fca23375 74 _end = true;
helioslyons 11:1fd8fca23375 75 return _end;
helioslyons 7:5fe9ac6522c5 76 }
helioslyons 7:5fe9ac6522c5 77
helioslyons 7:5fe9ac6522c5 78 else {
helioslyons 11:1fd8fca23375 79 _end = false;
helioslyons 11:1fd8fca23375 80 return _end;
helioslyons 7:5fe9ac6522c5 81 }
helioslyons 6:e3a1bfbb1627 82 }
helioslyons 8:ec4199484adf 83
helioslyons 11:1fd8fca23375 84 void Army::draw(N5110 &lcd) // call draw for alive invaders
helioslyons 11:1fd8fca23375 85 {
helioslyons 11:1fd8fca23375 86 for (int i = 0; i < _rows; i++) { // iterate through Invader vector
helioslyons 11:1fd8fca23375 87 for (int n = 0; n < _columns; n++) { // call draw function if death is false
helioslyons 11:1fd8fca23375 88 bool state = invaders[i][n]->get_death();
helioslyons 11:1fd8fca23375 89 if (!state) {invaders[i][n]->draw(lcd);}
helioslyons 11:1fd8fca23375 90 }
helioslyons 8:ec4199484adf 91 }
helioslyons 8:ec4199484adf 92 }
helioslyons 9:6a245c8ce08e 93
helioslyons 11:1fd8fca23375 94 // NOTE: instead of all these 'for' loops, one that checked and deleted dead
helioslyons 11:1fd8fca23375 95 // invaders would have been more efficient, if called prior to draw and
helioslyons 11:1fd8fca23375 96 // collision functions
helioslyons 11:1fd8fca23375 97
helioslyons 11:1fd8fca23375 98 // NOTE 2: std::for_each could have been used instead of functions called on
helioslyons 11:1fd8fca23375 99 // all invaders, but I could not identify the correct syntax for apply this
helioslyons 11:1fd8fca23375 100 // to a vector of vectors of pointers.
helioslyons 11:1fd8fca23375 101
helioslyons 11:1fd8fca23375 102 //void Army::move_army()
helioslyons 11:1fd8fca23375 103
helioslyons 11:1fd8fca23375 104 // removed due to numerous errors, will be fixed if losing 5% is deemed
helioslyons 11:1fd8fca23375 105 // worth it
helioslyons 11:1fd8fca23375 106