Christopher Doel
/
el17cd
Cube Dodger A 3D 'endless runner' game
Game/Game.cpp@46:824ec81ff578, 2019-05-08 (annotated)
- 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?
User | Revision | Line number | New 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 | } |