My ELEC2645 joystick project Tetris Game NAME: JIANWEI CHEN SID: 200879849
Dependencies: N5110 SDFileSystem mbed
Game.h
- Committer:
- cjw851102
- Date:
- 2016-05-05
- Revision:
- 4:463abe5f5135
File content as of revision 4:463abe5f5135:
/** @file Game.h @brief Header file containing functions prototypes, defines and global variables for the tetris game. @brief Revision 1.0. @author JIANWEI CHEN @date May 2016 */ #ifndef GAME_H #define GAME_H #include "mbed.h" #include "Patterns.h" #include "N5110.h" #include "SDFileSystem.h" #include "main.h" //! Create patterns object Patterns patterns; /** Create ticker object for game @brief ticker to control the speed of game */ Ticker game; //////////////////////////////////////////////////////// // Variables //////////////////////////////////////////////////////// int xOld; /*!< Variable for storing the pattern previous position when game is runnung */ int typeCount = 0; /*!< Variable for counting elements in array typeArray[100]*/ int nextTypeCount; /*!< Variable to show the position of next element in typeArray[100] i.e. nextTypeCount=typeCount+1*/ /** Flag to show left hand side conllision of pattern @note flag = 0 - there is no collision on the left @note flag = 1 - there is collision on the left */ int left_collision_flag = 0; /** Flag to show right hand side conllision of pattern @note flag = 0 - there is no collision @note flag = 1 - there is collision */ int right_collision_flag = 0; /** Flag to show bottom conllision of pattern @note flag = 0 - there is no collision @note flag = 1 - there is collision */ int bottom_collision_flag = 0; /** Flag to show top conllision of pattern @note flag = 0 - there is no collision @note flag = 1 - there is collision */ int top_collision_flag = 0; /** Flag to show if there is pixels set on the 4 pixels distance away from the bottom of pattern @brief if flag = 0, user can pull joystick down to make pattern falling faster @note flag = 0 - there is no collision @note flag = 1 - there is collision */ int fastmove_bottom_collision_flag = 0; /** Flag to show if allow patterns to rotate @note flag = 0 - allow @note flag = 1 - not allow */ int rotation_collision_flag = 0; /** Two dimension array to store current pattern pixels setting in a 6x6 square @note For example, if current pattern is "L" @note the pixels setting is @note 1 1 0 0 0 0 @note 1 1 0 0 0 0 @note 1 1 0 0 0 0 @note 1 1 0 0 0 0 @note 1 1 1 1 0 0 @note 1 1 1 1 0 0 */ int pattern_buffer[6][6]; /** Array to store types of pattern @brief 100 random integers in the range of 0~6 @brief will be stored in the array in order to generate @brief random type of pattern each time new pattern is generated */ int typeArray[100]; int buffer[84][48]; /*!< Array to store whole screen pixel settings */ int score=0; /*!< Variable to store score in the game */ volatile int g_game_flag = 0; /*!< Flag for game ticker */ /** Struct for position @brief Contains the pattern position(x,y), @brief pattern type and rotation */ struct Position { float x; float y; int type; int rotation; }; typedef struct Position position; position pos; //////////////////////////////////////////////////////////////////////// // Functions //////////////////////////////////////////////////////////////////////// /** Game ticker isr function */ void game_isr(); /** Initialise the variables in game */ void init_game(); /** Drawing the pattern at position (x,y) @param type - type of pattern (0~6) @param rotation - rotation of pattern (0~3) @param x - x co-ordinate of pattern, which is the top left corner pixel of 6x6 square @param y - y co-ordinate of pattern, which is the top left corner pixel of 6x6 square @param fill - fill = 0 white, fill = 1 black */ void drawPattern(int type,int rotation,int x,int y,int fill); /**Left collision detect @brief Function to check the left collision of current falling pattern and set the left_collision_flag */ void left_collisionDetect(); /**Right collision detect @brief Function to check the right collision of current falling pattern and set the left_collision_flag */ void right_collisionDetect(); /**Bottom collision detect @brief Function to check the bottom collision of current falling pattern and set the right_collision_flag */ void bottom_collisionDetect(); /**top collision detect @brief Function to check the top collision of current falling pattern and set the top_collision_flag */ void top_collisionDetect(); /**Rotation collision detect @brief Function to check if the program should allow user to rotate the pattern and set the rotation_collision_flag */ void rotation_collisionDetect(); /**Fast move collision detect @brief Function to check if the program should allow user to move the pattern falling faster and set the fastmove_collision_flag @note check the 4 pixels distance away from the bottom of pattern */ void fastmove_bottom_collisionDetect(); /**Get pattern pixel settings @brief Function to get the current falling pattern pixel settings @note pixels setting will be store in pattern_buffer[6][6]; @param type - type of pattern (0~6) @param rotation - rotation of pattern (0~3) */ void get_pattern(int type, int rotatin); /**Scan the whole screen pixel settings @brief Function to store the whole screen pixel settings and store in buffer[84][48] */ void scan(); /** Cancel the filled lines and add the score @brief Function to check if there are lines filled @brief if one line is filled, cancel it and move the pixels above this line down and add the score */ void cancelLine(); /** Game finish animations */ void finishAnimation(); /** User press button when game is in process @brief When button pressed in the game, ask user if they want to exit the game @return TRUE - exit the game FALSE - contiute the game */ bool buttonPressedInGame(); /**Save the highest score to SD card @param score - a integer number need to save to SD card */ void save_score_SD(int score); /** Read the highest score from SD card */ int read_score_SD(); /** Complete tetris game */ void tetis_game(); ///////////////////////////////////////////////// /// Function Definitions ///////////////////////////////////////////////// void tetis_game() { bool exitGame; //bool variable to save the exit game decision when button pressed while (1) { if(g_game_flag==1) { g_game_flag = 0; exitGame=buttonPressedInGame(); //check if user press button and get the decision if(exitGame) { // exit game break; //jump out of while loop } pos.type = typeArray[typeCount]; //get the pattern type nextTypeCount=typeCount+1; if (nextTypeCount>99) { //start from the first element in type array nextTypeCount=0; } drawPattern(typeArray[nextTypeCount],0,55,41,1);// draw next pattern on the right hand side of screen if (pos.y >= -5) { // when pattern start falling, clear previous pattern drawPattern(pos.type,pos.rotation,xOld,pos.y-1,0); } updateJoystick(); //get the joystick direction top_collisionDetect(); // check if current pattern touch the top if (top_collision_flag == 1) { // if touch the top, finish the game red_led=1; green_led=0; //play sound at end of game for(double i=1; i>=0; i-=0.1) { buzzer = i; wait(0.2); } buzzer = 0; finishAnimation(); //finish animation lcd.clear(); int stored_score=read_score_SD(); if (score>stored_score) { // if score is larger than highest score, save it to SD card save_score_SD(score); } // show the score char scoreBuffer[14]; sprintf(scoreBuffer,"%d",score); lcd.printString("SCORE IS: ",10,2); lcd.printString(scoreBuffer,35,4); lcd.refresh(); wait(3.0); lcd.clear(); state=0; // back to the main menu break; } //move patterns according to joystick direction switch(joystick.direction) { case UP: // rotation rotation_collision_flag = 0; rotation_collisionDetect(); // check if allow rotation if(rotation_collision_flag == 0) { // allow rotation pos.rotation++; if (pos.rotation>3) { pos.rotation=0; } drawPattern(pos.type,pos.rotation,pos.x,pos.y,1); } else {// not allow rotation drawPattern(pos.type,pos.rotation,pos.x,pos.y,1); } break; case DOWN: // faster moving down fastmove_bottom_collision_flag = 0; fastmove_bottom_collisionDetect(); if (fastmove_bottom_collision_flag == 0) {// allow faster move pos.y +=4; // move pattern down by 4 pixels distance drawPattern(pos.type,pos.rotation,pos.x,pos.y,1); } else { drawPattern(pos.type,pos.rotation,pos.x,pos.y,1); } break; case RIGHT: // move right right_collision_flag = 0; right_collisionDetect(); // detect right collision if( right_collision_flag == 0) { // allow move right pos.x +=2; drawPattern(pos.type,pos.rotation,pos.x,pos.y,1); } else { // not allow move right drawPattern(pos.type,pos.rotation,pos.x,pos.y,1); right_collision_flag = 0; } break; case LEFT: //move left left_collision_flag = 0; left_collisionDetect(); // detect left collision if( left_collision_flag == 0) {// allow move left pos.x -=2; drawPattern(pos.type,pos.rotation,pos.x,pos.y,1); } else { // not allow move left drawPattern(pos.type,pos.rotation,pos.x,pos.y,1); left_collision_flag = 0; } break; case CENTRE: // joystick in centre drawPattern(pos.type,pos.rotation,pos.x,pos.y,1); break; case UNKNOWN: drawPattern(pos.type,pos.rotation,pos.x,pos.y,1); break; } xOld = pos.x; //store previous pattern x co-codinate bottom_collisionDetect(); // bottom collision detect if (bottom_collision_flag == 0) { // no collision pos.y++; // keep moving pattern down buzzer = 0; // turn off buzzer } else { // bottom collision drawPattern(pos.type,pos.rotation,pos.x,pos.y,1); // fix pattern cancelLine(); // check filled lines and add score pos.x = 10; // new pattern will fall from the centre pos.y = -6; pos.rotation=0; drawPattern(typeArray[nextTypeCount],pos.rotation,55,41,0);// clear the old next pattern show on RHS of screen typeCount ++; //new type of pattern if (typeCount >99) { typeCount = 0; } } lcd.refresh(); } sleep(); // go to sleep mode unless ticker interupt } } void init_game() { pos.x = 10; pos.y = -6; pos.rotation=0; typeCount=0; green_led=1; // turn on green led //generate 100 random integers in the range of 0~6 //and store in typeArray for(int i=0; i<=99; i++) { typeArray[i] = rand()%7; } //gaming screen lcd.drawLine(30,0,30,47,1); lcd.printString("Level:",42,0); lcd.printString("Score:",42,2); lcd.printString("0",42,3); lcd.printString("Next:",42,4); //play sound at begining of game for(double i=0; i<=1.0; i+=0.1) { buzzer = i; wait(0.2); } buzzer = 0; } void get_pattern(int type, int rotation) { for(int i=0; i<=5; i++) { for(int j=0; j<=5; j++) {// patterns.getPatterns(type,rotation,j,i) return pattern[type][rotation][y][x]; pattern_buffer[i][j] = patterns.getPatterns(type,rotation,j,i); } } } void scan() { //screen has 84x48 pixels for (int i=0; i<=83; i++) { for (int j=0; j<=47; j++) { if(lcd.getPixel(i,j)) { //if pixel is set buffer[i][j] = 1; } else { // pixel is clear buffer[i][j] = 0; } } } } // draw pattern at (x,y) void drawPattern(int type,int rotation,int x,int y,int fill) { get_pattern(type,rotation); // get the pattern pixel settings, which store in pattern_buffer for(int i=x; i <= x+5; i++) { // (x,y) is the left top point of a 6*6 square for(int j=y; j <= y+5; j++) { if (j>=0) { if(pattern_buffer[i-x][j-y]==1) {//pixel setting is 1 if (fill==0) { //draw white pattern if (j<=47 && i>=0) { // draw pattern inside the screen lcd.clearPixel(i,j); } } else if (fill==1) { //draw black pattern if (j<=47 && i>=0) { lcd.setPixel(i,j); } } } } } } } void left_collisionDetect() { int left_boundary[6][6]; get_pattern(pos.type,pos.rotation); /* get the left boundary pixel settings e.g: if pattern is L left boundary is 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 */ for (int j=0; j<=5; j++) { // for (int i=0; i<=5; i++) { if (pattern_buffer[i][j]==1) { left_boundary[i][j]=1; for(int k=i+1; k<=5; k++) { left_boundary[k][j] = 0; } break; } else { left_boundary[i][j]=0; } } } //check left collision int x = pos.x; int y = pos.y; if (x<0) { //for all the pattern, when x<0, pattern is on the most LHS of screen left_collision_flag = 1; } else { //check the pixel status away from left boundary for one pixel distance for(int i=x; i <= x+5; i++) { // (x,y) is the left top point of a 6*6 square for(int j=y; j <= y+5; j++) { if(left_boundary[i-x][j-y]==1) { if(i == 0) { // pattern at most LHS of screen left_collision_flag = 1; break; // don't need to check the other pixels at same x, jump out of inner for loop } else if (lcd.getPixel(i-1,j)) { //check one pixel away from left boundary left_collision_flag = 1; break; } else { left_collision_flag = 0; } } } if (left_collision_flag == 1) { break;// jump out of inner for loop } } } } void right_collisionDetect() { int right_boundary[6][6]; get_pattern(pos.type,pos.rotation); /* get the right boundary pixel settings e.g: if pattern is L left boundary is 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 */ for (int j=0; j<=5; j++) { for (int i=5; i>=0; i--) { if (pattern_buffer[i][j]==1) { right_boundary[i][j]=1; for(int k=i-1; k>=0; k--) { right_boundary[k][j] = 0; } break; } else { right_boundary[i][j]=0; } } } //check right collision int x = pos.x; int y = pos.y; for(int i = x; i <= x+5; i++) { // (x,y) is the left top point of a 6*6 square for(int j=y; j <= y+5; j++) { if(right_boundary[i-x][j-y]==1) { if(j>=0) { if(i >= 29) { // most RHS of gaming screen right_collision_flag = 1; break; } else if (lcd.getPixel(i+1,j)) {//check the pixel status away from right boundary for one pixel distance right_collision_flag = 1; break; } else { right_collision_flag = 0; } } } } if (right_collision_flag == 1) { break; } } } void bottom_collisionDetect() { int bot_boundary[6][6]; get_pattern(pos.type,pos.rotation); /* get the left boundary pixel settings e.g: if pattern is L left boundary is 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 */ for (int i=0; i<=5; i++) { for (int j=5; j>=0; j--) { if (pattern_buffer[i][j]==1) { bot_boundary[i][j]=1; for(int k=j-1; k>=0; k--) { bot_boundary[i][k] = 0; } break; } else { bot_boundary[i][j]=0; } } } //check bottom collision int x = pos.x; int y = pos.y; for(int i = x; i <= x+5; i++) { //check from left for(int j=y+5; j >= y; j--) { //check from bottom if (j>=-1) { //start check when pattern fall in the screen if(bot_boundary[i-x][j-y]==1) { if(j >= 47) { // pattern at bottom bottom_collision_flag = 1; break; // jump out of inner for loop } else if (lcd.getPixel(i,j+1)) {//check the pixel status away from bottom boundary for one pixel distance bottom_collision_flag = 1; break; } else { bottom_collision_flag = 0; } } } else { //at bottom of screen bottom_collision_flag = 0; } } if( bottom_collision_flag == 1) { break; // jump out of inner for loop } } } void rotation_collisionDetect() { int rotation = pos.rotation+1; if (rotation>3) { rotation=0; } get_pattern(pos.type,rotation); //check pixel status of upcoming rotation int x = pos.x; int y = pos.y; for(int i = x; i <= x+5; i++) { // (x,y) is the left top point of a 6*6 square for(int j=y; j <= y+5; j++) { if(pattern_buffer[i-x][j-y]==1) { if(i<0) { // out of LHS screen rotation_collision_flag = 1; } else if(lcd.getPixel(i,j)) { // there is pixel set rotation_collision_flag = 1; break; //jump out of inner for loop } else { rotation_collision_flag = 0; } } } if (rotation_collision_flag == 1) { break; //jump out of inner for loop } } } void top_collisionDetect() { if (pos.y==-6) { //pattern is about to fall bottom_collisionDetect(); if (bottom_collision_flag == 1) { //if can't fall top_collision_flag = 1; // top collision } else { top_collision_flag = 0; } } } void fastmove_bottom_collisionDetect() { int bot_boundary[6][6]; get_pattern(pos.type,pos.rotation); // get the bottom boundary pattern for (int i=0; i<=5; i++) { for (int j=5; j>=0; j--) { if (pattern_buffer[i][j]==1) { bot_boundary[i][j]=1; for(int k=j-1; k>=0; k--) { bot_boundary[i][k] = 0; } break; } else { bot_boundary[i][j]=0; } } } //check bottom collision for 4 pixel distance away from bottom boundary int x = pos.x; int y = pos.y; for(int i = x; i <= x+5; i++) { // (x,y) is the left top point of a 6*6 square for(int j=y+5; j >= y; j--) { if (j>=-1) { if(bot_boundary[i-x][j-y]==1) { if(j >= 42) { // pattern is about to fall on the bottom fastmove_bottom_collision_flag = 1; break; } else if (lcd.getPixel(i,j+4)) {//check bottom collision for 4 pixel distance away from bottom boundary fastmove_bottom_collision_flag = 1; break; } else { fastmove_bottom_collision_flag = 0; } } } else { fastmove_bottom_collision_flag = 0; } } if( fastmove_bottom_collision_flag == 1) { break; } } } void game_isr() { g_game_flag = 1; } void cancelLine() { // int linePattern[30][2]; //the pixel setting for one line(30x2 square) int count; // count setting pixels two by two for(int j=0; j<=46; j+=2) { for(int i=0; i<=29; i++) { if (lcd.getPixel(i,j)==0||lcd.getPixel(i,j+1)==0) { // there is clear pixel count=0; break; } else if (lcd.getPixel(i,j)&&lcd.getPixel(i,j+1)) { count++; } } if(count==30) { // one line is filled count=0; // reset the variable count lcd.drawRect(0,j,29,1,2); //clear the line buzzer = 0.5; score+=10; // add the score //update the score char scoreBuffer[14]; sprintf(scoreBuffer,"%d",score); lcd.printString(scoreBuffer,42,3); scan(); // move the patterns above the line down for 2 pixels' hight for (int x=0; x<=29; x++) { for (int y=j; y>=0; y--) { if (buffer[x][y]) { lcd.clearPixel(x,y); lcd.setPixel(x,y+2); } } } } } } void finishAnimation() { for (int j=47; j>=0; j--) { lcd.drawRect(0,j,29,1,1); wait(0.05); lcd.refresh(); } } bool buttonPressedInGame() { bool exit_game; if (g_button_flag) { // user press button finish game g_button_flag=0; scan(); // save the currnet gaming screen game.detach(); // detach the game ticker lcd.clear(); while(1) { lcd.printString("Exit The Game?",1,1); lcd.printString("YES",38,3); lcd.printString("NO",38,4); pointer(); // invoke pointer function if (g_button_flag) { g_button_flag=0; if(pointer_position==0) { //"YES" -exit game lcd.clear(); state=0; // back to main menu pointer_position=0; exit_game=true; int stored_score=read_score_SD(); if (score>stored_score) { // if the score is higher than highest score, save it save_score_SD(score); } score=0; //clear socre red_led=1; green_led=0; break; } else { //"NO" - continue the game exit_game=false; if(state==3) { // game level is easy lcd.clear(); for(int i=0; i<=83; i++) { // back to the gaming screen before press button for(int j=0; j<=47; j++) { if(buffer[i][j]) { lcd.setPixel(i,j); } } } game.attach(&game_isr,0.2); // easy game exit_game=false; break; } else if(state==4) {// game level is hard lcd.clear(); for(int i=0; i<=83; i++) {// back to the gaming screen before press button for(int j=0; j<=47; j++) { if(buffer[i][j]) { lcd.setPixel(i,j); } } } game.attach(&game_isr,0.1);// hard game break; } } break; } } } if(exit_game) { return true; } else { return false; } } int read_score_SD() { fp = fopen("/sd/topscore.txt", "r"); //open file int stored_top_score; fscanf(fp, "%d",&stored_top_score); // ensure data type matches - note address operator (&) fclose(fp); // ensure you close the file after reading return stored_top_score; } void save_score_SD(int score) { fp = fopen("/sd/topscore.txt", "w"); fprintf(fp, "%d",score); // ensure data type matches fclose(fp); // ensure you close the file after writing } #endif