Cube Dodger A 3D 'endless runner' game

Dependencies:   mbed

Committer:
el17cd
Date:
Wed May 08 18:17:59 2019 +0000
Revision:
46:824ec81ff578
Parent:
39:41dcf1604fdf
Potentiometer now changes screen contrast for use on other devices.; Final Submission.; I have read and agreed with the Statement of Academic Integrity.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
el17cd 15:8fbbdefbe720 1 #include "Game.h"
el17cd 32:9c250eda7f3f 2
el17cd 30:91038c2afec7 3 SDFileSystem sd(PTE3, PTE1, PTE2, PTE4, "sd"); // MOSI, MISO, SCK, CS
el17cd 19:ec4cb22accb0 4
el17cd 26:8a85aede976d 5 Serial pc(USBTX, USBRX); // tx, rx
el17cd 26:8a85aede976d 6
el17cd 15:8fbbdefbe720 7 Game::Game(){
el17cd 25:3995271e411c 8 noOfCubes = 25; //How many cubes are in the scene
el17cd 31:e681177037ef 9 menuSelections.homeMenuSelection = 0; //default selection for the home screen
el17cd 15:8fbbdefbe720 10 gamepad.init();
el17cd 15:8fbbdefbe720 11 renderer.init();
el17cd 26:8a85aede976d 12 resetScene();
el17cd 31:e681177037ef 13 helpScreenNumber = -1; //Set help screen to inactive (-1)
el17cd 30:91038c2afec7 14 input.x = 0; //Set joystick input to 0
el17cd 30:91038c2afec7 15 input.bCooldown = input.yCooldown = input.aCooldown = false; //Allow buttons to be pressed
el17cd 31:e681177037ef 16 menuSelections.deathMenuSelection = 0; //Set death menu to highlight restart option
el17cd 30:91038c2afec7 17 highScore = readHighScore();
el17cd 26:8a85aede976d 18 }
el17cd 26:8a85aede976d 19
el17cd 26:8a85aede976d 20 void Game::resetScene(){
el17cd 25:3995271e411c 21 for(int i = 0; i < noOfCubes; i++){ //Set initial position of all cubes
el17cd 39:41dcf1604fdf 22 cubeArray[i].translate(rand()%250-125, 0, 10 + i*5); //Position will be based on random integers
el17cd 15:8fbbdefbe720 23 }
el17cd 15:8fbbdefbe720 24 }
el17cd 15:8fbbdefbe720 25
el17cd 30:91038c2afec7 26 int Game::readHighScore(){
el17cd 30:91038c2afec7 27 int highScore = 0;
el17cd 30:91038c2afec7 28 filePointer = fopen("/sd/el17cdHighScore.txt", "r");
el17cd 30:91038c2afec7 29
el17cd 29:4a02f0bae202 30 if (filePointer != NULL) {
el17cd 30:91038c2afec7 31 fscanf(filePointer, "%d", &highScore); //read integer from sd card file
el17cd 30:91038c2afec7 32 fclose(filePointer);
el17cd 29:4a02f0bae202 33 }
el17cd 30:91038c2afec7 34 return highScore;;
el17cd 29:4a02f0bae202 35 }
el17cd 29:4a02f0bae202 36
el17cd 29:4a02f0bae202 37 void Game::writeHighScore(int score){
el17cd 30:91038c2afec7 38 filePointer = fopen("/sd/el17cdHighScore.txt", "w");
el17cd 30:91038c2afec7 39
el17cd 29:4a02f0bae202 40 if (filePointer != NULL) {
el17cd 30:91038c2afec7 41 fprintf(filePointer, "%d", score); //write integer to sd card file
el17cd 30:91038c2afec7 42 fclose(filePointer);
el17cd 29:4a02f0bae202 43 }
el17cd 29:4a02f0bae202 44 }
el17cd 29:4a02f0bae202 45
el17cd 29:4a02f0bae202 46
el17cd 15:8fbbdefbe720 47 void Game::run(){
el17cd 30:91038c2afec7 48 inHomeMenu = true; //Start at home screen
el17cd 18:8256546a3cbf 49 score = 0;
el17cd 26:8a85aede976d 50 playing = true; //set game state to playing and death screen selection to 'restart'
el17cd 26:8a85aede976d 51 while(true) {
el17cd 30:91038c2afec7 52 processInput(); //process user input and store values in input struct
el17cd 26:8a85aede976d 53 renderer.clear();
el17cd 31:e681177037ef 54 if(helpScreenNumber > -1){
el17cd 30:91038c2afec7 55 helpScreen(); //Show the help screen if the help screen number is above -1
el17cd 27:e46af658c67a 56 }
el17cd 28:f8ff7c8c1627 57 else if(inHomeMenu){
el17cd 26:8a85aede976d 58 homeScreen();
el17cd 26:8a85aede976d 59 }
el17cd 26:8a85aede976d 60 else{
el17cd 26:8a85aede976d 61 play();
el17cd 15:8fbbdefbe720 62 }
el17cd 26:8a85aede976d 63 renderer.refresh(); //refresh lcd
el17cd 25:3995271e411c 64 }
el17cd 25:3995271e411c 65 }
el17cd 25:3995271e411c 66
el17cd 26:8a85aede976d 67 void Game::play(){
el17cd 26:8a85aede976d 68 renderer.drawHorizon(input.x/15); //draw the horizon line
el17cd 26:8a85aede976d 69
el17cd 26:8a85aede976d 70 for (int c = 0; c< noOfCubes; c++){
el17cd 26:8a85aede976d 71 moveCubes(&cubeArray[c]); //translate cubes depending on joystick location and score
el17cd 26:8a85aede976d 72 cubeToBeRendered(&cubeArray[c], c); //add all cube faces to array to later be rendered
el17cd 46:824ec81ff578 73 checkDespawn(&cubeArray[c]); //check if any cubes are behind the perspective, then respawn them
el17cd 26:8a85aede976d 74 checkDeath(&cubeArray[c]); //check if any cubes are too close to user
el17cd 26:8a85aede976d 75 }
el17cd 26:8a85aede976d 76 renderer.drawAllFaces(faceArray, noOfCubes, input.x); //draw all faces added to the face array
el17cd 26:8a85aede976d 77 displayDeathMenu(); //display death menu if cube is too close to user
el17cd 26:8a85aede976d 78 addScore();
el17cd 29:4a02f0bae202 79 renderer.printScore(score, 0, 0); //print score on top left of screen
el17cd 26:8a85aede976d 80 }
el17cd 26:8a85aede976d 81
el17cd 25:3995271e411c 82 void Game::checkDespawn(Cube *cube){ //checks if the cube is behind the perspective
el17cd 25:3995271e411c 83 if (cube->despawn()){
el17cd 25:3995271e411c 84 cube->resetPos(); //reset position to origin
el17cd 25:3995271e411c 85 cube->translate(rand()%250-125,0,140); //translate cube to new far away position
el17cd 25:3995271e411c 86 }
el17cd 25:3995271e411c 87 }
el17cd 25:3995271e411c 88
el17cd 25:3995271e411c 89 void Game::checkDeath(Cube *cube){ //Check whether the user has hit a cube
el17cd 25:3995271e411c 90 if (cube->tooClose()){
el17cd 25:3995271e411c 91 playing = false; //set state of game to not playing
el17cd 25:3995271e411c 92 cube->resetPos();
el17cd 25:3995271e411c 93 cube->translate(rand()%250-125,0,140); //reset and translate cube to back position
el17cd 15:8fbbdefbe720 94 }
el17cd 15:8fbbdefbe720 95 }
el17cd 18:8256546a3cbf 96
el17cd 25:3995271e411c 97 void Game::cubeToBeRendered(Cube *cube, int cubeIndex){ //Adds all faces within the cube to an array of faces to be rendered
el17cd 25:3995271e411c 98 for (int i = 0; i < 6; i++){
el17cd 25:3995271e411c 99 faceArray[cubeIndex*6 + i] = cube->getFace(i);
el17cd 25:3995271e411c 100 }
el17cd 25:3995271e411c 101 }
el17cd 25:3995271e411c 102
el17cd 29:4a02f0bae202 103
el17cd 25:3995271e411c 104 void Game::moveCubes(Cube *cube){ //animate cubes
el17cd 25:3995271e411c 105 if(playing){
el17cd 30:91038c2afec7 106 if(score < 6000)
el17cd 26:8a85aede976d 107 cube->translate(-input.x*1.4f,0,-1-(float)score/1000); //move cubes closer to user and in x axis depending on joystick pos
el17cd 25:3995271e411c 108 else{
el17cd 26:8a85aede976d 109 cube->translate(-input.x*1.4f,0,-3); //once max speed reached maintain constant z speed
el17cd 25:3995271e411c 110 }
el17cd 25:3995271e411c 111 }
el17cd 25:3995271e411c 112 else{
el17cd 31:e681177037ef 113 input.x = 0; //if not playing (dead) prevent joystick moving anything
el17cd 25:3995271e411c 114 }
el17cd 25:3995271e411c 115 }
el17cd 25:3995271e411c 116
el17cd 29:4a02f0bae202 117 void Game::displayDeathMenu() { //display restart or back to home menu
el17cd 25:3995271e411c 118 if(!playing){
el17cd 29:4a02f0bae202 119 if(score > highScore) {
el17cd 29:4a02f0bae202 120 highScore = score;
el17cd 29:4a02f0bae202 121 writeHighScore(highScore);
el17cd 29:4a02f0bae202 122 }
el17cd 31:e681177037ef 123 renderer.drawDeathScreen(menuSelections.deathMenuSelection, highScore); //draw death screen if game over
el17cd 26:8a85aede976d 124 deathButtonSelections(); //select menu option
el17cd 25:3995271e411c 125 }
el17cd 26:8a85aede976d 126
el17cd 25:3995271e411c 127 }
el17cd 25:3995271e411c 128
el17cd 25:3995271e411c 129 void Game::addScore(){ //increment score by 1 each frame
el17cd 26:8a85aede976d 130 if(playing){
el17cd 26:8a85aede976d 131 score++; //add score if still playing
el17cd 26:8a85aede976d 132 }
el17cd 21:6b5d2d75e083 133 }
el17cd 21:6b5d2d75e083 134
el17cd 25:3995271e411c 135 void Game::resetScore(){ //reset score to 0
el17cd 21:6b5d2d75e083 136 score = 0;
el17cd 21:6b5d2d75e083 137 }
el17cd 22:236319885874 138
el17cd 25:3995271e411c 139 void Game::deathButtonSelections(){ //determine selection on death screen
el17cd 26:8a85aede976d 140 if(input.yButton){ //if y pressed highlight top option (restart)
el17cd 31:e681177037ef 141 menuSelections.deathMenuSelection = 0;
el17cd 18:8256546a3cbf 142 }
el17cd 26:8a85aede976d 143 else if(input.aButton){ //if a pressed highlight bottom option (home menu)
el17cd 31:e681177037ef 144 menuSelections.deathMenuSelection = 1;
el17cd 18:8256546a3cbf 145 }
el17cd 31:e681177037ef 146 if (menuSelections.deathMenuSelection == 0 && input.bButton){ //if top option highlighted and b pressed then restart game
el17cd 18:8256546a3cbf 147 playing = true;
el17cd 18:8256546a3cbf 148 score = 0;
el17cd 21:6b5d2d75e083 149 resetScore();
el17cd 26:8a85aede976d 150 resetScene();
el17cd 18:8256546a3cbf 151 }
el17cd 31:e681177037ef 152 else if(menuSelections.deathMenuSelection == 1 && input.bButton){ //if bottom option highlighted and b pressed then go to home screen
el17cd 21:6b5d2d75e083 153 resetScore();
el17cd 28:f8ff7c8c1627 154 inHomeMenu = true;
el17cd 18:8256546a3cbf 155 }
el17cd 18:8256546a3cbf 156 }
el17cd 18:8256546a3cbf 157
el17cd 25:3995271e411c 158 void Game::homeButtonSelections(){ //determine selection on home screen
el17cd 31:e681177037ef 159 if(input.yButton && menuSelections.homeMenuSelection > 0){ //if top option isnt highlighted and y pressed then move highlight up
el17cd 31:e681177037ef 160 menuSelections.homeMenuSelection--;
el17cd 18:8256546a3cbf 161 }
el17cd 31:e681177037ef 162 else if(input.aButton && menuSelections.homeMenuSelection < 2){ //if bottom option isnt highlighted and a pressed then move highlight down
el17cd 31:e681177037ef 163 menuSelections.homeMenuSelection++;
el17cd 18:8256546a3cbf 164 }
el17cd 31:e681177037ef 165 if (input.bButton && menuSelections.homeMenuSelection == 0){ //if top highlighted and b pressed then start game
el17cd 28:f8ff7c8c1627 166 inHomeMenu = false;
el17cd 30:91038c2afec7 167 playing = true;
el17cd 18:8256546a3cbf 168 }
el17cd 31:e681177037ef 169 else if(input.bButton && menuSelections.homeMenuSelection == 1){ //if bottom highlighted and b pressed then exit game
el17cd 31:e681177037ef 170 helpScreenNumber = 1;
el17cd 26:8a85aede976d 171 }
el17cd 31:e681177037ef 172 else if(input.bButton && menuSelections.homeMenuSelection == 2){ //if bottom highlighted and b pressed then exit game
el17cd 26:8a85aede976d 173 renderer.turnOff();
el17cd 26:8a85aede976d 174 exit(0);
el17cd 18:8256546a3cbf 175 }
el17cd 18:8256546a3cbf 176 }
el17cd 18:8256546a3cbf 177
el17cd 30:91038c2afec7 178 void Game::homeScreen(){//draw home screen
el17cd 26:8a85aede976d 179 homeButtonSelections(); //determine selection on home screen
el17cd 31:e681177037ef 180 renderer.drawHomeScreen(menuSelections.homeMenuSelection);
el17cd 27:e46af658c67a 181 }
el17cd 27:e46af658c67a 182
el17cd 30:91038c2afec7 183 void Game::helpScreen(){ //Show help screen depending on help screen number
el17cd 31:e681177037ef 184 if (helpScreenNumber == 1) {
el17cd 27:e46af658c67a 185 renderer.drawHelpScreen1();
el17cd 27:e46af658c67a 186 checkNextHelpScreen();
el17cd 27:e46af658c67a 187 }
el17cd 31:e681177037ef 188 else if (helpScreenNumber == 2) {
el17cd 30:91038c2afec7 189 renderer.drawHelpScreen2();
el17cd 27:e46af658c67a 190 checkNextHelpScreen();
el17cd 27:e46af658c67a 191 }
el17cd 31:e681177037ef 192 else if (helpScreenNumber == 3) {
el17cd 27:e46af658c67a 193 renderer.drawHelpScreen3();
el17cd 27:e46af658c67a 194 checkNextHelpScreen();
el17cd 27:e46af658c67a 195 }
el17cd 31:e681177037ef 196 else if (helpScreenNumber == 4) {
el17cd 31:e681177037ef 197 renderer.drawHelpScreen4();
el17cd 31:e681177037ef 198 checkNextHelpScreen();
el17cd 31:e681177037ef 199
el17cd 31:e681177037ef 200 }
el17cd 31:e681177037ef 201 else if (helpScreenNumber == 5) { //if past last screen then set help screen number to disabled (-1)
el17cd 31:e681177037ef 202 helpScreenNumber = -1;
el17cd 27:e46af658c67a 203 }
el17cd 27:e46af658c67a 204 }
el17cd 27:e46af658c67a 205
el17cd 30:91038c2afec7 206 void Game::checkNextHelpScreen(){ //if a button pressed then advance help screen
el17cd 27:e46af658c67a 207 if(input.bButton){
el17cd 31:e681177037ef 208 helpScreenNumber ++;
el17cd 27:e46af658c67a 209 }
el17cd 26:8a85aede976d 210 }
el17cd 26:8a85aede976d 211
el17cd 30:91038c2afec7 212 void Game::processInput(){ //Obtain user inputs and store in input struct
el17cd 46:824ec81ff578 213 renderer.setContrast(gamepad.read_pot()); //Set the contrast of the screen based on the pot
el17cd 30:91038c2afec7 214 input.x = gamepad.get_coord().x; //Get value of joystick x axis
el17cd 46:824ec81ff578 215 bool y = gamepad.check_event(Gamepad::Y_PRESSED); //Get Y, A, B button states
el17cd 26:8a85aede976d 216 bool a = gamepad.check_event(Gamepad::A_PRESSED);
el17cd 26:8a85aede976d 217 bool b = gamepad.check_event(Gamepad::B_PRESSED);
el17cd 26:8a85aede976d 218
el17cd 26:8a85aede976d 219 disableYButton(y);
el17cd 26:8a85aede976d 220 disableAButton(a);
el17cd 26:8a85aede976d 221 disableBButton(b);
el17cd 26:8a85aede976d 222 }
el17cd 26:8a85aede976d 223
el17cd 31:e681177037ef 224 void Game::disableYButton(bool y){ //Set y button to disabled, call function to reenable in 0.2 seconds
el17cd 26:8a85aede976d 225 if(!input.yCooldown && y){
el17cd 26:8a85aede976d 226 input.yCooldown = true;
el17cd 31:e681177037ef 227 disableY.attach(callback(this, &Game::enableY), 0.2); //attach function to ticker to renable y button
el17cd 26:8a85aede976d 228 input.yButton = true;
el17cd 26:8a85aede976d 229 }
el17cd 26:8a85aede976d 230 else{
el17cd 26:8a85aede976d 231 input.yButton = false;
el17cd 18:8256546a3cbf 232 }
el17cd 18:8256546a3cbf 233 }
el17cd 26:8a85aede976d 234
el17cd 31:e681177037ef 235 void Game::disableAButton(bool a){ //Set a button to disabled, call function to reenable in 0.2 seconds
el17cd 26:8a85aede976d 236 if(!input.aCooldown && a){
el17cd 26:8a85aede976d 237 input.aCooldown = true;
el17cd 31:e681177037ef 238 disableA.attach(callback(this, &Game::enableA), 0.2); //attach function to ticker to renable a button
el17cd 26:8a85aede976d 239 input.aButton = true;
el17cd 26:8a85aede976d 240 }
el17cd 26:8a85aede976d 241 else{
el17cd 26:8a85aede976d 242 input.aButton = false;
el17cd 26:8a85aede976d 243 }
el17cd 26:8a85aede976d 244 }
el17cd 26:8a85aede976d 245
el17cd 31:e681177037ef 246 void Game::disableBButton(bool b){ //Set b button to disabled, call function to reenable in 0.2 seconds
el17cd 26:8a85aede976d 247 if(!input.bCooldown && b){
el17cd 26:8a85aede976d 248 input.bCooldown = true;
el17cd 31:e681177037ef 249 disableB.attach(callback(this, &Game::enableB), 0.2); //attach function to ticker to renable b button
el17cd 26:8a85aede976d 250 input.bButton = true;
el17cd 26:8a85aede976d 251 }
el17cd 26:8a85aede976d 252 else{
el17cd 26:8a85aede976d 253 input.bButton = false;
el17cd 26:8a85aede976d 254 }
el17cd 26:8a85aede976d 255 }
el17cd 26:8a85aede976d 256
el17cd 30:91038c2afec7 257 void Game::enableY(){ //reenable y button
el17cd 30:91038c2afec7 258 disableY.detach(); //detach ticker so function only runs once
el17cd 30:91038c2afec7 259 input.yCooldown = false;
el17cd 30:91038c2afec7 260 }
el17cd 30:91038c2afec7 261
el17cd 30:91038c2afec7 262 void Game::enableA(){ //reenable a button
el17cd 30:91038c2afec7 263 disableA.detach(); //detach ticker so function only runs once
el17cd 26:8a85aede976d 264 input.aCooldown = false;
el17cd 26:8a85aede976d 265 }
el17cd 26:8a85aede976d 266
el17cd 30:91038c2afec7 267 void Game::enableB(){ //reenable b button
el17cd 30:91038c2afec7 268 disableB.detach(); //detach ticker so function only runs once
el17cd 26:8a85aede976d 269 input.bCooldown = false;
el17cd 26:8a85aede976d 270 }