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
Child:
13:1472c1637bfc
Helios A. Lyons 201239214;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
eencae 0:b7f1f47bb26a 1 /*
eencae 0:b7f1f47bb26a 2 ELEC2645 Embedded Systems Project
eencae 0:b7f1f47bb26a 3 School of Electronic & Electrical Engineering
eencae 0:b7f1f47bb26a 4 University of Leeds
eencae 0:b7f1f47bb26a 5 2019/20
eencae 0:b7f1f47bb26a 6
helioslyons 1:a3f43007030e 7 Name: Helios Ael Lyons
helioslyons 1:a3f43007030e 8 Username: mc18hal
helioslyons 1:a3f43007030e 9 Student ID Number: 201239214
helioslyons 1:a3f43007030e 10 Date: 24th March 2020
helioslyons 1:a3f43007030e 11 */
helioslyons 1:a3f43007030e 12
helioslyons 1:a3f43007030e 13 /** Main
helioslyons 11:1fd8fca23375 14 * @brief Start screen, menu, and game loop
helioslyons 1:a3f43007030e 15 * @author Helios A. Lyons
helioslyons 1:a3f43007030e 16 * @date March, 2020
eencae 0:b7f1f47bb26a 17 */
eencae 0:b7f1f47bb26a 18
helioslyons 10:19b250c7de5e 19 ///////// pre-processor directives ////////
eencae 0:b7f1f47bb26a 20 #include "mbed.h"
eencae 0:b7f1f47bb26a 21 #include "Gamepad.h"
eencae 0:b7f1f47bb26a 22 #include "N5110.h"
helioslyons 11:1fd8fca23375 23 #include "Bitmap.h"
helioslyons 10:19b250c7de5e 24 #include "Battle.h"
helioslyons 10:19b250c7de5e 25
helioslyons 10:19b250c7de5e 26 // structs
helioslyons 10:19b250c7de5e 27 struct UserInput {
helioslyons 10:19b250c7de5e 28 Direction d;
helioslyons 10:19b250c7de5e 29 float mag;
helioslyons 10:19b250c7de5e 30 };
helioslyons 11:1fd8fca23375 31
helioslyons 10:19b250c7de5e 32 // objects
helioslyons 10:19b250c7de5e 33 N5110 lcd;
helioslyons 10:19b250c7de5e 34 Gamepad pad;
helioslyons 10:19b250c7de5e 35 Battle battle;
helioslyons 11:1fd8fca23375 36 Canon player;
helioslyons 11:1fd8fca23375 37
helioslyons 11:1fd8fca23375 38 Timer playTime;
helioslyons 10:19b250c7de5e 39
helioslyons 10:19b250c7de5e 40 // prototypes
helioslyons 10:19b250c7de5e 41 void init();
helioslyons 10:19b250c7de5e 42 void update_game(UserInput input);
helioslyons 10:19b250c7de5e 43 void render();
helioslyons 10:19b250c7de5e 44 void welcome();
helioslyons 11:1fd8fca23375 45 void wave(int n);
helioslyons 11:1fd8fca23375 46 void game(Gamepad &pad);
helioslyons 11:1fd8fca23375 47 void menu(Gamepad &pad);
helioslyons 10:19b250c7de5e 48
helioslyons 10:19b250c7de5e 49 // functions
helioslyons 10:19b250c7de5e 50 int main()
helioslyons 11:1fd8fca23375 51 {
helioslyons 11:1fd8fca23375 52 //lcd.clear();
helioslyons 11:1fd8fca23375 53 init(); // initialise LCD and gamepad
helioslyons 11:1fd8fca23375 54
helioslyons 11:1fd8fca23375 55 welcome(); // display welcome screen
helioslyons 11:1fd8fca23375 56
helioslyons 11:1fd8fca23375 57 Menu_Point: // goto point after victory/defeat
helioslyons 11:1fd8fca23375 58 menu(pad);
helioslyons 11:1fd8fca23375 59
helioslyons 11:1fd8fca23375 60 battle.reset_life(); // start player lives at 3
helioslyons 11:1fd8fca23375 61 int n = 0;
helioslyons 10:19b250c7de5e 62
helioslyons 11:1fd8fca23375 63 while (n < 9) {
helioslyons 11:1fd8fca23375 64 n++;
helioslyons 11:1fd8fca23375 65 if (battle.life() < 1) { break; } // break condition for when player dies
helioslyons 11:1fd8fca23375 66 switch(n) {
helioslyons 11:1fd8fca23375 67 case 1: // initialise entities for the wave
helioslyons 11:1fd8fca23375 68 battle.init(1,3,4,3,0,3); // row,column,speed,firing interval,boss,bossNum
helioslyons 11:1fd8fca23375 69 battle.clock(pad); // start the invader firing pattern
helioslyons 11:1fd8fca23375 70 wave(n); // print wave #
helioslyons 11:1fd8fca23375 71 playTime.start(); // start timer before game starts
helioslyons 11:1fd8fca23375 72 game(pad); // start the main game loop
helioslyons 11:1fd8fca23375 73 playTime.stop(); // stop timer
helioslyons 11:1fd8fca23375 74 break;
helioslyons 11:1fd8fca23375 75
helioslyons 11:1fd8fca23375 76 case 2:
helioslyons 11:1fd8fca23375 77 battle.init(3,3,4,3,0,3); // init function is used this way to provide
helioslyons 11:1fd8fca23375 78 battle.clock(pad); // easy options to vary invader formation and number
helioslyons 11:1fd8fca23375 79 wave(n); // in wave
helioslyons 11:1fd8fca23375 80 playTime.start();
helioslyons 11:1fd8fca23375 81 game(pad);
helioslyons 11:1fd8fca23375 82 playTime.stop();
helioslyons 11:1fd8fca23375 83 break;
helioslyons 11:1fd8fca23375 84
helioslyons 11:1fd8fca23375 85 case 3:
helioslyons 11:1fd8fca23375 86 battle.init(1,1,3,2,1,1);
helioslyons 11:1fd8fca23375 87 battle.clock(pad);
helioslyons 11:1fd8fca23375 88 wave(n);
helioslyons 11:1fd8fca23375 89 playTime.start();
helioslyons 11:1fd8fca23375 90 game(pad);
helioslyons 11:1fd8fca23375 91 playTime.stop();
helioslyons 11:1fd8fca23375 92 break;
helioslyons 11:1fd8fca23375 93
helioslyons 11:1fd8fca23375 94 case 4:
helioslyons 11:1fd8fca23375 95 battle.init(2,3,3,3,0,1);
helioslyons 11:1fd8fca23375 96 battle.clock(pad);
helioslyons 11:1fd8fca23375 97 wave(n);
helioslyons 11:1fd8fca23375 98 playTime.start();
helioslyons 11:1fd8fca23375 99 game(pad);
helioslyons 11:1fd8fca23375 100 playTime.stop();
helioslyons 11:1fd8fca23375 101 break;
helioslyons 11:1fd8fca23375 102
helioslyons 11:1fd8fca23375 103 case 5:
helioslyons 11:1fd8fca23375 104 battle.init(3,3,3,3,0,1);
helioslyons 11:1fd8fca23375 105 battle.clock(pad);
helioslyons 11:1fd8fca23375 106 wave(n);
helioslyons 11:1fd8fca23375 107 playTime.start();
helioslyons 11:1fd8fca23375 108 game(pad);
helioslyons 11:1fd8fca23375 109 playTime.stop();
helioslyons 11:1fd8fca23375 110 break;
helioslyons 11:1fd8fca23375 111
helioslyons 11:1fd8fca23375 112 case 6:
helioslyons 11:1fd8fca23375 113 battle.init(1,1,2,1,1,2);
helioslyons 11:1fd8fca23375 114 battle.clock(pad);
helioslyons 11:1fd8fca23375 115 wave(n);
helioslyons 11:1fd8fca23375 116 playTime.start();
helioslyons 11:1fd8fca23375 117 game(pad);
helioslyons 11:1fd8fca23375 118 playTime.stop();
helioslyons 11:1fd8fca23375 119 break;
helioslyons 11:1fd8fca23375 120
helioslyons 11:1fd8fca23375 121 case 7:
helioslyons 11:1fd8fca23375 122 battle.init(3,4,2,3,0,2);
helioslyons 11:1fd8fca23375 123 battle.clock(pad);
helioslyons 11:1fd8fca23375 124 wave(n);
helioslyons 11:1fd8fca23375 125 playTime.start();
helioslyons 11:1fd8fca23375 126 game(pad);
helioslyons 11:1fd8fca23375 127 playTime.stop();
helioslyons 11:1fd8fca23375 128 break;
helioslyons 11:1fd8fca23375 129
helioslyons 11:1fd8fca23375 130 case 8:
helioslyons 11:1fd8fca23375 131 battle.init(3,6,3,2,0,2);
helioslyons 11:1fd8fca23375 132 battle.clock(pad);
helioslyons 11:1fd8fca23375 133 wave(n);
helioslyons 11:1fd8fca23375 134 playTime.start();
helioslyons 11:1fd8fca23375 135 game(pad);
helioslyons 11:1fd8fca23375 136 playTime.stop();
helioslyons 11:1fd8fca23375 137 break;
helioslyons 11:1fd8fca23375 138
helioslyons 11:1fd8fca23375 139 case 9:
helioslyons 11:1fd8fca23375 140 battle.init(1,1,1,1,1,3);
helioslyons 11:1fd8fca23375 141 battle.clock(pad);
helioslyons 11:1fd8fca23375 142 wave(n);
helioslyons 11:1fd8fca23375 143 playTime.start();
helioslyons 11:1fd8fca23375 144 game(pad);
helioslyons 11:1fd8fca23375 145 playTime.stop();
helioslyons 11:1fd8fca23375 146 break;
helioslyons 11:1fd8fca23375 147 } // end of switch statement
helioslyons 11:1fd8fca23375 148 }
helioslyons 11:1fd8fca23375 149
helioslyons 11:1fd8fca23375 150 if (battle.life() < 1) { // if player failed display game over
helioslyons 11:1fd8fca23375 151 lcd.printString("Game Over",16,2);
helioslyons 11:1fd8fca23375 152 lcd.refresh();
helioslyons 11:1fd8fca23375 153 wait(8.0);
helioslyons 11:1fd8fca23375 154 goto Menu_Point; // return to main menu after wait
helioslyons 11:1fd8fca23375 155 }
helioslyons 11:1fd8fca23375 156 else { // if waves are completed display time and victory screen
helioslyons 11:1fd8fca23375 157 lcd.printString("You won!",16,2);
helioslyons 11:1fd8fca23375 158 char buffer4[14];
helioslyons 11:1fd8fca23375 159 float time = sprintf(buffer4,"Time:%.2f",playTime.read());
helioslyons 11:1fd8fca23375 160 lcd.printString(buffer4,16,3);
helioslyons 11:1fd8fca23375 161 lcd.refresh();
helioslyons 11:1fd8fca23375 162 wait(8.0);
helioslyons 11:1fd8fca23375 163 goto Menu_Point; // return to main menu
helioslyons 11:1fd8fca23375 164 }
helioslyons 10:19b250c7de5e 165 }
eencae 0:b7f1f47bb26a 166
helioslyons 11:1fd8fca23375 167 void init() // initialises LCD and Gamepad
eencae 0:b7f1f47bb26a 168 {
helioslyons 10:19b250c7de5e 169 lcd.init();
helioslyons 10:19b250c7de5e 170 pad.init();
eencae 0:b7f1f47bb26a 171 }
eencae 0:b7f1f47bb26a 172
helioslyons 11:1fd8fca23375 173 void render() { // clears screen and re-draws content (+ current lives left)
helioslyons 11:1fd8fca23375 174 lcd.clear(); // called in the main game() loop
helioslyons 11:1fd8fca23375 175 battle.draw(lcd);
helioslyons 11:1fd8fca23375 176 lcd.refresh();
helioslyons 11:1fd8fca23375 177
helioslyons 11:1fd8fca23375 178 char buffer[4];
helioslyons 11:1fd8fca23375 179 int lives = sprintf(buffer,"%2d",battle.life());
helioslyons 11:1fd8fca23375 180 lcd.printString(buffer,0,5);
helioslyons 10:19b250c7de5e 181 lcd.refresh();
helioslyons 10:19b250c7de5e 182 }
helioslyons 10:19b250c7de5e 183
helioslyons 11:1fd8fca23375 184 void game(Gamepad &pad) { // main game loop, reads input and updates bullet / canon positions
helioslyons 11:1fd8fca23375 185 while (1) {
helioslyons 11:1fd8fca23375 186 int fps = 6;
helioslyons 11:1fd8fca23375 187 battle.read_input(pad);
helioslyons 11:1fd8fca23375 188 battle.update(pad);
helioslyons 11:1fd8fca23375 189 render();
helioslyons 11:1fd8fca23375 190 wait(1.0f/fps);
helioslyons 11:1fd8fca23375 191 if (battle.end() || battle.life() < 1 ) { break; }
helioslyons 11:1fd8fca23375 192 }
helioslyons 11:1fd8fca23375 193 lcd.clear();
helioslyons 11:1fd8fca23375 194 }
helioslyons 11:1fd8fca23375 195
helioslyons 11:1fd8fca23375 196 void wave(int n) { // prints wave number and time taken so far
helioslyons 11:1fd8fca23375 197 lcd.clear();
helioslyons 11:1fd8fca23375 198 char buffer[14];
helioslyons 11:1fd8fca23375 199 char buffer3[3];
helioslyons 11:1fd8fca23375 200 int number = sprintf(buffer,"Wave%2d",n);
helioslyons 11:1fd8fca23375 201 float time = sprintf(buffer3,"%.2f",playTime.read());
helioslyons 11:1fd8fca23375 202 lcd.printString(buffer,24,1);
helioslyons 11:1fd8fca23375 203 lcd.printString(buffer3,27,2);
helioslyons 11:1fd8fca23375 204
helioslyons 11:1fd8fca23375 205 lcd.refresh();
helioslyons 11:1fd8fca23375 206 wait(3.0);
helioslyons 11:1fd8fca23375 207 }
helioslyons 11:1fd8fca23375 208
helioslyons 11:1fd8fca23375 209 void welcome() { // bitmap logo and title for start screen
helioslyons 11:1fd8fca23375 210 static int logo[] = {
helioslyons 11:1fd8fca23375 211 0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
helioslyons 11:1fd8fca23375 212 0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
helioslyons 11:1fd8fca23375 213 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,
helioslyons 11:1fd8fca23375 214 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,
helioslyons 11:1fd8fca23375 215 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,
helioslyons 11:1fd8fca23375 216 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,
helioslyons 11:1fd8fca23375 217 0,0,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,0,0,
helioslyons 11:1fd8fca23375 218 0,0,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,0,0,
helioslyons 11:1fd8fca23375 219 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
helioslyons 11:1fd8fca23375 220 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
helioslyons 11:1fd8fca23375 221 1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,
helioslyons 11:1fd8fca23375 222 1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,
helioslyons 11:1fd8fca23375 223 1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,
helioslyons 11:1fd8fca23375 224 1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,
helioslyons 11:1fd8fca23375 225 0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
helioslyons 11:1fd8fca23375 226 0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0
helioslyons 11:1fd8fca23375 227 };
helioslyons 10:19b250c7de5e 228
helioslyons 11:1fd8fca23375 229 Bitmap canon_sprite(logo, 16, 22);
helioslyons 11:1fd8fca23375 230 canon_sprite.render(lcd,30,4);
helioslyons 11:1fd8fca23375 231
helioslyons 11:1fd8fca23375 232 lcd.printString("Space Invaders",0,3);
helioslyons 11:1fd8fca23375 233 lcd.printString("Press Start",8,4);
helioslyons 10:19b250c7de5e 234 lcd.refresh();
helioslyons 11:1fd8fca23375 235
helioslyons 11:1fd8fca23375 236 while (pad.start_pressed() == false) { // LEDs flash until start is pressed
helioslyons 11:1fd8fca23375 237 lcd.setContrast(pad.read_pot1());
helioslyons 10:19b250c7de5e 238 pad.leds_on();
helioslyons 10:19b250c7de5e 239 wait(0.1);
helioslyons 10:19b250c7de5e 240 pad.leds_off();
helioslyons 10:19b250c7de5e 241 wait(0.1);
helioslyons 10:19b250c7de5e 242 }
helioslyons 11:1fd8fca23375 243 }
helioslyons 11:1fd8fca23375 244
helioslyons 11:1fd8fca23375 245 void menu(Gamepad &pad) {
helioslyons 11:1fd8fca23375 246 while(1) {
helioslyons 11:1fd8fca23375 247 pad.reset_buttons();
helioslyons 11:1fd8fca23375 248 lcd.clear();
helioslyons 11:1fd8fca23375 249 lcd.printString("(A) Play",0,1);
helioslyons 11:1fd8fca23375 250 lcd.printString("(X) How To",0,2);
helioslyons 11:1fd8fca23375 251 lcd.printString("(B) Credits",0,3);
helioslyons 11:1fd8fca23375 252 lcd.refresh();
helioslyons 11:1fd8fca23375 253
helioslyons 11:1fd8fca23375 254 if (pad.X_pressed()) {
helioslyons 11:1fd8fca23375 255 lcd.clear();
helioslyons 11:1fd8fca23375 256 lcd.printString("Press A",0,2);
helioslyons 11:1fd8fca23375 257 lcd.printString("to shoot",0,3);
helioslyons 11:1fd8fca23375 258 lcd.refresh();
helioslyons 11:1fd8fca23375 259 wait(5.0);
helioslyons 11:1fd8fca23375 260
helioslyons 11:1fd8fca23375 261 lcd.clear();
helioslyons 11:1fd8fca23375 262 lcd.printString("Use the",0,1);
helioslyons 11:1fd8fca23375 263 lcd.printString("joystick to",0,2);
helioslyons 11:1fd8fca23375 264 lcd.printString("move left",0,3);
helioslyons 11:1fd8fca23375 265 lcd.printString("or right",0,4);
helioslyons 11:1fd8fca23375 266 lcd.refresh();
helioslyons 11:1fd8fca23375 267 wait(5.0);
helioslyons 11:1fd8fca23375 268
helioslyons 11:1fd8fca23375 269 lcd.clear();
helioslyons 11:1fd8fca23375 270 lcd.printString("Remaining ",0,1);
helioslyons 11:1fd8fca23375 271 lcd.printString("lives are on",0,2);
helioslyons 11:1fd8fca23375 272 lcd.printString("the bottom",0,3);
helioslyons 11:1fd8fca23375 273 lcd.printString("left",0,4);
helioslyons 11:1fd8fca23375 274 lcd.refresh();
helioslyons 11:1fd8fca23375 275 wait(5.0);
helioslyons 11:1fd8fca23375 276
helioslyons 11:1fd8fca23375 277 lcd.clear();
helioslyons 11:1fd8fca23375 278 lcd.printString("Elapsed time",0,1);
helioslyons 11:1fd8fca23375 279 lcd.printString("is shown at",0,2);
helioslyons 11:1fd8fca23375 280 lcd.printString("each wave",0,3);
helioslyons 11:1fd8fca23375 281 lcd.printString("interval",0,4);
helioslyons 11:1fd8fca23375 282 lcd.refresh();
helioslyons 11:1fd8fca23375 283 wait(5.0);
helioslyons 11:1fd8fca23375 284 }
helioslyons 11:1fd8fca23375 285 else if (pad.A_pressed()) {
helioslyons 11:1fd8fca23375 286 return;
helioslyons 11:1fd8fca23375 287 }
helioslyons 11:1fd8fca23375 288 else if (pad.B_pressed()) {
helioslyons 11:1fd8fca23375 289 lcd.clear();
helioslyons 11:1fd8fca23375 290 lcd.printString("Game by",0,2);
helioslyons 11:1fd8fca23375 291 lcd.printString("H.A. Lyons",0,3);
helioslyons 11:1fd8fca23375 292 lcd.refresh();
helioslyons 11:1fd8fca23375 293 wait(5.0);
helioslyons 11:1fd8fca23375 294 }
helioslyons 11:1fd8fca23375 295 }
helioslyons 11:1fd8fca23375 296
helioslyons 11:1fd8fca23375 297 }