Snake and Physics based jumping game with high scores and different difficulties.

Dependencies:   N5110 SDFileSystem mbed

Committer:
el14jw
Date:
Wed May 04 15:01:20 2016 +0000
Revision:
5:ae641b1d04fa
Parent:
4:c2d920b17b14
Snake and Physics based jumping game

Who changed what in which revision?

UserRevisionLine numberNew contents of line
el14jw 0:23a749719479 1 /**
el14jw 0:23a749719479 2 2645 Project Games
el14jw 0:23a749719479 3 @file main.cpp
el14jw 0:23a749719479 4
el14jw 0:23a749719479 5 @brief Program Implementation
el14jw 5:ae641b1d04fa 6 @brief Revision 1.1
el14jw 0:23a749719479 7 @author Joel W. Webb
el14jw 0:23a749719479 8 */
el14jw 0:23a749719479 9
el14jw 0:23a749719479 10 #include "main.h"
el14jw 0:23a749719479 11
el14jw 0:23a749719479 12
el14jw 0:23a749719479 13 // Joystick Polling code taken from joystick example code
el14jw 0:23a749719479 14 /// Enumerated type to store joystick direction
el14jw 0:23a749719479 15 enum DirectionName {
el14jw 0:23a749719479 16 UP,
el14jw 0:23a749719479 17 DOWN,
el14jw 0:23a749719479 18 LEFT,
el14jw 0:23a749719479 19 RIGHT,
el14jw 0:23a749719479 20 CENTRE,
el14jw 0:23a749719479 21 UNKNOWN
el14jw 0:23a749719479 22 };
el14jw 0:23a749719479 23
el14jw 0:23a749719479 24 /// Struct for storing data about default Joystick position and Current position
el14jw 0:23a749719479 25 struct JoyStick {
el14jw 0:23a749719479 26 float x; // current x value
el14jw 0:23a749719479 27 float x0; // 'centred' x value
el14jw 0:23a749719479 28 float y; // current y value
el14jw 0:23a749719479 29 float y0; // 'centred' y value
el14jw 0:23a749719479 30 DirectionName direction; // current direction
el14jw 0:23a749719479 31 };
el14jw 0:23a749719479 32 typedef struct JoyStick Joystick;
el14jw 5:ae641b1d04fa 33 /// Global Joystick struct for storing data about default Joystick position and Current position
el14jw 0:23a749719479 34 Joystick joystick;
el14jw 5:ae641b1d04fa 35
el14jw 0:23a749719479 36 /// Ticker interrput for polling the joystick
el14jw 0:23a749719479 37 Ticker pollJoystick;
el14jw 4:c2d920b17b14 38 /// Ticker for controlling refresh rate of games
el14jw 2:80a91a737e17 39 Ticker gametick;
el14jw 5:ae641b1d04fa 40 /// Ticker for sctrolling the refresh rate of the display
el14jw 5:ae641b1d04fa 41 Ticker screentick;
el14jw 4:c2d920b17b14 42 /// File pointer for accessing SD card locations
el14jw 5:ae641b1d04fa 43 FILE *fp = NULL;
el14jw 0:23a749719479 44
el14jw 0:23a749719479 45
el14jw 0:23a749719479 46 int main()
el14jw 0:23a749719479 47 {
el14jw 0:23a749719479 48 initInputs();
el14jw 0:23a749719479 49 playSound(tune_intro);
el14jw 0:23a749719479 50
el14jw 4:c2d920b17b14 51 int snakeDifficulty = 1;
el14jw 1:c4928de1f922 52 int plinkDifficulty = 0;
el14jw 0:23a749719479 53 while (true) {
el14jw 1:c4928de1f922 54
el14jw 0:23a749719479 55 // Main menu screen
el14jw 1:c4928de1f922 56 int select = menu(menuList,3);
el14jw 0:23a749719479 57
el14jw 0:23a749719479 58 // Selected Snake
el14jw 0:23a749719479 59 if (select == 0) {
el14jw 1:c4928de1f922 60 // If select = 3 or -1 then user has chosen 'Back' button
el14jw 1:c4928de1f922 61 while( !(select == 3 || select ==-1) ) {
el14jw 0:23a749719479 62
el14jw 0:23a749719479 63 // Snake selection screen
el14jw 1:c4928de1f922 64 select = menu(snakeList,5);
el14jw 1:c4928de1f922 65 if (select == 0) {
el14jw 1:c4928de1f922 66 // Play Snake game
el14jw 1:c4928de1f922 67 snake(snakeDifficulty);
el14jw 1:c4928de1f922 68 }
el14jw 0:23a749719479 69 // Selected Difficulty
el14jw 1:c4928de1f922 70 else if (select == 1) {
el14jw 0:23a749719479 71 // Difficulty selection screen
el14jw 1:c4928de1f922 72 int tempdiff = snakeDifficulty;
el14jw 1:c4928de1f922 73 snakeDifficulty = menu(difficultyList,4);
el14jw 1:c4928de1f922 74 if (snakeDifficulty == -1) {
el14jw 1:c4928de1f922 75 snakeDifficulty = tempdiff;
el14jw 1:c4928de1f922 76 }
el14jw 0:23a749719479 77 }
el14jw 1:c4928de1f922 78 // Highscore
el14jw 1:c4928de1f922 79 else if (select == 2) {
el14jw 1:c4928de1f922 80 fp = fopen("/sd/snakehighscore.txt", "r");
el14jw 1:c4928de1f922 81 wait(0.05);
el14jw 1:c4928de1f922 82 int stored_top_score = -1; // -1 to demonstrate it has changed after reading
el14jw 1:c4928de1f922 83
el14jw 1:c4928de1f922 84 lcd.clear();
el14jw 1:c4928de1f922 85 if (fp == NULL) { // if it can't open the file then print error message
el14jw 1:c4928de1f922 86 lcd.printString("No Results",0,0);
el14jw 1:c4928de1f922 87 wait(2.0);
el14jw 1:c4928de1f922 88 } else { // opened file so can write
el14jw 5:ae641b1d04fa 89 while ( ! (g_buttonA_flag | g_buttonjoy_flag)) {
el14jw 1:c4928de1f922 90 fscanf(fp,"%d",&stored_top_score); // ensure data type matches - note address operator (&)
el14jw 1:c4928de1f922 91 fclose(fp); // ensure you close the file after reading
el14jw 1:c4928de1f922 92 lcd.printString("Highscore:",10,0);
el14jw 1:c4928de1f922 93 if (stored_top_score != -2) {
el14jw 1:c4928de1f922 94 char buffer[14];
el14jw 1:c4928de1f922 95 sprintf(buffer,"%d",stored_top_score);
el14jw 1:c4928de1f922 96 lcd.printString(buffer,0,1);
el14jw 1:c4928de1f922 97 } else {
el14jw 1:c4928de1f922 98 lcd.printString("No Saved Score",0,1);
el14jw 1:c4928de1f922 99 }
el14jw 1:c4928de1f922 100 lcd.printString(">> Back",0,2);
el14jw 1:c4928de1f922 101 sleep();
el14jw 1:c4928de1f922 102 }
el14jw 1:c4928de1f922 103 g_buttonjoy_flag = 0;
el14jw 1:c4928de1f922 104 g_buttonA_flag = 0;
el14jw 1:c4928de1f922 105 }
el14jw 1:c4928de1f922 106 }
el14jw 1:c4928de1f922 107
el14jw 0:23a749719479 108 }
el14jw 0:23a749719479 109 }
el14jw 0:23a749719479 110
el14jw 1:c4928de1f922 111 // Selected Plink
el14jw 0:23a749719479 112 else if (select == 1) {
el14jw 5:ae641b1d04fa 113
el14jw 1:c4928de1f922 114 // If select = 3 or -1 then user has chosen 'Back' button
el14jw 1:c4928de1f922 115 while( !(select == 3 || select ==-1) ) {
el14jw 0:23a749719479 116
el14jw 1:c4928de1f922 117 select = menu(plinkList,5);
el14jw 1:c4928de1f922 118 // Start Plink
el14jw 1:c4928de1f922 119 if (select == 0) {
el14jw 0:23a749719479 120 playSound(tune_intro);
el14jw 1:c4928de1f922 121 plink(plinkDifficulty);
el14jw 1:c4928de1f922 122 }
el14jw 1:c4928de1f922 123 // Difficulty selection
el14jw 1:c4928de1f922 124 else if (select == 1) {
el14jw 1:c4928de1f922 125 int tempdiff = plinkDifficulty;
el14jw 1:c4928de1f922 126 plinkDifficulty = menu(difficultyList,4);
el14jw 1:c4928de1f922 127 if (plinkDifficulty == -1) {
el14jw 1:c4928de1f922 128 plinkDifficulty = tempdiff;
el14jw 1:c4928de1f922 129 }
el14jw 1:c4928de1f922 130 }
el14jw 1:c4928de1f922 131 // Highscore
el14jw 1:c4928de1f922 132 else if (select == 2) {
el14jw 1:c4928de1f922 133 fp = fopen("/sd/plinkhighscore.txt", "r");
el14jw 1:c4928de1f922 134 wait(0.05);
el14jw 1:c4928de1f922 135 int stored_top_score = -2; // -2 to demonstrate it has changed after reading
el14jw 1:c4928de1f922 136
el14jw 1:c4928de1f922 137 lcd.clear();
el14jw 1:c4928de1f922 138 if (fp == NULL) { // if it can't open the file then print error message
el14jw 1:c4928de1f922 139 lcd.printString("No Results",0,0);
el14jw 1:c4928de1f922 140 wait(2.0);
el14jw 1:c4928de1f922 141 } else { // opened file so can read
el14jw 1:c4928de1f922 142 while ( ! (g_buttonA_flag || g_buttonjoy_flag)) {
el14jw 1:c4928de1f922 143 fscanf(fp,"%d",&stored_top_score); // ensure data type matches - note address operator (&)
el14jw 1:c4928de1f922 144 fclose(fp); // ensure you close the file after reading
el14jw 1:c4928de1f922 145 lcd.printString("Highscore",10,0);
el14jw 1:c4928de1f922 146 if (stored_top_score !=-2) {
el14jw 1:c4928de1f922 147 char buffer[14];
el14jw 1:c4928de1f922 148 sprintf(buffer,"%d",stored_top_score);
el14jw 1:c4928de1f922 149 lcd.printString(buffer,0,1);
el14jw 1:c4928de1f922 150 } else {
el14jw 1:c4928de1f922 151 lcd.printString("No Saved Score",0,1);
el14jw 1:c4928de1f922 152 }
el14jw 1:c4928de1f922 153 lcd.printString(">> Back",0,2);
el14jw 1:c4928de1f922 154 sleep();
el14jw 1:c4928de1f922 155 }
el14jw 1:c4928de1f922 156 g_buttonjoy_flag = 0;
el14jw 1:c4928de1f922 157 g_buttonA_flag = 0;
el14jw 1:c4928de1f922 158 }
el14jw 0:23a749719479 159 }
el14jw 0:23a749719479 160 }
el14jw 0:23a749719479 161 }
el14jw 0:23a749719479 162 }
el14jw 0:23a749719479 163 }
el14jw 0:23a749719479 164
el14jw 0:23a749719479 165
el14jw 1:c4928de1f922 166 // SNAKE
el14jw 0:23a749719479 167
el14jw 0:23a749719479 168 void snake(int difficulty)
el14jw 0:23a749719479 169 {
el14jw 0:23a749719479 170 // Play the snake intro tune
el14jw 0:23a749719479 171 playSound(tune_snakeintro);
el14jw 0:23a749719479 172 // Creates an array for storing the snake body x and y data. The snake can be up to 880 cells long
el14jw 0:23a749719479 173 cell snake[880];
el14jw 1:c4928de1f922 174 // Clears data from previous games
el14jw 1:c4928de1f922 175 for (int i=0; i<880; i++) {
el14jw 1:c4928de1f922 176 snake[i].x = 0;
el14jw 1:c4928de1f922 177 snake[i].y = 0;
el14jw 1:c4928de1f922 178 }
el14jw 1:c4928de1f922 179
el14jw 0:23a749719479 180 cell food;
el14jw 0:23a749719479 181 // Starting length is 5 cells
el14jw 0:23a749719479 182 int length = 5;
el14jw 0:23a749719479 183 // Starting 5 cells are x = 20 and y = 11,12,13,14 and 15
el14jw 0:23a749719479 184 for (int i=0; i<length; i++) {
el14jw 0:23a749719479 185 snake[i].x = 20;
el14jw 0:23a749719479 186 snake[i].y = 11+i;
el14jw 0:23a749719479 187 }
el14jw 0:23a749719479 188
el14jw 0:23a749719479 189 // Creates timer based on how hard you set the difficulty (default Medium)
el14jw 0:23a749719479 190 gametick.attach(&gametick_isr,(0.4-(difficulty*0.15)));
el14jw 0:23a749719479 191 // Initialise the snake_direction parameter as UP
el14jw 0:23a749719479 192 DirectionName snake_direction = UP;
el14jw 0:23a749719479 193 // Set the game over condition before while loop
el14jw 0:23a749719479 194 int gameOver = 0;
el14jw 0:23a749719479 195
el14jw 1:c4928de1f922 196 // Create the random food location flag (0 if food needs to be randomised and 1 if food still exists)
el14jw 0:23a749719479 197 int rand_food = 0;
el14jw 0:23a749719479 198
el14jw 0:23a749719479 199 while(!gameOver) {
el14jw 0:23a749719479 200 // When the game ticker updates
el14jw 0:23a749719479 201 if (g_gametick_flag) {
el14jw 0:23a749719479 202 // Reset the ticker flag
el14jw 0:23a749719479 203 g_gametick_flag = 0;
el14jw 1:c4928de1f922 204
el14jw 0:23a749719479 205 // If the current snake_direction is the opposite of the joystick direction or the joystick direction is centerd or unknown then keep current direction
el14jw 0:23a749719479 206 if ( !( (snake_direction == UP && joystick.direction == DOWN) ||
el14jw 0:23a749719479 207 (snake_direction == DOWN && joystick.direction == UP) ||
el14jw 0:23a749719479 208 (snake_direction == LEFT && joystick.direction == RIGHT) ||
el14jw 0:23a749719479 209 (snake_direction == RIGHT && joystick.direction == LEFT) ||
el14jw 0:23a749719479 210 (joystick.direction == CENTRE || joystick.direction == UNKNOWN) )) {
el14jw 0:23a749719479 211 snake_direction = joystick.direction;
el14jw 0:23a749719479 212 }
el14jw 0:23a749719479 213 // Iterate through array and move each cell backwards as far as the length of the snake
el14jw 0:23a749719479 214 for (int i=(length-1); i>0; i--) {
el14jw 0:23a749719479 215 snake[i] = snake[i-1];
el14jw 0:23a749719479 216 }
el14jw 0:23a749719479 217 // Then change the x or y coordinate of the first cell of the snake depending on which direction it is moving in
el14jw 0:23a749719479 218 switch(snake_direction) {
el14jw 0:23a749719479 219 case UP:
el14jw 0:23a749719479 220 snake[0].y = snake[0].y - 1;
el14jw 0:23a749719479 221 break;
el14jw 0:23a749719479 222 case DOWN:
el14jw 0:23a749719479 223 snake[0].y = snake[0].y + 1;
el14jw 0:23a749719479 224 break;
el14jw 0:23a749719479 225 case LEFT:
el14jw 0:23a749719479 226 snake[0].x = snake[0].x - 1;
el14jw 0:23a749719479 227 break;
el14jw 0:23a749719479 228 case RIGHT:
el14jw 0:23a749719479 229 snake[0].x = snake[0].x + 1;
el14jw 0:23a749719479 230 break;
el14jw 0:23a749719479 231 default:
el14jw 0:23a749719479 232 error();
el14jw 0:23a749719479 233 }
el14jw 0:23a749719479 234
el14jw 0:23a749719479 235 // If snake hits wall then game over
el14jw 0:23a749719479 236 if ( (snake[0].x == 41) || (snake[0].x == 0) || (snake[0].y == 23) || (snake[0].y == 0 ) ) {
el14jw 0:23a749719479 237 gameOver = 1;
el14jw 0:23a749719479 238 }
el14jw 0:23a749719479 239 // If snake hits self then game over
el14jw 0:23a749719479 240 for (int i=1; i<length; i++) {
el14jw 0:23a749719479 241 if (snake[0].x == snake[i].x && snake[0].y == snake[i].y) {
el14jw 0:23a749719479 242 gameOver = 1;
el14jw 0:23a749719479 243 }
el14jw 0:23a749719479 244 }
el14jw 1:c4928de1f922 245
el14jw 0:23a749719479 246 // If the snake head is at the same value of x and y as the food then play tune and increase length by 2
el14jw 0:23a749719479 247 if (food.x == snake[0].x && food.y == snake[0].y) {
el14jw 0:23a749719479 248 playSound(tune_snakeEat);
el14jw 0:23a749719479 249 length += 2;
el14jw 0:23a749719479 250 // Also set new random food to be generated
el14jw 0:23a749719479 251 rand_food = 0;
el14jw 0:23a749719479 252 }
el14jw 1:c4928de1f922 253
el14jw 0:23a749719479 254 // Create a random location for the food that is not the same as a snake location
el14jw 0:23a749719479 255 while(rand_food == 0) {
el14jw 0:23a749719479 256 rand_food = 1;
el14jw 0:23a749719479 257 food.x = rand();
el14jw 0:23a749719479 258 food.x = food.x %40 +1;
el14jw 0:23a749719479 259 food.y = rand();
el14jw 0:23a749719479 260 food.y = food.y %22 +1;
el14jw 0:23a749719479 261 for (int i=0; i<length; i++) {
el14jw 0:23a749719479 262 if(food.x == snake[i].x && food.y == snake[i].y) {
el14jw 0:23a749719479 263 rand_food = 0;
el14jw 0:23a749719479 264 }
el14jw 0:23a749719479 265 }
el14jw 0:23a749719479 266 }
el14jw 1:c4928de1f922 267
el14jw 1:c4928de1f922 268 // Drawing Display
el14jw 1:c4928de1f922 269 lcd.clear();
el14jw 1:c4928de1f922 270 // Draws Boundary 2 thick
el14jw 1:c4928de1f922 271 lcd.drawRect(0,0,83,47,0);
el14jw 1:c4928de1f922 272 lcd.drawRect(1,1,81,45,0);
el14jw 1:c4928de1f922 273 // Draws snake
el14jw 1:c4928de1f922 274 for (int i=0; i<length; i++) {
el14jw 1:c4928de1f922 275 lcd.drawRect(snake[i].x*2,snake[i].y*2,1,1,1);
el14jw 1:c4928de1f922 276 }
el14jw 1:c4928de1f922 277 // Draws food
el14jw 1:c4928de1f922 278 lcd.drawRect(food.x*2,food.y*2,1,1,1);
el14jw 0:23a749719479 279 lcd.refresh();
el14jw 1:c4928de1f922 280
el14jw 0:23a749719479 281 }
el14jw 0:23a749719479 282 sleep();
el14jw 0:23a749719479 283 }
el14jw 1:c4928de1f922 284 // End game ticker
el14jw 1:c4928de1f922 285 gametick.detach();
el14jw 1:c4928de1f922 286 int score = length -5; // length -5 because starting length is 5 and a score without collecting anything should be 0
el14jw 1:c4928de1f922 287 lcd.clear();
el14jw 2:80a91a737e17 288
el14jw 1:c4928de1f922 289 // Read previous highscore if one exists
el14jw 1:c4928de1f922 290 fp = fopen("/sd/snakehighscore.txt", "r");
el14jw 1:c4928de1f922 291 int current_high_score = -1; // -1 to demonstrate it has changed after reading
el14jw 1:c4928de1f922 292
el14jw 1:c4928de1f922 293 if (fp == NULL) { // if it can't open the file then print error message
el14jw 1:c4928de1f922 294 lcd.printString("Failed Read",0,5);
el14jw 1:c4928de1f922 295 } else { // opened file so can write
el14jw 1:c4928de1f922 296 fscanf(fp,"%d",&current_high_score); // ensure data type matches - note address operator (&)
el14jw 1:c4928de1f922 297 fclose(fp); // ensure you close the file after reading
el14jw 1:c4928de1f922 298 }
el14jw 1:c4928de1f922 299
el14jw 1:c4928de1f922 300 // Writing score to sd card if new high score
el14jw 1:c4928de1f922 301 if (current_high_score < score && current_high_score != -1) {
el14jw 1:c4928de1f922 302 fp = fopen("/sd/snakehighscore.txt", "w");
el14jw 1:c4928de1f922 303 if (fp == NULL) { // if it can't open the file then print error message
el14jw 1:c4928de1f922 304 lcd.printString("No SD Card",0,5);
el14jw 1:c4928de1f922 305 } else { // opened file so can write
el14jw 1:c4928de1f922 306 fprintf(fp,"%d",score); // ensure data type matches
el14jw 1:c4928de1f922 307 fclose(fp); // ensure you close the file after writing
el14jw 1:c4928de1f922 308 }
el14jw 1:c4928de1f922 309 }
el14jw 1:c4928de1f922 310
el14jw 1:c4928de1f922 311 // Appropriate strings printed to LCD
el14jw 1:c4928de1f922 312 lcd.printString("Game Over",20,0);
el14jw 5:ae641b1d04fa 313 if (current_high_score == -2) {
el14jw 5:ae641b1d04fa 314 lcd.printString("New High Score:",0,1);
el14jw 5:ae641b1d04fa 315 } else if (current_high_score != -1 && current_high_score < score) {
el14jw 1:c4928de1f922 316 lcd.printString("New High Score",0,1);
el14jw 1:c4928de1f922 317 lcd.printString("Previously",0,3);
el14jw 5:ae641b1d04fa 318 } else if (current_high_score != -1 && current_high_score >= score) {
el14jw 1:c4928de1f922 319 lcd.printString("Score",0,1);
el14jw 1:c4928de1f922 320 lcd.printString("High Score",0,3);
el14jw 1:c4928de1f922 321 } else {
el14jw 1:c4928de1f922 322 lcd.printString("Score:",0,1);
el14jw 1:c4928de1f922 323 lcd.printString("No Previous",0,3);
el14jw 1:c4928de1f922 324 }
el14jw 1:c4928de1f922 325 // Print score
el14jw 1:c4928de1f922 326 char buffer[14];
el14jw 1:c4928de1f922 327 sprintf(buffer,"%d",score);
el14jw 1:c4928de1f922 328 lcd.printString(buffer,20,2);
el14jw 1:c4928de1f922 329 // Print previous high-score
el14jw 5:ae641b1d04fa 330 if (current_high_score != -1 && current_high_score != -2) {
el14jw 1:c4928de1f922 331 char str[14];
el14jw 1:c4928de1f922 332 sprintf(str,"%d",current_high_score);
el14jw 1:c4928de1f922 333 lcd.printString(str,20,4);
el14jw 1:c4928de1f922 334 }
el14jw 1:c4928de1f922 335
el14jw 0:23a749719479 336 playSound(tune_gameOver);
el14jw 0:23a749719479 337 wait(3.0);
el14jw 0:23a749719479 338 g_buttonA_flag = 0;
el14jw 1:c4928de1f922 339 g_buttonB_flag = 0;
el14jw 0:23a749719479 340 g_buttonjoy_flag = 0;
el14jw 0:23a749719479 341 }
el14jw 1:c4928de1f922 342
el14jw 1:c4928de1f922 343
el14jw 1:c4928de1f922 344 // PLINK
el14jw 1:c4928de1f922 345
el14jw 1:c4928de1f922 346 void plink(int difficulty)
el14jw 0:23a749719479 347 {
el14jw 1:c4928de1f922 348 playSound(tune_plinkintro);
el14jw 1:c4928de1f922 349 lcd.clear();
el14jw 3:02d9072a2507 350 // Instead of damaging the program flow with global variables I pass a struct full of variables from one plink function to another.
el14jw 1:c4928de1f922 351
el14jw 3:02d9072a2507 352 plinkvar pvar;
el14jw 3:02d9072a2507 353 pvar.difficulty = difficulty;
el14jw 2:80a91a737e17 354
el14jw 3:02d9072a2507 355 // Initialise plink variables
el14jw 3:02d9072a2507 356 pvar = initpvar(pvar);
el14jw 2:80a91a737e17 357 // Game ticker
el14jw 1:c4928de1f922 358 int refreshRate = 100;
el14jw 1:c4928de1f922 359 float tickerDelay = 1.0/refreshRate;
el14jw 3:02d9072a2507 360 pvar.tickerDelay = tickerDelay;
el14jw 1:c4928de1f922 361 gametick.attach(&gametick_isr,tickerDelay);
el14jw 5:ae641b1d04fa 362 // Update screen 30 fps
el14jw 5:ae641b1d04fa 363 tickerDelay = 1.0/30.0;
el14jw 5:ae641b1d04fa 364 screentick.attach(&screentick_isr,tickerDelay);
el14jw 3:02d9072a2507 365 wait(0.25);
el14jw 2:80a91a737e17 366
el14jw 3:02d9072a2507 367 while(!pvar.gameOver) {
el14jw 1:c4928de1f922 368 if (g_gametick_flag) {
el14jw 5:ae641b1d04fa 369 g_gametick_flag = 0;
el14jw 1:c4928de1f922 370
el14jw 1:c4928de1f922 371 // Screen scrolling
el14jw 3:02d9072a2507 372 pvar = plinkScroll(pvar);
el14jw 1:c4928de1f922 373 // Platform generation
el14jw 3:02d9072a2507 374 pvar = plinkPlatGen(pvar);
el14jw 1:c4928de1f922 375 // Collisions
el14jw 3:02d9072a2507 376 pvar = plinkCollisions(pvar);
el14jw 3:02d9072a2507 377 // Physics Engine
el14jw 3:02d9072a2507 378 pvar = plinkPhysicsEngine(pvar);
el14jw 3:02d9072a2507 379 // LCD drawing
el14jw 3:02d9072a2507 380 pvar = plinkDrawScreen(pvar);
el14jw 1:c4928de1f922 381
el14jw 1:c4928de1f922 382 }
el14jw 3:02d9072a2507 383 // Sleep to conserve power until next interrupt
el14jw 3:02d9072a2507 384 sleep();
el14jw 0:23a749719479 385 }
el14jw 1:c4928de1f922 386
el14jw 1:c4928de1f922 387 gametick.detach();
el14jw 1:c4928de1f922 388 lcd.clear();
el14jw 5:ae641b1d04fa 389
el14jw 4:c2d920b17b14 390 // Handle high scores and printing game over messages to LCD
el14jw 3:02d9072a2507 391 pvar = plinkGameOver(pvar);
el14jw 5:ae641b1d04fa 392
el14jw 4:c2d920b17b14 393 }
el14jw 3:02d9072a2507 394
el14jw 3:02d9072a2507 395 plinkvar initpvar(plinkvar pvar)
el14jw 3:02d9072a2507 396 {
el14jw 3:02d9072a2507 397 // Initial physics conditions
el14jw 3:02d9072a2507 398 vector pos = {41,47};
el14jw 3:02d9072a2507 399 vector vel = {0,-25};
el14jw 3:02d9072a2507 400 vector acc = {0,10};
el14jw 3:02d9072a2507 401 pvar.pos = pos;
el14jw 3:02d9072a2507 402 pvar.vel = vel;
el14jw 3:02d9072a2507 403 pvar.acc = acc;
el14jw 3:02d9072a2507 404
el14jw 3:02d9072a2507 405 // Initialising game parameters
el14jw 3:02d9072a2507 406 pvar.height = 0; // This is the number of pixels that the lcd has 'scrolled' by
el14jw 3:02d9072a2507 407 pvar.gameOver = 0; // When something consitutes a game over parameter this is set to 1 and the while loop is broken out of
el14jw 3:02d9072a2507 408 pvar.platformWidth = 7 - (pvar.difficulty * 2); // Platform width is based on difficulty and also changed by power ups
el14jw 3:02d9072a2507 409 cell powerUp = {42,-100}; // The first power up can be found at these coordinates
el14jw 3:02d9072a2507 410 pvar.powerUp = powerUp;
el14jw 3:02d9072a2507 411 pvar.powerUpHeight = 0; // This parameter keeps tabs on the number of pixels scrolled while a power up is active (after 100 picels the power up wears off)
el14jw 3:02d9072a2507 412 pvar.powerUpRadius = 5; // Helpful parameter for detecting collisions
el14jw 3:02d9072a2507 413 pvar.ballRadius = 2; // Also helpful parameter for detecting collisions and is changed in 2 power up cases
el14jw 3:02d9072a2507 414
el14jw 3:02d9072a2507 415 // Initialising platforms
el14jw 3:02d9072a2507 416 pvar.platforms[0].x = 42;
el14jw 3:02d9072a2507 417 pvar.platforms[0].y = 46;
el14jw 3:02d9072a2507 418 for (int i=1; i<20; i++) {
el14jw 3:02d9072a2507 419 pvar.platforms[i].x = rand()%(84-pvar.platformWidth) + (pvar.platformWidth-1)/2;
el14jw 3:02d9072a2507 420 pvar.platforms[i].y = pvar.platforms[i-1].y - (rand()%10 + 5);
el14jw 3:02d9072a2507 421 }
el14jw 3:02d9072a2507 422
el14jw 3:02d9072a2507 423 return pvar;
el14jw 3:02d9072a2507 424 }
el14jw 3:02d9072a2507 425 plinkvar plinkScroll(plinkvar pvar)
el14jw 3:02d9072a2507 426 {
el14jw 3:02d9072a2507 427 // Scrolling Block
el14jw 3:02d9072a2507 428 while (pvar.pos.y < 14) {
el14jw 3:02d9072a2507 429 pvar.pos.y++;
el14jw 3:02d9072a2507 430 pvar.height++;
el14jw 3:02d9072a2507 431 pvar.powerUpHeight++;
el14jw 3:02d9072a2507 432 for (int i=0; i<20; i++) {
el14jw 3:02d9072a2507 433 pvar.platforms[i].y++;
el14jw 3:02d9072a2507 434 }
el14jw 3:02d9072a2507 435 pvar.powerUp.y++;
el14jw 3:02d9072a2507 436 }
el14jw 3:02d9072a2507 437 return pvar;
el14jw 3:02d9072a2507 438 }
el14jw 3:02d9072a2507 439 plinkvar plinkPlatGen(plinkvar pvar)
el14jw 3:02d9072a2507 440 {
el14jw 3:02d9072a2507 441 // Platform generation
el14jw 3:02d9072a2507 442 for (int i=0; i<20; i++) {
el14jw 3:02d9072a2507 443 if (pvar.platforms[i].y > 47) {
el14jw 3:02d9072a2507 444 // Stage 1
el14jw 3:02d9072a2507 445 if (pvar.height <= 500) {
el14jw 3:02d9072a2507 446 if (i == 0) {
el14jw 3:02d9072a2507 447 pvar.platforms[0].x = rand()%(84-pvar.platformWidth) + (pvar.platformWidth-1)/2;
el14jw 3:02d9072a2507 448 pvar.platforms[0].y = pvar.platforms[19].y - (rand()%10 + 5);
el14jw 3:02d9072a2507 449 } else {
el14jw 3:02d9072a2507 450 pvar.platforms[i].x = rand()%(84-pvar.platformWidth) + (pvar.platformWidth-1)/2;
el14jw 3:02d9072a2507 451 pvar.platforms[i].y = pvar.platforms[i-1].y - (rand()%10 + 5);
el14jw 3:02d9072a2507 452 }
el14jw 3:02d9072a2507 453 }
el14jw 3:02d9072a2507 454 // Stage 2
el14jw 3:02d9072a2507 455 else if (500 < pvar.height <= 1000) {
el14jw 3:02d9072a2507 456 if (i == 0) {
el14jw 3:02d9072a2507 457 pvar.platforms[0].x = rand()%(84-pvar.platformWidth) + (pvar.platformWidth-1)/2;
el14jw 3:02d9072a2507 458 pvar.platforms[0].y = pvar.platforms[19].y - (rand()%10 + 10);
el14jw 3:02d9072a2507 459 } else {
el14jw 3:02d9072a2507 460 pvar.platforms[i].x = rand()%(84-pvar.platformWidth) + (pvar.platformWidth-1)/2;
el14jw 3:02d9072a2507 461 pvar.platforms[i].y = pvar.platforms[i-1].y - (rand()%10 + 10);
el14jw 3:02d9072a2507 462 }
el14jw 3:02d9072a2507 463 }
el14jw 3:02d9072a2507 464 //Stage 3
el14jw 3:02d9072a2507 465 else if (pvar.height > 1000) {
el14jw 3:02d9072a2507 466 if (i == 0) {
el14jw 3:02d9072a2507 467 pvar.platforms[0].x = rand()%(84-pvar.platformWidth) + (pvar.platformWidth-1)/2;
el14jw 3:02d9072a2507 468 pvar.platforms[0].y = pvar.platforms[19].y - (rand()%10 + 15);
el14jw 3:02d9072a2507 469 } else {
el14jw 3:02d9072a2507 470 pvar.platforms[i].x = rand()%(84-pvar.platformWidth) + (pvar.platformWidth-1)/2;
el14jw 3:02d9072a2507 471 pvar.platforms[i].y = pvar.platforms[i-1].y - (rand()%10 + 15);
el14jw 3:02d9072a2507 472 }
el14jw 3:02d9072a2507 473 }
el14jw 3:02d9072a2507 474 }
el14jw 3:02d9072a2507 475 }
el14jw 3:02d9072a2507 476 return pvar;
el14jw 3:02d9072a2507 477 }
el14jw 3:02d9072a2507 478 plinkvar plinkCollisions(plinkvar pvar)
el14jw 3:02d9072a2507 479 {
el14jw 3:02d9072a2507 480 // Collisions
el14jw 3:02d9072a2507 481 // Platforms
el14jw 3:02d9072a2507 482 for (int i=0; i<20; i++) {
el14jw 3:02d9072a2507 483 if ( (int)pvar.pos.y == (pvar.platforms[i].y - 1) && (int)pvar.pos.x > pvar.platforms[i].x-pvar.platformWidth-2 && (int)pvar.pos.x < pvar.platforms[i].x+pvar.platformWidth+2 ) {
el14jw 3:02d9072a2507 484 pvar.vel.y = -25;
el14jw 3:02d9072a2507 485 // Play appropriate sound when bouncing
el14jw 3:02d9072a2507 486 switch (pvar.ballRadius) {
el14jw 3:02d9072a2507 487 case 1:
el14jw 3:02d9072a2507 488 playSound(tune_plinkjump_small);
el14jw 3:02d9072a2507 489 break;
el14jw 3:02d9072a2507 490 case 2:
el14jw 3:02d9072a2507 491 playSound(tune_plinkjump_normal);
el14jw 3:02d9072a2507 492 break;
el14jw 3:02d9072a2507 493 case 4:
el14jw 3:02d9072a2507 494 playSound(tune_plinkjump_big);
el14jw 3:02d9072a2507 495 break;
el14jw 3:02d9072a2507 496 }
el14jw 3:02d9072a2507 497 }
el14jw 3:02d9072a2507 498 }
el14jw 3:02d9072a2507 499 // Walls
el14jw 3:02d9072a2507 500 if (pvar.pos.x <= pvar.ballRadius) {
el14jw 3:02d9072a2507 501 pvar.vel.x = abs(pvar.vel.x);
el14jw 3:02d9072a2507 502 } else if (pvar.pos.x >= 83 - pvar.ballRadius) {
el14jw 3:02d9072a2507 503 pvar.vel.x = -abs(pvar.vel.x);
el14jw 3:02d9072a2507 504 }
el14jw 3:02d9072a2507 505 // Power Up
el14jw 3:02d9072a2507 506 if ((int)pvar.pos.x+pvar.ballRadius >= (pvar.powerUp.x-pvar.powerUpRadius)
el14jw 3:02d9072a2507 507 && (int)pvar.pos.x-pvar.ballRadius <= (pvar.powerUp.x+pvar.powerUpRadius)
el14jw 3:02d9072a2507 508 && (int)pvar.pos.y+pvar.ballRadius >= (pvar.powerUp.y-pvar.powerUpRadius)
el14jw 3:02d9072a2507 509 && (int)pvar.pos.y-pvar.ballRadius <= (pvar.powerUp.y+pvar.powerUpRadius)) {
el14jw 3:02d9072a2507 510 // Create new powerUp box at the next 100 mark
el14jw 3:02d9072a2507 511 pvar.powerUp.x = rand()%(84-1-(pvar.powerUpRadius*2)) + pvar.powerUpRadius;
el14jw 3:02d9072a2507 512 pvar.powerUp.y = -100;
el14jw 3:02d9072a2507 513
el14jw 3:02d9072a2507 514 //reset power up height
el14jw 3:02d9072a2507 515 pvar.powerUpHeight = 0;
el14jw 3:02d9072a2507 516
el14jw 3:02d9072a2507 517 // Choose new power up randomly
el14jw 3:02d9072a2507 518 switch (rand()%4) {
el14jw 3:02d9072a2507 519 case 0:
el14jw 3:02d9072a2507 520 pvar.ballRadius = 4;
el14jw 3:02d9072a2507 521 break;
el14jw 3:02d9072a2507 522 case 1:
el14jw 3:02d9072a2507 523 pvar.ballRadius = 1;
el14jw 3:02d9072a2507 524 break;
el14jw 3:02d9072a2507 525 case 2:
el14jw 3:02d9072a2507 526 pvar.platformWidth = 11;
el14jw 3:02d9072a2507 527 break;
el14jw 3:02d9072a2507 528 case 3:
el14jw 3:02d9072a2507 529 pvar.platformWidth = 5;
el14jw 3:02d9072a2507 530 break;
el14jw 3:02d9072a2507 531 default:
el14jw 3:02d9072a2507 532 error();
el14jw 3:02d9072a2507 533 }
el14jw 5:ae641b1d04fa 534 }
el14jw 4:c2d920b17b14 535 // If the powerup has been missed then generate new one
el14jw 4:c2d920b17b14 536 else if (pvar.powerUp.y > 47+pvar.powerUpRadius) {
el14jw 3:02d9072a2507 537 pvar.powerUp.x = rand()%(84-1-(pvar.powerUpRadius*2)) + pvar.powerUpRadius;
el14jw 3:02d9072a2507 538 pvar.powerUp.y = -150;
el14jw 3:02d9072a2507 539 }
el14jw 4:c2d920b17b14 540 // After certain height achieved then cancel power up
el14jw 3:02d9072a2507 541 if (pvar.powerUpHeight > 100) {
el14jw 3:02d9072a2507 542 pvar.ballRadius = 2;
el14jw 3:02d9072a2507 543 pvar.platformWidth = 7 - (pvar.difficulty * 2);
el14jw 3:02d9072a2507 544 }
el14jw 3:02d9072a2507 545 return pvar;
el14jw 3:02d9072a2507 546 }
el14jw 3:02d9072a2507 547 plinkvar plinkPhysicsEngine(plinkvar pvar)
el14jw 3:02d9072a2507 548 {
el14jw 3:02d9072a2507 549 // Physics engine
el14jw 3:02d9072a2507 550 // Acceleration due to joystick
el14jw 3:02d9072a2507 551 if (g_joystick_flag) {
el14jw 3:02d9072a2507 552 if (joystick.direction == LEFT) {
el14jw 3:02d9072a2507 553 pvar.acc.x = -15;
el14jw 3:02d9072a2507 554 } else if (joystick.direction == RIGHT) {
el14jw 3:02d9072a2507 555 pvar.acc.x = 15;
el14jw 3:02d9072a2507 556 } else {
el14jw 3:02d9072a2507 557 pvar.acc.x = 0;
el14jw 3:02d9072a2507 558 }
el14jw 3:02d9072a2507 559 }
el14jw 4:c2d920b17b14 560 // physics iteration
el14jw 3:02d9072a2507 561 pvar.vel.y = pvar.vel.y + (pvar.acc.y * pvar.tickerDelay * 4);
el14jw 3:02d9072a2507 562 pvar.vel.x = 0.97F*(pvar.vel.x + (pvar.acc.x * pvar.tickerDelay)*4); // 0.97 adds slight damping factor to horizontal movement
el14jw 3:02d9072a2507 563 pvar.pos.y = pvar.pos.y + (pvar.vel.y * pvar.tickerDelay * 4);
el14jw 3:02d9072a2507 564 pvar.pos.x = pvar.pos.x + (pvar.vel.x * pvar.tickerDelay * 4);
el14jw 3:02d9072a2507 565 // Boundaries of physics engine
el14jw 3:02d9072a2507 566 if (pvar.pos.y > 48) {
el14jw 3:02d9072a2507 567 pvar.gameOver = 1;
el14jw 3:02d9072a2507 568 }
el14jw 4:c2d920b17b14 569 // If ball is out of boundaries then place it back in boundaries
el14jw 3:02d9072a2507 570 if (pvar.pos.x - pvar.ballRadius < 0) {
el14jw 3:02d9072a2507 571 pvar.pos.x = pvar.ballRadius;
el14jw 3:02d9072a2507 572 } else if (pvar.pos.x + pvar.ballRadius > 83) {
el14jw 3:02d9072a2507 573 pvar.pos.x = 83-pvar.ballRadius;
el14jw 3:02d9072a2507 574 }
el14jw 3:02d9072a2507 575 return pvar;
el14jw 3:02d9072a2507 576 }
el14jw 3:02d9072a2507 577 plinkvar plinkDrawScreen(plinkvar pvar)
el14jw 3:02d9072a2507 578 {
el14jw 5:ae641b1d04fa 579 if (g_screentick_flag) {
el14jw 5:ae641b1d04fa 580 g_screentick_flag = 0;
el14jw 5:ae641b1d04fa 581 // Drawing on lcd
el14jw 5:ae641b1d04fa 582 lcd.clear();
el14jw 5:ae641b1d04fa 583 // Print Current Score
el14jw 5:ae641b1d04fa 584 char buffer[14];
el14jw 5:ae641b1d04fa 585 sprintf(buffer,"Score: %d",pvar.height);
el14jw 5:ae641b1d04fa 586 lcd.printString(buffer,0,0);
el14jw 5:ae641b1d04fa 587 // Drawing ball/blob
el14jw 5:ae641b1d04fa 588 // If second blob stage
el14jw 5:ae641b1d04fa 589 int noPlatform = 1;
el14jw 5:ae641b1d04fa 590 if (pvar.ballRadius == 2) {
el14jw 5:ae641b1d04fa 591 for (int i=0; i<20; i++) {
el14jw 5:ae641b1d04fa 592 if ( (int)pvar.pos.y == (pvar.platforms[i].y - 2) && (int)pvar.pos.x > pvar.platforms[i].x-pvar.platformWidth-2 && (int)pvar.pos.x < pvar.platforms[i].x+pvar.platformWidth+2 ) {
el14jw 5:ae641b1d04fa 593 noPlatform = 0;
el14jw 5:ae641b1d04fa 594 lcd.drawRect(pvar.pos.x-2,pvar.pos.y-1,4,2,1); // X, Y, Width, Height, Fill
el14jw 5:ae641b1d04fa 595 lcd.setPixel(pvar.pos.x-1,pvar.pos.y-2);
el14jw 5:ae641b1d04fa 596 lcd.setPixel(pvar.pos.x,pvar.pos.y-2);
el14jw 5:ae641b1d04fa 597 lcd.setPixel(pvar.pos.x+1,pvar.pos.y-2);
el14jw 5:ae641b1d04fa 598 lcd.setPixel(pvar.pos.x-3,pvar.pos.y+1);
el14jw 5:ae641b1d04fa 599 lcd.setPixel(pvar.pos.x+3,pvar.pos.y+1);
el14jw 5:ae641b1d04fa 600 }
el14jw 5:ae641b1d04fa 601 // If third blob stage
el14jw 5:ae641b1d04fa 602 else if ( (int)pvar.pos.y == (pvar.platforms[i].y - 1) && (int)pvar.pos.x > pvar.platforms[i].x-pvar.platformWidth-2 && (int)pvar.pos.x < pvar.platforms[i].x+pvar.platformWidth+2 ) {
el14jw 5:ae641b1d04fa 603 noPlatform = 0;
el14jw 5:ae641b1d04fa 604 lcd.drawRect(pvar.pos.x-3,pvar.pos.y-1,6,1,1); // X, Y, Width, Height, Fill
el14jw 5:ae641b1d04fa 605 lcd.setPixel(pvar.pos.x-4,pvar.pos.y);
el14jw 5:ae641b1d04fa 606 lcd.setPixel(pvar.pos.x+4,pvar.pos.y);
el14jw 5:ae641b1d04fa 607 lcd.setPixel(pvar.pos.x-2,pvar.pos.y-2);
el14jw 5:ae641b1d04fa 608 lcd.setPixel(pvar.pos.x-1,pvar.pos.y-2);
el14jw 5:ae641b1d04fa 609 lcd.setPixel(pvar.pos.x,pvar.pos.y-2);
el14jw 5:ae641b1d04fa 610 lcd.setPixel(pvar.pos.x+1,pvar.pos.y-2);
el14jw 5:ae641b1d04fa 611 lcd.setPixel(pvar.pos.x+2,pvar.pos.y-2);
el14jw 5:ae641b1d04fa 612 }
el14jw 5:ae641b1d04fa 613 }
el14jw 5:ae641b1d04fa 614 }
el14jw 5:ae641b1d04fa 615 // Else default blob stage
el14jw 5:ae641b1d04fa 616 if (noPlatform == 1) {
el14jw 5:ae641b1d04fa 617 lcd.drawCircle((int)pvar.pos.x,(int)pvar.pos.y,pvar.ballRadius,1); // X, Y, Radius, Fill
el14jw 5:ae641b1d04fa 618 lcd.refresh();
el14jw 5:ae641b1d04fa 619 }
el14jw 5:ae641b1d04fa 620 // Platforms and boundaries drawing
el14jw 3:02d9072a2507 621 for (int i=0; i<20; i++) {
el14jw 5:ae641b1d04fa 622 if (pvar.platforms[i].y > 0) {
el14jw 5:ae641b1d04fa 623 lcd.drawRect( pvar.platforms[i].x-pvar.platformWidth ,pvar.platforms[i].y,pvar.platformWidth*2,1,1); // X, Y, Width, Height, Fill
el14jw 3:02d9072a2507 624 }
el14jw 5:ae641b1d04fa 625 }
el14jw 5:ae641b1d04fa 626 lcd.drawLine(0,0,0,47,1); // x0,y0,x1,y1,type
el14jw 5:ae641b1d04fa 627 lcd.drawLine(83,0,83,47,1);
el14jw 5:ae641b1d04fa 628 // PowerUp drawing
el14jw 5:ae641b1d04fa 629 if (pvar.powerUp.y > 0-pvar.powerUpRadius && pvar.powerUp.y < 47+pvar.powerUpRadius) {
el14jw 5:ae641b1d04fa 630 lcd.drawRect(pvar.powerUp.x-pvar.powerUpRadius,pvar.powerUp.y-pvar.powerUpRadius,10,10,0); // X, Y, Width, Height, Fill
el14jw 5:ae641b1d04fa 631 lcd.setPixel(pvar.powerUp.x,pvar.powerUp.y+3);
el14jw 5:ae641b1d04fa 632 lcd.setPixel(pvar.powerUp.x,pvar.powerUp.y+1);
el14jw 5:ae641b1d04fa 633 lcd.setPixel(pvar.powerUp.x+1,pvar.powerUp.y);
el14jw 5:ae641b1d04fa 634 lcd.setPixel(pvar.powerUp.x+2,pvar.powerUp.y-1);
el14jw 5:ae641b1d04fa 635 lcd.setPixel(pvar.powerUp.x+2,pvar.powerUp.y-2);
el14jw 5:ae641b1d04fa 636 lcd.setPixel(pvar.powerUp.x+1,pvar.powerUp.y-3);
el14jw 5:ae641b1d04fa 637 lcd.setPixel(pvar.powerUp.x,pvar.powerUp.y-3);
el14jw 5:ae641b1d04fa 638 lcd.setPixel(pvar.powerUp.x-1,pvar.powerUp.y-3);
el14jw 5:ae641b1d04fa 639 lcd.setPixel(pvar.powerUp.x-2,pvar.powerUp.y-2);
el14jw 5:ae641b1d04fa 640 }
el14jw 5:ae641b1d04fa 641
el14jw 5:ae641b1d04fa 642 lcd.refresh();
el14jw 5:ae641b1d04fa 643 // Looks more pleasing when the ball pauses to bounce
el14jw 5:ae641b1d04fa 644 if (noPlatform == 0) {
el14jw 5:ae641b1d04fa 645 wait(0.03);
el14jw 3:02d9072a2507 646 }
el14jw 3:02d9072a2507 647 }
el14jw 3:02d9072a2507 648 return pvar;
el14jw 3:02d9072a2507 649 }
el14jw 5:ae641b1d04fa 650 plinkvar plinkGameOver(plinkvar pvar)
el14jw 5:ae641b1d04fa 651 {
el14jw 3:02d9072a2507 652 // Handle saving high scores to SD card
el14jw 1:c4928de1f922 653 // Read previous highscore if one exists
el14jw 1:c4928de1f922 654 fp = fopen("/sd/plinkhighscore.txt", "r");
el14jw 1:c4928de1f922 655 int current_high_score = -1; // -1 to demonstrate it has changed after reading
el14jw 1:c4928de1f922 656
el14jw 1:c4928de1f922 657 if (fp == NULL) { // if it can't open the file then print error message
el14jw 1:c4928de1f922 658 lcd.printString("Failed Read",0,5);
el14jw 1:c4928de1f922 659 } else { // opened file so can write
el14jw 1:c4928de1f922 660 fscanf(fp,"%d",&current_high_score); // ensure data type matches - note address operator (&)
el14jw 1:c4928de1f922 661 fclose(fp); // ensure you close the file after reading
el14jw 1:c4928de1f922 662 }
el14jw 1:c4928de1f922 663
el14jw 1:c4928de1f922 664 // Writing score to sd card if new high score
el14jw 3:02d9072a2507 665 if (current_high_score < pvar.height && current_high_score != -1) {
el14jw 1:c4928de1f922 666 fp = fopen("/sd/plinkhighscore.txt", "w");
el14jw 1:c4928de1f922 667 if (fp == NULL) { // if it can't open the file then print error message
el14jw 1:c4928de1f922 668 lcd.printString("No SD Card ",0,5);
el14jw 1:c4928de1f922 669 } else { // opened file so can write
el14jw 3:02d9072a2507 670 fprintf(fp,"%d",pvar.height); // ensure data type matches
el14jw 1:c4928de1f922 671 fclose(fp); // ensure you close the file after writing
el14jw 1:c4928de1f922 672 }
el14jw 1:c4928de1f922 673 }
el14jw 1:c4928de1f922 674
el14jw 1:c4928de1f922 675 // Appropriate strings printed to LCD
el14jw 1:c4928de1f922 676 lcd.printString("Game Over",20,0);
el14jw 5:ae641b1d04fa 677 if (current_high_score == -2) {
el14jw 5:ae641b1d04fa 678 lcd.printString("New High Score:",0,1);
el14jw 5:ae641b1d04fa 679 } else if (current_high_score != -1 && current_high_score < pvar.height) {
el14jw 1:c4928de1f922 680 lcd.printString("New High Score",0,1);
el14jw 1:c4928de1f922 681 lcd.printString("Previously",0,3);
el14jw 5:ae641b1d04fa 682 } else if (current_high_score != -1 && current_high_score >= pvar.height) {
el14jw 5:ae641b1d04fa 683 lcd.printString("Score:",0,1);
el14jw 1:c4928de1f922 684 lcd.printString("High Score",0,3);
el14jw 1:c4928de1f922 685 } else {
el14jw 1:c4928de1f922 686 lcd.printString("Score:",0,1);
el14jw 1:c4928de1f922 687 lcd.printString("No Previous",0,3);
el14jw 1:c4928de1f922 688 }
el14jw 1:c4928de1f922 689 // Print score
el14jw 1:c4928de1f922 690 char buffer[14];
el14jw 3:02d9072a2507 691 sprintf(buffer,"%d",pvar.height);
el14jw 1:c4928de1f922 692 lcd.printString(buffer,20,2);
el14jw 1:c4928de1f922 693 // Print previous high-score
el14jw 5:ae641b1d04fa 694 if (current_high_score != -1 && current_high_score != -2) {
el14jw 1:c4928de1f922 695 char str[14];
el14jw 1:c4928de1f922 696 sprintf(str,"%d",current_high_score);
el14jw 1:c4928de1f922 697 lcd.printString(str,20,4);
el14jw 1:c4928de1f922 698 }
el14jw 2:80a91a737e17 699
el14jw 1:c4928de1f922 700 playSound(tune_gameOver);
el14jw 0:23a749719479 701 lcd.refresh();
el14jw 1:c4928de1f922 702 wait(3.0);
el14jw 4:c2d920b17b14 703 // Reset all flags so no unexpected behaviour occurs
el14jw 1:c4928de1f922 704 g_buttonA_flag = 0;
el14jw 1:c4928de1f922 705 g_buttonB_flag = 0;
el14jw 1:c4928de1f922 706 g_buttonjoy_flag = 0;
el14jw 3:02d9072a2507 707 return pvar;
el14jw 0:23a749719479 708 }
el14jw 0:23a749719479 709
el14jw 0:23a749719479 710
el14jw 0:23a749719479 711 // ISR's
el14jw 1:c4928de1f922 712 void buttonA_isr()
el14jw 1:c4928de1f922 713 {
el14jw 1:c4928de1f922 714 g_buttonA_flag = 1;
el14jw 1:c4928de1f922 715 }
el14jw 1:c4928de1f922 716 void buttonB_isr()
el14jw 1:c4928de1f922 717 {
el14jw 1:c4928de1f922 718 g_buttonB_flag = 1;
el14jw 1:c4928de1f922 719 }
el14jw 1:c4928de1f922 720 void buttonjoy_isr()
el14jw 1:c4928de1f922 721 {
el14jw 1:c4928de1f922 722 g_buttonjoy_flag = 1;
el14jw 1:c4928de1f922 723 }
el14jw 1:c4928de1f922 724 void gametick_isr()
el14jw 1:c4928de1f922 725 {
el14jw 1:c4928de1f922 726 g_gametick_flag = 1;
el14jw 1:c4928de1f922 727 }
el14jw 5:ae641b1d04fa 728 void screentick_isr()
el14jw 5:ae641b1d04fa 729 {
el14jw 5:ae641b1d04fa 730 g_screentick_flag = 1;
el14jw 5:ae641b1d04fa 731 }
el14jw 0:23a749719479 732
el14jw 4:c2d920b17b14 733
el14jw 0:23a749719479 734 // Initialises Inputs
el14jw 0:23a749719479 735 void initInputs()
el14jw 0:23a749719479 736 {
el14jw 0:23a749719479 737
el14jw 0:23a749719479 738 errorLED = 1;
el14jw 0:23a749719479 739
el14jw 0:23a749719479 740 /// Setting up Interrupt service routines for input buttons
el14jw 0:23a749719479 741 /// PullDown mode is assumed
el14jw 0:23a749719479 742 buttonA.rise(&buttonA_isr);
el14jw 0:23a749719479 743 buttonB.rise(&buttonB_isr);
el14jw 0:23a749719479 744 buttonjoy.rise(&buttonjoy_isr);
el14jw 0:23a749719479 745 buttonA.mode(PullDown);
el14jw 0:23a749719479 746 buttonB.mode(PullDown);
el14jw 0:23a749719479 747 buttonjoy.mode(PullDown);
el14jw 0:23a749719479 748
el14jw 0:23a749719479 749 /// Testing LCD display works (splash screen)
el14jw 0:23a749719479 750 lcd.init();
el14jw 2:80a91a737e17 751 wait(0.5);
el14jw 5:ae641b1d04fa 752 lcd.setBrightness(0.5); // Brightness set to maximum duty cycle so it isn't affected by changing frequency of buzzer
el14jw 0:23a749719479 753 lcd.printString("Calibrating",8,0);
el14jw 0:23a749719479 754 lcd.printString("Do not move",8,1);
el14jw 0:23a749719479 755 lcd.printString("Joystick",18,2);
el14jw 0:23a749719479 756 lcd.refresh();
el14jw 0:23a749719479 757
el14jw 0:23a749719479 758 /// Calibrating the Joystick on startup
el14jw 0:23a749719479 759 calibrateJoystick();
el14jw 0:23a749719479 760 /// read joystick 10 times per second
el14jw 0:23a749719479 761 pollJoystick.attach(&updateJoystick,1.0/10.0);
el14jw 5:ae641b1d04fa 762
el14jw 5:ae641b1d04fa 763 // Patch for sd card access not working first time
el14jw 5:ae641b1d04fa 764 fp = fopen("/sd/test.txt", "w");
el14jw 3:02d9072a2507 765 if (fp != NULL) {
el14jw 3:02d9072a2507 766 fclose(fp);
el14jw 2:80a91a737e17 767 }
el14jw 5:ae641b1d04fa 768 fp = fopen("/sd/test.txt", "w");
el14jw 5:ae641b1d04fa 769 if (fp != NULL) {
el14jw 5:ae641b1d04fa 770 fclose(fp); // ensure you close the file after writing
el14jw 5:ae641b1d04fa 771 }
el14jw 5:ae641b1d04fa 772
el14jw 5:ae641b1d04fa 773 // If file does not exist then create it
el14jw 5:ae641b1d04fa 774 fp = fopen("/sd/plinkhighscore.txt","r");
el14jw 5:ae641b1d04fa 775 if (fp == NULL) {
el14jw 5:ae641b1d04fa 776 fp = fopen("/sd/plinkhighscore.txt","w");
el14jw 5:ae641b1d04fa 777 if (fp != NULL) {
el14jw 5:ae641b1d04fa 778 fprintf(fp,"%d",-2);
el14jw 5:ae641b1d04fa 779 fclose(fp);
el14jw 5:ae641b1d04fa 780 }
el14jw 5:ae641b1d04fa 781 } else {
el14jw 5:ae641b1d04fa 782 fclose(fp);
el14jw 5:ae641b1d04fa 783 }
el14jw 5:ae641b1d04fa 784
el14jw 5:ae641b1d04fa 785 fp = fopen("/sd/snakehighscore.txt","r");
el14jw 5:ae641b1d04fa 786 if (fp == NULL) {
el14jw 5:ae641b1d04fa 787 fp = fopen("/sd/snakehighscore.txt","w");
el14jw 5:ae641b1d04fa 788 if (fp != NULL) {
el14jw 5:ae641b1d04fa 789 fprintf(fp,"%d",-2);
el14jw 5:ae641b1d04fa 790 fclose(fp);
el14jw 5:ae641b1d04fa 791 }
el14jw 5:ae641b1d04fa 792 } else {
el14jw 5:ae641b1d04fa 793 fclose(fp);
el14jw 5:ae641b1d04fa 794 }
el14jw 5:ae641b1d04fa 795
el14jw 0:23a749719479 796 wait(1.0);
el14jw 0:23a749719479 797 }
el14jw 5:ae641b1d04fa 798
el14jw 0:23a749719479 799 // Hangs on an error
el14jw 0:23a749719479 800 void error()
el14jw 0:23a749719479 801 {
el14jw 0:23a749719479 802 while(1) {
el14jw 0:23a749719479 803 errorLED = !errorLED;
el14jw 0:23a749719479 804 wait(0.2);
el14jw 0:23a749719479 805 }
el14jw 0:23a749719479 806 }
el14jw 0:23a749719479 807
el14jw 0:23a749719479 808 // Menu function for handling the printing and selecting of menu screens
el14jw 0:23a749719479 809 int menu(const stringList* menuList,int lines)
el14jw 0:23a749719479 810 {
el14jw 0:23a749719479 811 int select = 0;
el14jw 1:c4928de1f922 812 // While either joystick button or button A or button B are not on then continue selection process
el14jw 1:c4928de1f922 813 // Once either button is on the the selected value is returned
el14jw 1:c4928de1f922 814 while(g_buttonjoy_flag == 0 && g_buttonA_flag == 0 && g_buttonB_flag == 0) {
el14jw 0:23a749719479 815
el14jw 0:23a749719479 816 // Changes the value of variable select determined by what the joystick value is
el14jw 0:23a749719479 817 if (g_joystick_flag) {
el14jw 0:23a749719479 818 if (joystick.direction == UP) {
el14jw 0:23a749719479 819 if (select == 0) {
el14jw 0:23a749719479 820 select = lines-2;
el14jw 0:23a749719479 821 } else {
el14jw 0:23a749719479 822 select--;
el14jw 0:23a749719479 823 }
el14jw 0:23a749719479 824 } else if(joystick.direction == DOWN) {
el14jw 0:23a749719479 825 if (select == lines-2) {
el14jw 0:23a749719479 826 select = 0;
el14jw 0:23a749719479 827 } else {
el14jw 0:23a749719479 828 select++;
el14jw 0:23a749719479 829 }
el14jw 0:23a749719479 830 }
el14jw 0:23a749719479 831 }
el14jw 0:23a749719479 832
el14jw 0:23a749719479 833 // Prints the correct strings
el14jw 0:23a749719479 834 drawStrings(menuList,lines);
el14jw 1:c4928de1f922 835 int line = select + 1;
el14jw 0:23a749719479 836 char buffer[14];
el14jw 1:c4928de1f922 837 sprintf(buffer,">> %s",menuList[line].str);
el14jw 1:c4928de1f922 838 lcd.printString(buffer,menuList[line].offset,line);
el14jw 1:c4928de1f922 839
el14jw 0:23a749719479 840 if (g_joystick_flag) {
el14jw 0:23a749719479 841 g_joystick_flag = 0;
el14jw 1:c4928de1f922 842 // Adds acceptable scrolling delay
el14jw 0:23a749719479 843 wait(0.2);
el14jw 0:23a749719479 844 }
el14jw 0:23a749719479 845 sleep();
el14jw 0:23a749719479 846 }
el14jw 0:23a749719479 847 // Debouncing
el14jw 1:c4928de1f922 848 wait(0.2);
el14jw 0:23a749719479 849 g_buttonjoy_flag = 0;
el14jw 0:23a749719479 850 g_buttonA_flag = 0;
el14jw 1:c4928de1f922 851 // Returns -1 if B is pressed to automatically go back a menu
el14jw 1:c4928de1f922 852 if (g_buttonB_flag) {
el14jw 1:c4928de1f922 853 g_buttonB_flag = 0;
el14jw 1:c4928de1f922 854 select = -1;
el14jw 1:c4928de1f922 855 }
el14jw 0:23a749719479 856 return select;
el14jw 0:23a749719479 857 }
el14jw 1:c4928de1f922 858 // Draw Strings function used for plotting an array of stringList to the LCD
el14jw 0:23a749719479 859 void drawStrings(const stringList* list,int lines)
el14jw 0:23a749719479 860 {
el14jw 0:23a749719479 861 lcd.clear();
el14jw 0:23a749719479 862 for (int i=0; i<lines; i++) {
el14jw 0:23a749719479 863 lcd.printString(list[i].str,list[i].offset,i);
el14jw 0:23a749719479 864 }
el14jw 0:23a749719479 865 }
el14jw 0:23a749719479 866
el14jw 0:23a749719479 867
el14jw 0:23a749719479 868 /// Read default positions of the joystick to calibrate later readings
el14jw 0:23a749719479 869 void calibrateJoystick()
el14jw 0:23a749719479 870 {
el14jw 0:23a749719479 871 // must not move during calibration
el14jw 0:23a749719479 872 joystick.x0 = xPot; /// initial positions in the range 0.0 to 1.0 (0.5 if centred exactly)
el14jw 0:23a749719479 873 joystick.y0 = yPot;
el14jw 0:23a749719479 874 }
el14jw 0:23a749719479 875 void updateJoystick()
el14jw 0:23a749719479 876 {
el14jw 0:23a749719479 877 /// read current joystick values relative to calibrated values (in range -0.5 to 0.5, 0.0 is centred)
el14jw 0:23a749719479 878 joystick.x = xPot - joystick.x0;
el14jw 0:23a749719479 879 joystick.y = yPot - joystick.y0;
el14jw 0:23a749719479 880
el14jw 0:23a749719479 881 // calculate direction depending on x,y values
el14jw 0:23a749719479 882 // tolerance allows a little lee-way in case joystick not exactly in the stated direction
el14jw 0:23a749719479 883 if ( fabs(joystick.y) < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
el14jw 0:23a749719479 884 joystick.direction = CENTRE;
el14jw 2:80a91a737e17 885 } else if ( joystick.y < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
el14jw 0:23a749719479 886 joystick.direction = UP;
el14jw 2:80a91a737e17 887 } else if ( joystick.y > DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
el14jw 0:23a749719479 888 joystick.direction = DOWN;
el14jw 0:23a749719479 889 } else if ( joystick.x > DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
el14jw 0:23a749719479 890 joystick.direction = RIGHT;
el14jw 0:23a749719479 891 } else if ( joystick.x < DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
el14jw 0:23a749719479 892 joystick.direction = LEFT;
el14jw 0:23a749719479 893 } else {
el14jw 0:23a749719479 894 joystick.direction = UNKNOWN;
el14jw 0:23a749719479 895 }
el14jw 0:23a749719479 896
el14jw 0:23a749719479 897 // set flag for printing
el14jw 0:23a749719479 898 g_joystick_flag = 1;
el14jw 0:23a749719479 899 }