ELEC2645 (2017/18) / Mbed OS el16ajm
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Engine.cpp Source File

Engine.cpp

00001 #include "Engine.h"
00002 
00003 Engine::Engine()
00004 {
00005 
00006 }
00007 
00008 Engine::~Engine()
00009 {
00010 
00011 }
00012 
00013 void Engine::init()     // initialise the game parameters
00014 {
00015 
00016     gameTest();
00017 
00018     _solid.init(10,15);
00019     _noodles.init(10,10);
00020     _gameOver = false;
00021 
00022     printf("Engine initialised\n");
00023 }
00024 void Engine::setLvl(int _levelToSet)
00025 {
00026     _lvl = _levelToSet; // sets the current level, this is used when the menu changes the currently selected level
00027 }
00028 
00029 void Engine::loadLvl()
00030 {
00031     if (_lvl == 1) { //checks to see what level should be loaded
00032         lvlOne();
00033     } else if (_lvl == 2) {
00034         lvlTwo();
00035     } else if (_lvl == 3) {
00036         lvlThree();
00037     }
00038     printf("Level Loaded\n");
00039 }
00040 
00041 void Engine::lvlOne()
00042 {
00043     memset(_grid, 0, sizeof(_grid)); //clears the grid as it is a blank level
00044 }
00045 
00046 void Engine::lvlTwo()
00047 {
00048     int _newGrid[22][22] = {
00049         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00050         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00051         {0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0},
00052         {0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0},
00053         {0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
00054         {0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
00055         {0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
00056         {0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
00057         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00058         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00059         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00060         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00061         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00062         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00063         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00064         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00065         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00066         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00067         {0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
00068         {0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
00069         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00070         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
00071     };
00072 
00073     /*
00074     To load a set level, the level is first created as a new 2d array. It is set values for each coordinate
00075     Then the functional array has the values of _newGrid set to it individually
00076     */
00077     for(int i = 0; i < 22; i++) {
00078         for (int j = 0; j < 22; j++) {
00079             _grid[i][j] = _newGrid[i][j];
00080         }
00081     }
00082 }
00083 
00084 void Engine::lvlThree()
00085 {
00086     int _newGrid[22][22] = {
00087         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00088         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00089         {0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
00090         {0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0},
00091         {0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0},
00092         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0},
00093         {0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0},
00094         {0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0},
00095         {0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00096         {0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00097         {0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00098         {0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00099         {0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00100         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
00101         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
00102         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
00103         {0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
00104         {0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
00105         {0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0},
00106         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00107         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
00108         {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
00109     };
00110 
00111     for(int i = 0; i < 22; i++) {
00112         for (int j = 0; j < 22; j++) {
00113             _grid[i][j] = _newGrid[i][j];
00114         }
00115     }
00116 }
00117 
00118 void Engine::read_input(Gamepad &pad)
00119 {
00120     _d = pad.get_direction(); //_d stores the direction that the joystick is pushed in for later use
00121 }
00122 
00123 void Engine::draw(N5110 &lcd)
00124 {
00125     lcd.drawRect(0,0,48,48,FILL_TRANSPARENT);                           //draws a square around the 'play area'
00126 
00127     for (int j = 0; j < 22; j++) {                                      //goes through each coordinate in the grid,
00128         for (int i = 0; i < 22; i++) {
00129             if (_grid[i][j] != 0) {                                     //checks if the current square is NOT empty
00130                 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)
00131             }
00132         }
00133     }
00134 
00135     lcd.printString("Score",50,0);
00136 
00137 
00138     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
00139 
00140     char buffer1[21];                           //buffer used for changing ints to strings
00141     sprintf(buffer1,"%3d",_score);              //changes _score to a 3 letter string
00142     lcd.printString(buffer1,50,1);              //prints the new string in the top right of the screen
00143 }
00144 
00145 void Engine::gameOverScreen(N5110 &lcd)
00146 {
00147     printf("GameOver\n");
00148     for (int i = 0; i < 22; i++) {                                  //covers every square of the grid
00149         for (int j = 0; j < 22; j++) {
00150             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
00151             wait(0.01);                                             //slight delay to allow the screen to keep up
00152             lcd.refresh();                                          //refreshes the screen but doesn't clear it, the intention is to get an overlay effect
00153         }
00154     }
00155 }
00156 
00157 void Engine::update(Gamepad &pad)
00158 {
00159     loadLvl(); //loads the level
00160 
00161     _solid.update(_d); //updates the coordinates of the snake
00162 
00163     checkGameOverAndSetGrid(); //checks if a game over state has been reached, if not set the new coordinates for the snake
00164 
00165     _grid[_noodles.getX()][_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
00166 
00167     if (checkFood()) { //checks if the head has reached food
00168 
00169         pad.tone(750.0,0.1); //plays a beep to signify that the snake has eaten
00170 
00171         growSnake(); //grows the snake as it has eaten the food
00172 
00173         bool empty = false; //makes a varible for finding an empty square
00174 
00175         while (!empty) {    //loops until empty square found
00176 
00177             _noodles.random(); //randomise position of noodles
00178 
00179             if ( _grid[_noodles.getX()][_noodles.getY()] == 0) {
00180 
00181                 empty = true; //stops looping when free space is found
00182                 // no need to set the grid as it will put the noodles in the new location the next time 'update' is called
00183             }
00184 
00185         }
00186     }
00187 }
00188 
00189 void Engine::checkGameOverAndSetGrid()
00190 {
00191 
00192     int _l =_solid.getLength();                                 //stores the length of the snake to make it easier to debug
00193 
00194     for (int z = 0; z < _l; z++) {                              //checks the entire lenght of the snake
00195 
00196         if (_solid.getX(z) > 21 || _solid.getX(z) < 0) {        //checks if the x coordinate is out of bounds
00197             _gameOver = true;
00198         } else if (_solid.getY(z) > 21 || _solid.getY(z) < 0) { //checks if the y coordinate is out of bounds
00199             _gameOver = true;
00200         }
00201 
00202         if (_grid[_solid.getX(z)][_solid.getY(z)] != 1) {       //checks if the square the snake has moved to is clear
00203             _grid[_solid.getX(z)][_solid.getY(z)] = 1;          //if so sets the current square to be occupied
00204         } else {
00205             _gameOver = true;                                   //if not a game over state has been reached
00206         }
00207     }
00208 }
00209 
00210 bool Engine::checkFood()
00211 {
00212     if (_grid[_solid.getX(0)][_solid.getY(0)] == 2) { //checks if the head has reached food
00213         return true;
00214     } else {
00215         return false;
00216     }
00217 }
00218 
00219 void Engine::growSnake()
00220 {
00221     if (_solid.getLength()<484) { //checks if the snake can grow any more
00222 
00223         _solid.grow();  //makes snake longer
00224 
00225     }
00226 
00227     //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
00228     //I feel no need to implement a victory screen due to how unlikey this is to happen
00229 }
00230 
00231 float Engine::getScore()
00232 {
00233     return _score;
00234 }
00235 
00236 
00237 bool Engine::getGameOver()
00238 {
00239     return _gameOver;
00240 }
00241 
00242 void  Engine::gameTest()
00243 {
00244     printf("Testing...\n");
00245     if (!snakeTest()) {
00246         printf("Some game tests failed!\n");
00247     } else if (!foodTest()) {
00248         printf("Some game tests failed!\n");
00249     } else {
00250         printf("All game tests passed!\n");
00251     }
00252 }
00253 
00254 bool  Engine::snakeTest()
00255 {
00256     //checks if the grow function and initalisation works corectly
00257 
00258     _solid.init(12,10);
00259 
00260     bool _testState = true;
00261 
00262     _solid.grow();
00263     _solid.grow();
00264 
00265     int _testLength = _solid.getLength();
00266 
00267     if ( _testLength != 5) { //checks if the snake has grown
00268         _testState = false;
00269     }
00270     if ( _solid.getY(0) != 10) { //checks the coordiantes of each snake section to check they are in the correct place
00271         _testState = false;
00272     }
00273     if ( _solid.getX(0) != 12) {
00274         _testState = false;
00275     }
00276     if ( _solid.getY(1) != 11) {
00277         _testState = false;
00278     }
00279     if ( _solid.getX(1) != 12) {
00280         _testState = false;
00281     }
00282     if ( _solid.getY(2) != 12) {
00283         _testState = false;
00284     }
00285     if ( _solid.getX(2) != 12) {
00286         _testState = false;
00287     }
00288 
00289     return _testState;
00290 
00291 }
00292 
00293 bool  Engine::foodTest()
00294 {
00295     //checks if the radomise function works correctly for the food
00296 
00297     bool _testState = true;
00298 
00299     _noodles.init(7,3);
00300 
00301     _grid[_noodles.getX()][_noodles.getY()] = 2; //sets the grid value so that the randomise loop will work correctly
00302 
00303 
00304 
00305     bool empty = false; //makes a varible for finding an empty square
00306 
00307     while (!empty) {    //loops until empty square found
00308 
00309         _noodles.random(); //randomise position of noodles
00310 
00311         if ( _grid[_noodles.getX()][_noodles.getY()] == 0) {
00312 
00313             empty = true; //stops looping when free space is found
00314             // no need to set the grid as it will put the noodles in the new location the next time 'update' is called
00315         }
00316 
00317     }
00318 
00319 
00320     if (_noodles.getX() ==7 && _noodles.getY() == 3) { //checks to see if randomised correctly
00321         _testState = false; //fail
00322     }
00323 
00324     return _testState;
00325 }