ELEC2645 (2017/18) / Mbed OS el16ajm
Committer:
Andrew_M
Date:
Tue May 08 14:06:47 2018 +0000
Revision:
15:130900e5c268
Parent:
14:a57a40ff9430
Child:
16:4d329ce7b156
Added a large amount of explanatory comments

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Andrew_M 1:a14415de3ad5 1 #include "Engine.h"
Andrew_M 1:a14415de3ad5 2
Andrew_M 1:a14415de3ad5 3 Engine::Engine()
Andrew_M 1:a14415de3ad5 4 {
Andrew_M 1:a14415de3ad5 5
Andrew_M 1:a14415de3ad5 6 }
Andrew_M 1:a14415de3ad5 7
Andrew_M 1:a14415de3ad5 8 Engine::~Engine()
Andrew_M 1:a14415de3ad5 9 {
Andrew_M 1:a14415de3ad5 10
Andrew_M 1:a14415de3ad5 11 }
Andrew_M 1:a14415de3ad5 12
Andrew_M 2:9ca5e1c221c3 13 void Engine::init() // initialise the game parameters
Andrew_M 1:a14415de3ad5 14 {
Andrew_M 12:d3eef5ea3f43 15 _solid.init(10,15);
Andrew_M 12:d3eef5ea3f43 16 _noodles.init(10,10);
Andrew_M 12:d3eef5ea3f43 17 _gameOver = false;
Andrew_M 12:d3eef5ea3f43 18 lvlTwo() ;
Andrew_M 12:d3eef5ea3f43 19 }
Andrew_M 12:d3eef5ea3f43 20 void Engine::setLvl(int _levelToSet)
Andrew_M 12:d3eef5ea3f43 21 {
Andrew_M 15:130900e5c268 22 _lvl = _levelToSet; // sets the current level, this is used when the menu changes the currently selected level
Andrew_M 12:d3eef5ea3f43 23 }
Andrew_M 12:d3eef5ea3f43 24
Andrew_M 12:d3eef5ea3f43 25 void Engine::loadLvl()
Andrew_M 12:d3eef5ea3f43 26 {
Andrew_M 15:130900e5c268 27 if (_lvl == 1) { //checks to see what level should be loaded
Andrew_M 12:d3eef5ea3f43 28 lvlOne();
Andrew_M 13:81573be8fac6 29 } else if (_lvl == 2) {
Andrew_M 12:d3eef5ea3f43 30 lvlTwo();
Andrew_M 13:81573be8fac6 31 } else if (_lvl == 3) {
Andrew_M 12:d3eef5ea3f43 32 lvlThree();
Andrew_M 12:d3eef5ea3f43 33 }
Andrew_M 12:d3eef5ea3f43 34 }
Andrew_M 12:d3eef5ea3f43 35
Andrew_M 12:d3eef5ea3f43 36 void Engine::lvlOne()
Andrew_M 12:d3eef5ea3f43 37 {
Andrew_M 15:130900e5c268 38 memset(_grid, 0, sizeof(_grid)); //clears the grid as it is a blank level
Andrew_M 12:d3eef5ea3f43 39 }
Andrew_M 12:d3eef5ea3f43 40
Andrew_M 12:d3eef5ea3f43 41 void Engine::lvlTwo()
Andrew_M 12:d3eef5ea3f43 42 {
Andrew_M 12:d3eef5ea3f43 43 int _newGrid[22][22] = {
Andrew_M 12:d3eef5ea3f43 44 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 45 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 46 {0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0},
Andrew_M 12:d3eef5ea3f43 47 {0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0},
Andrew_M 12:d3eef5ea3f43 48 {0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
Andrew_M 12:d3eef5ea3f43 49 {0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
Andrew_M 12:d3eef5ea3f43 50 {0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
Andrew_M 12:d3eef5ea3f43 51 {0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
Andrew_M 12:d3eef5ea3f43 52 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 53 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 54 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 55 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 56 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 57 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 58 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 59 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 60 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 61 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 62 {0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
Andrew_M 12:d3eef5ea3f43 63 {0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
Andrew_M 12:d3eef5ea3f43 64 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 65 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
Andrew_M 12:d3eef5ea3f43 66 };
Andrew_M 12:d3eef5ea3f43 67
Andrew_M 15:130900e5c268 68 /*
Andrew_M 15:130900e5c268 69 To load a set level, the level is first created as a new 2d array. It is set values for each coordinate
Andrew_M 15:130900e5c268 70 Then the functional array has the values of _newGrid set to it individually
Andrew_M 15:130900e5c268 71 */
Andrew_M 12:d3eef5ea3f43 72 for(int i = 0; i < 22; i++) {
Andrew_M 12:d3eef5ea3f43 73 for (int j = 0; j < 22; j++) {
Andrew_M 12:d3eef5ea3f43 74 _grid[i][j] = _newGrid[i][j];
Andrew_M 12:d3eef5ea3f43 75 }
Andrew_M 12:d3eef5ea3f43 76 }
Andrew_M 12:d3eef5ea3f43 77 }
Andrew_M 12:d3eef5ea3f43 78
Andrew_M 12:d3eef5ea3f43 79 void Engine::lvlThree()
Andrew_M 12:d3eef5ea3f43 80 {
Andrew_M 12:d3eef5ea3f43 81 int _newGrid[22][22] = {
Andrew_M 12:d3eef5ea3f43 82 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 83 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 84 {0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 85 {0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0},
Andrew_M 12:d3eef5ea3f43 86 {0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0},
Andrew_M 12:d3eef5ea3f43 87 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0},
Andrew_M 12:d3eef5ea3f43 88 {0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0},
Andrew_M 12:d3eef5ea3f43 89 {0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0},
Andrew_M 12:d3eef5ea3f43 90 {0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 91 {0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 92 {0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 93 {0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 94 {0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 95 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
Andrew_M 12:d3eef5ea3f43 96 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
Andrew_M 12:d3eef5ea3f43 97 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
Andrew_M 12:d3eef5ea3f43 98 {0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
Andrew_M 12:d3eef5ea3f43 99 {0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
Andrew_M 12:d3eef5ea3f43 100 {0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
Andrew_M 12:d3eef5ea3f43 101 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 102 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
Andrew_M 12:d3eef5ea3f43 103 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
Andrew_M 12:d3eef5ea3f43 104 };
Andrew_M 12:d3eef5ea3f43 105
Andrew_M 12:d3eef5ea3f43 106 for(int i = 0; i < 22; i++) {
Andrew_M 12:d3eef5ea3f43 107 for (int j = 0; j < 22; j++) {
Andrew_M 12:d3eef5ea3f43 108 _grid[i][j] = _newGrid[i][j];
Andrew_M 12:d3eef5ea3f43 109 }
Andrew_M 12:d3eef5ea3f43 110 }
Andrew_M 1:a14415de3ad5 111 }
Andrew_M 1:a14415de3ad5 112
Andrew_M 1:a14415de3ad5 113 void Engine::read_input(Gamepad &pad)
Andrew_M 1:a14415de3ad5 114 {
Andrew_M 15:130900e5c268 115 _d = pad.get_direction(); //_d stores the direction that the joystick is pushed in for later use
Andrew_M 1:a14415de3ad5 116 }
Andrew_M 1:a14415de3ad5 117
Andrew_M 1:a14415de3ad5 118 void Engine::draw(N5110 &lcd)
Andrew_M 1:a14415de3ad5 119 {
Andrew_M 15:130900e5c268 120 lcd.drawRect(0,0,48,48,FILL_TRANSPARENT); //draws a square around the 'play area'
Andrew_M 15:130900e5c268 121
Andrew_M 15:130900e5c268 122 for (int j = 0; j < 22; j++) { //goes through each coordinate in the grid,
Andrew_M 2:9ca5e1c221c3 123 for (int i = 0; i < 22; i++) {
Andrew_M 15:130900e5c268 124 if (_grid[i][j] != 0) { //checks if the current square is NOT empty
Andrew_M 15:130900e5c268 125 lcd.drawRect((2 * i) + 2,(2 * j) + 2,2,2,FILL_BLACK); //if the above is true a 2x2 square will be drawn in the allocated location (the grid is scalled up 2x with a 2 pixel gap arround the edge)
Andrew_M 2:9ca5e1c221c3 126 }
Andrew_M 2:9ca5e1c221c3 127 }
Andrew_M 2:9ca5e1c221c3 128 }
Andrew_M 11:b25874e7efe4 129
Andrew_M 15:130900e5c268 130 lcd.printString("Score",50,0);
Andrew_M 7:c1e0593bfc99 131
Andrew_M 7:c1e0593bfc99 132
Andrew_M 15:130900e5c268 133 int _score = (_solid.getLength() - 3); //gets the score from the current snake length, it defualts to lenght 3 and increases with each food eaten. Therefor the length will allways be 3 more than the score
Andrew_M 7:c1e0593bfc99 134
Andrew_M 15:130900e5c268 135 char buffer1[21]; //buffer used for changing ints to strings
Andrew_M 15:130900e5c268 136 sprintf(buffer1,"%3d",_score); //changes _score to a 3 letter string
Andrew_M 15:130900e5c268 137 lcd.printString(buffer1,50,1); //prints the new string in the top right of the screen
Andrew_M 12:d3eef5ea3f43 138 }
Andrew_M 12:d3eef5ea3f43 139
Andrew_M 12:d3eef5ea3f43 140 void Engine::gameOverScreen(N5110 &lcd)
Andrew_M 12:d3eef5ea3f43 141 {
Andrew_M 15:130900e5c268 142 for (int i = 0; i < 22; i++) { //covers every square of the grid
Andrew_M 12:d3eef5ea3f43 143 for (int j = 0; j < 22; j++) {
Andrew_M 15:130900e5c268 144 lcd.drawRect((2 * i) + 2,(2 * j) + 2,2,2,FILL_BLACK); //draws a 2x2 square ontop of whatever is drawn in the cooridnates of the grid at the current time
Andrew_M 15:130900e5c268 145 wait(0.01); //slight delay to allow the screen to keep up
Andrew_M 15:130900e5c268 146 lcd.refresh(); //refreshes the screen but doesn't clear it, the intention is to get an overlay effect
Andrew_M 5:a3a9e0417e04 147 }
Andrew_M 11:b25874e7efe4 148 }
Andrew_M 1:a14415de3ad5 149 }
Andrew_M 1:a14415de3ad5 150
Andrew_M 1:a14415de3ad5 151 void Engine::update(Gamepad &pad)
Andrew_M 1:a14415de3ad5 152 {
Andrew_M 15:130900e5c268 153 loadLvl(); //loads the level
Andrew_M 15:130900e5c268 154
Andrew_M 15:130900e5c268 155 _solid.update(_d); //updates the coordinates of the snake
Andrew_M 3:6253a2d374fa 156
Andrew_M 15:130900e5c268 157 checkGameOverAndSetGrid(); //checks if a game over state has been reached, if not set the new coordinates for the snake
Andrew_M 14:a57a40ff9430 158
Andrew_M 15:130900e5c268 159 _grid[_noodles.getY()][_noodles.getY()] = 2; //sets the current location of the food to the grid, stored as a 2 to differentiate it from the terrrain and tail
Andrew_M 14:a57a40ff9430 160
Andrew_M 15:130900e5c268 161 if (checkFood()) { //checks if the head has reached food
Andrew_M 15:130900e5c268 162
Andrew_M 15:130900e5c268 163 pad.tone(750.0,0.1); //plays a beep to signify that the snake has eaten
Andrew_M 14:a57a40ff9430 164
Andrew_M 15:130900e5c268 165 growSnake(); //grows the snake as it has eaten the food
Andrew_M 15:130900e5c268 166
Andrew_M 15:130900e5c268 167 bool empty = false; //makes a varible for finding an empty square
Andrew_M 14:a57a40ff9430 168
Andrew_M 14:a57a40ff9430 169 while (!empty) { //loops until empty square found
Andrew_M 15:130900e5c268 170
Andrew_M 14:a57a40ff9430 171 _noodles.random(); //randomise position of noodles
Andrew_M 15:130900e5c268 172
Andrew_M 14:a57a40ff9430 173 if ( _grid[_noodles.getY()][_noodles.getY()] == 0) {
Andrew_M 15:130900e5c268 174
Andrew_M 14:a57a40ff9430 175 empty = true; //stops looping when free space is found
Andrew_M 14:a57a40ff9430 176 // no need to set the grid as it will put the noodles in the new location the next time 'update' is called
Andrew_M 14:a57a40ff9430 177 }
Andrew_M 14:a57a40ff9430 178
Andrew_M 14:a57a40ff9430 179 }
Andrew_M 14:a57a40ff9430 180 }
Andrew_M 14:a57a40ff9430 181 }
Andrew_M 14:a57a40ff9430 182
Andrew_M 14:a57a40ff9430 183 void Engine::checkGameOverAndSetGrid()
Andrew_M 14:a57a40ff9430 184 {
Andrew_M 3:6253a2d374fa 185
Andrew_M 15:130900e5c268 186 int _l =_solid.getLength(); //stores the length of the snake to make it easier to debug
Andrew_M 3:6253a2d374fa 187
Andrew_M 15:130900e5c268 188 for (int z = 0; z < _l; z++) { //checks the entire lenght of the snake
Andrew_M 11:b25874e7efe4 189
Andrew_M 15:130900e5c268 190 if (_solid.getX(z) > 21 || _solid.getX(z) < 0) { //checks if the x coordinate is out of bounds
Andrew_M 11:b25874e7efe4 191 _gameOver = true;
Andrew_M 15:130900e5c268 192 } else if (_solid.getY(z) > 21 || _solid.getY(z) < 0) { //checks if the y coordinate is out of bounds
Andrew_M 11:b25874e7efe4 193 _gameOver = true;
Andrew_M 11:b25874e7efe4 194 }
Andrew_M 11:b25874e7efe4 195
Andrew_M 15:130900e5c268 196 if (_grid[_solid.getX(z)][_solid.getY(z)] != 1) { //checks if the square the snake has moved to is clear
Andrew_M 15:130900e5c268 197 _grid[_solid.getX(z)][_solid.getY(z)] = 1; //if so sets the current square to be occupied
Andrew_M 5:a3a9e0417e04 198 } else {
Andrew_M 15:130900e5c268 199 _gameOver = true; //if not a game over state has been reached
Andrew_M 5:a3a9e0417e04 200 }
Andrew_M 5:a3a9e0417e04 201 }
Andrew_M 1:a14415de3ad5 202 }
Andrew_M 5:a3a9e0417e04 203
Andrew_M 13:81573be8fac6 204 bool Engine::checkFood()
Andrew_M 13:81573be8fac6 205 {
Andrew_M 15:130900e5c268 206 if (_grid[_solid.getX(0)][_solid.getY(0)] == 2) { //checks if the head has reached food
Andrew_M 13:81573be8fac6 207 return true;
Andrew_M 13:81573be8fac6 208 } else {
Andrew_M 13:81573be8fac6 209 return false;
Andrew_M 13:81573be8fac6 210 }
Andrew_M 13:81573be8fac6 211 }
Andrew_M 13:81573be8fac6 212
Andrew_M 15:130900e5c268 213 void Engine::growSnake()
Andrew_M 13:81573be8fac6 214 {
Andrew_M 13:81573be8fac6 215 if (_solid.getLength()<484) { //checks if the snake can grow any more
Andrew_M 13:81573be8fac6 216
Andrew_M 13:81573be8fac6 217 _solid.grow(); //makes snake longer
Andrew_M 13:81573be8fac6 218
Andrew_M 13:81573be8fac6 219 }
Andrew_M 15:130900e5c268 220
Andrew_M 15:130900e5c268 221 //If the snake cannot grow any more the player has won the game and filled every tile with the snake, this is extremly unlikely to happen and a game over state will be reached
Andrew_M 15:130900e5c268 222 //I feel no need to implement a victory screen due to how unlikey this is to happen
Andrew_M 13:81573be8fac6 223 }
Andrew_M 13:81573be8fac6 224
Andrew_M 13:81573be8fac6 225 float Engine::getScore()
Andrew_M 12:d3eef5ea3f43 226 {
Andrew_M 11:b25874e7efe4 227 return _score;
Andrew_M 12:d3eef5ea3f43 228 }
Andrew_M 12:d3eef5ea3f43 229
Andrew_M 11:b25874e7efe4 230
Andrew_M 12:d3eef5ea3f43 231 bool Engine::getGameOver()
Andrew_M 12:d3eef5ea3f43 232 {
Andrew_M 12:d3eef5ea3f43 233 return _gameOver;
Andrew_M 12:d3eef5ea3f43 234 }
Andrew_M 12:d3eef5ea3f43 235