ELEC2645 (2015/16) / Mbed 2 deprecated el14jw_Project

Dependencies:   N5110 SDFileSystem mbed

Committer:
el14jw
Date:
Wed Apr 27 12:43:34 2016 +0000
Revision:
4:c2d920b17b14
Parent:
3:02d9072a2507
Child:
5:ae641b1d04fa
- Added Score displayed to plink 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 0:23a749719479 6 @brief Revision 1.0
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 0:23a749719479 33 /// Joystick struct for storing data about default Joystick position and Current position
el14jw 0:23a749719479 34 Joystick joystick;
el14jw 0:23a749719479 35 /// Ticker interrput for polling the joystick
el14jw 0:23a749719479 36 Ticker pollJoystick;
el14jw 4:c2d920b17b14 37 /// Ticker for controlling refresh rate of games
el14jw 2:80a91a737e17 38 Ticker gametick;
el14jw 4:c2d920b17b14 39 /// File pointer for accessing SD card locations
el14jw 1:c4928de1f922 40 FILE *fp;
el14jw 0:23a749719479 41
el14jw 0:23a749719479 42
el14jw 0:23a749719479 43 int main()
el14jw 0:23a749719479 44 {
el14jw 0:23a749719479 45 initInputs();
el14jw 0:23a749719479 46 playSound(tune_intro);
el14jw 1:c4928de1f922 47 // Initialise file pointer
el14jw 0:23a749719479 48
el14jw 4:c2d920b17b14 49 int snakeDifficulty = 1;
el14jw 1:c4928de1f922 50 int plinkDifficulty = 0;
el14jw 0:23a749719479 51 while (true) {
el14jw 1:c4928de1f922 52
el14jw 0:23a749719479 53 // Main menu screen
el14jw 1:c4928de1f922 54 int select = menu(menuList,3);
el14jw 0:23a749719479 55
el14jw 0:23a749719479 56 // Selected Snake
el14jw 0:23a749719479 57 if (select == 0) {
el14jw 1:c4928de1f922 58 // If select = 3 or -1 then user has chosen 'Back' button
el14jw 1:c4928de1f922 59 while( !(select == 3 || select ==-1) ) {
el14jw 0:23a749719479 60
el14jw 0:23a749719479 61 // Snake selection screen
el14jw 1:c4928de1f922 62 select = menu(snakeList,5);
el14jw 1:c4928de1f922 63 if (select == 0) {
el14jw 1:c4928de1f922 64 // Play Snake game
el14jw 1:c4928de1f922 65 snake(snakeDifficulty);
el14jw 1:c4928de1f922 66 }
el14jw 0:23a749719479 67 // Selected Difficulty
el14jw 1:c4928de1f922 68 else if (select == 1) {
el14jw 0:23a749719479 69 // Difficulty selection screen
el14jw 1:c4928de1f922 70 int tempdiff = snakeDifficulty;
el14jw 1:c4928de1f922 71 snakeDifficulty = menu(difficultyList,4);
el14jw 1:c4928de1f922 72 if (snakeDifficulty == -1) {
el14jw 1:c4928de1f922 73 snakeDifficulty = tempdiff;
el14jw 1:c4928de1f922 74 }
el14jw 0:23a749719479 75 }
el14jw 1:c4928de1f922 76 // Highscore
el14jw 1:c4928de1f922 77 else if (select == 2) {
el14jw 1:c4928de1f922 78 fp = fopen("/sd/snakehighscore.txt", "r");
el14jw 1:c4928de1f922 79 wait(0.05);
el14jw 1:c4928de1f922 80 int stored_top_score = -1; // -1 to demonstrate it has changed after reading
el14jw 1:c4928de1f922 81
el14jw 1:c4928de1f922 82 lcd.clear();
el14jw 1:c4928de1f922 83 if (fp == NULL) { // if it can't open the file then print error message
el14jw 1:c4928de1f922 84 lcd.printString("No Results",0,0);
el14jw 1:c4928de1f922 85 wait(2.0);
el14jw 1:c4928de1f922 86 } else { // opened file so can write
el14jw 1:c4928de1f922 87 while ( ! (g_buttonA_flag || g_buttonjoy_flag)) {
el14jw 1:c4928de1f922 88 fscanf(fp,"%d",&stored_top_score); // ensure data type matches - note address operator (&)
el14jw 1:c4928de1f922 89 fclose(fp); // ensure you close the file after reading
el14jw 1:c4928de1f922 90 lcd.printString("Highscore:",10,0);
el14jw 1:c4928de1f922 91 if (stored_top_score != -2) {
el14jw 1:c4928de1f922 92 char buffer[14];
el14jw 1:c4928de1f922 93 sprintf(buffer,"%d",stored_top_score);
el14jw 1:c4928de1f922 94 lcd.printString(buffer,0,1);
el14jw 1:c4928de1f922 95 } else {
el14jw 1:c4928de1f922 96 lcd.printString("No Saved Score",0,1);
el14jw 1:c4928de1f922 97 }
el14jw 1:c4928de1f922 98 lcd.printString(">> Back",0,2);
el14jw 1:c4928de1f922 99 sleep();
el14jw 1:c4928de1f922 100 }
el14jw 1:c4928de1f922 101 g_buttonjoy_flag = 0;
el14jw 1:c4928de1f922 102 g_buttonA_flag = 0;
el14jw 1:c4928de1f922 103 }
el14jw 1:c4928de1f922 104 }
el14jw 1:c4928de1f922 105
el14jw 0:23a749719479 106 }
el14jw 0:23a749719479 107 }
el14jw 0:23a749719479 108
el14jw 1:c4928de1f922 109 // Selected Plink
el14jw 0:23a749719479 110 else if (select == 1) {
el14jw 1:c4928de1f922 111 // If select = 3 or -1 then user has chosen 'Back' button
el14jw 1:c4928de1f922 112 while( !(select == 3 || select ==-1) ) {
el14jw 0:23a749719479 113
el14jw 1:c4928de1f922 114 select = menu(plinkList,5);
el14jw 1:c4928de1f922 115 // Start Plink
el14jw 1:c4928de1f922 116 if (select == 0) {
el14jw 0:23a749719479 117 playSound(tune_intro);
el14jw 1:c4928de1f922 118 plink(plinkDifficulty);
el14jw 1:c4928de1f922 119 }
el14jw 1:c4928de1f922 120 // Difficulty selection
el14jw 1:c4928de1f922 121 else if (select == 1) {
el14jw 1:c4928de1f922 122 int tempdiff = plinkDifficulty;
el14jw 1:c4928de1f922 123 plinkDifficulty = menu(difficultyList,4);
el14jw 1:c4928de1f922 124 if (plinkDifficulty == -1) {
el14jw 1:c4928de1f922 125 plinkDifficulty = tempdiff;
el14jw 1:c4928de1f922 126 }
el14jw 1:c4928de1f922 127 }
el14jw 1:c4928de1f922 128 // Highscore
el14jw 1:c4928de1f922 129 else if (select == 2) {
el14jw 1:c4928de1f922 130 fp = fopen("/sd/plinkhighscore.txt", "r");
el14jw 1:c4928de1f922 131 wait(0.05);
el14jw 1:c4928de1f922 132 int stored_top_score = -2; // -2 to demonstrate it has changed after reading
el14jw 1:c4928de1f922 133
el14jw 1:c4928de1f922 134 lcd.clear();
el14jw 1:c4928de1f922 135 if (fp == NULL) { // if it can't open the file then print error message
el14jw 1:c4928de1f922 136 lcd.printString("No Results",0,0);
el14jw 1:c4928de1f922 137 wait(2.0);
el14jw 1:c4928de1f922 138 } else { // opened file so can read
el14jw 1:c4928de1f922 139 while ( ! (g_buttonA_flag || g_buttonjoy_flag)) {
el14jw 1:c4928de1f922 140 fscanf(fp,"%d",&stored_top_score); // ensure data type matches - note address operator (&)
el14jw 1:c4928de1f922 141 fclose(fp); // ensure you close the file after reading
el14jw 1:c4928de1f922 142 lcd.printString("Highscore",10,0);
el14jw 1:c4928de1f922 143 if (stored_top_score !=-2) {
el14jw 1:c4928de1f922 144 char buffer[14];
el14jw 1:c4928de1f922 145 sprintf(buffer,"%d",stored_top_score);
el14jw 1:c4928de1f922 146 lcd.printString(buffer,0,1);
el14jw 1:c4928de1f922 147 } else {
el14jw 1:c4928de1f922 148 lcd.printString("No Saved Score",0,1);
el14jw 1:c4928de1f922 149 }
el14jw 1:c4928de1f922 150 lcd.printString(">> Back",0,2);
el14jw 1:c4928de1f922 151 sleep();
el14jw 1:c4928de1f922 152 }
el14jw 1:c4928de1f922 153 g_buttonjoy_flag = 0;
el14jw 1:c4928de1f922 154 g_buttonA_flag = 0;
el14jw 1:c4928de1f922 155 }
el14jw 0:23a749719479 156 }
el14jw 0:23a749719479 157 }
el14jw 0:23a749719479 158 }
el14jw 0:23a749719479 159
el14jw 0:23a749719479 160 sleep();
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 1:c4928de1f922 313 if (current_high_score != -1 && current_high_score < score) {
el14jw 1:c4928de1f922 314 lcd.printString("New High Score",0,1);
el14jw 1:c4928de1f922 315 lcd.printString("Previously",0,3);
el14jw 1:c4928de1f922 316 } else if (current_high_score != -1 && current_high_score > score) {
el14jw 1:c4928de1f922 317 lcd.printString("Score",0,1);
el14jw 1:c4928de1f922 318 lcd.printString("High Score",0,3);
el14jw 1:c4928de1f922 319 } else {
el14jw 1:c4928de1f922 320 lcd.printString("Score:",0,1);
el14jw 1:c4928de1f922 321 lcd.printString("No Previous",0,3);
el14jw 1:c4928de1f922 322 }
el14jw 1:c4928de1f922 323 // Print score
el14jw 1:c4928de1f922 324 char buffer[14];
el14jw 1:c4928de1f922 325 sprintf(buffer,"%d",score);
el14jw 1:c4928de1f922 326 lcd.printString(buffer,20,2);
el14jw 1:c4928de1f922 327 // Print previous high-score
el14jw 1:c4928de1f922 328 if (current_high_score != -1) {
el14jw 1:c4928de1f922 329 char str[14];
el14jw 1:c4928de1f922 330 sprintf(str,"%d",current_high_score);
el14jw 1:c4928de1f922 331 lcd.printString(str,20,4);
el14jw 1:c4928de1f922 332 }
el14jw 1:c4928de1f922 333
el14jw 0:23a749719479 334 playSound(tune_gameOver);
el14jw 0:23a749719479 335 wait(3.0);
el14jw 0:23a749719479 336 g_buttonA_flag = 0;
el14jw 1:c4928de1f922 337 g_buttonB_flag = 0;
el14jw 0:23a749719479 338 g_buttonjoy_flag = 0;
el14jw 0:23a749719479 339 }
el14jw 1:c4928de1f922 340
el14jw 1:c4928de1f922 341
el14jw 1:c4928de1f922 342 // PLINK
el14jw 1:c4928de1f922 343
el14jw 1:c4928de1f922 344 void plink(int difficulty)
el14jw 0:23a749719479 345 {
el14jw 1:c4928de1f922 346 playSound(tune_plinkintro);
el14jw 1:c4928de1f922 347 lcd.clear();
el14jw 3:02d9072a2507 348 // 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 349
el14jw 3:02d9072a2507 350 plinkvar pvar;
el14jw 3:02d9072a2507 351 pvar.difficulty = difficulty;
el14jw 2:80a91a737e17 352
el14jw 3:02d9072a2507 353 // Initialise plink variables
el14jw 3:02d9072a2507 354 pvar = initpvar(pvar);
el14jw 1:c4928de1f922 355
el14jw 2:80a91a737e17 356 // Game ticker
el14jw 1:c4928de1f922 357 int refreshRate = 100;
el14jw 1:c4928de1f922 358 float tickerDelay = 1.0/refreshRate;
el14jw 3:02d9072a2507 359 pvar.tickerDelay = tickerDelay;
el14jw 1:c4928de1f922 360 gametick.attach(&gametick_isr,tickerDelay);
el14jw 3:02d9072a2507 361 wait(0.25);
el14jw 2:80a91a737e17 362
el14jw 3:02d9072a2507 363 while(!pvar.gameOver) {
el14jw 1:c4928de1f922 364 if (g_gametick_flag) {
el14jw 1:c4928de1f922 365
el14jw 1:c4928de1f922 366 // Screen scrolling
el14jw 3:02d9072a2507 367 pvar = plinkScroll(pvar);
el14jw 1:c4928de1f922 368 // Platform generation
el14jw 3:02d9072a2507 369 pvar = plinkPlatGen(pvar);
el14jw 1:c4928de1f922 370 // Collisions
el14jw 3:02d9072a2507 371 pvar = plinkCollisions(pvar);
el14jw 3:02d9072a2507 372 // Physics Engine
el14jw 3:02d9072a2507 373 pvar = plinkPhysicsEngine(pvar);
el14jw 3:02d9072a2507 374 // LCD drawing
el14jw 3:02d9072a2507 375 pvar = plinkDrawScreen(pvar);
el14jw 1:c4928de1f922 376
el14jw 1:c4928de1f922 377 }
el14jw 3:02d9072a2507 378 // Sleep to conserve power until next interrupt
el14jw 3:02d9072a2507 379 sleep();
el14jw 0:23a749719479 380 }
el14jw 1:c4928de1f922 381
el14jw 1:c4928de1f922 382 gametick.detach();
el14jw 1:c4928de1f922 383 lcd.clear();
el14jw 4:c2d920b17b14 384
el14jw 4:c2d920b17b14 385 // Handle high scores and printing game over messages to LCD
el14jw 3:02d9072a2507 386 pvar = plinkGameOver(pvar);
el14jw 4:c2d920b17b14 387
el14jw 4:c2d920b17b14 388 }
el14jw 3:02d9072a2507 389
el14jw 3:02d9072a2507 390 plinkvar initpvar(plinkvar pvar)
el14jw 3:02d9072a2507 391 {
el14jw 3:02d9072a2507 392 // Initial physics conditions
el14jw 3:02d9072a2507 393 vector pos = {41,47};
el14jw 3:02d9072a2507 394 vector vel = {0,-25};
el14jw 3:02d9072a2507 395 vector acc = {0,10};
el14jw 3:02d9072a2507 396 pvar.pos = pos;
el14jw 3:02d9072a2507 397 pvar.vel = vel;
el14jw 3:02d9072a2507 398 pvar.acc = acc;
el14jw 3:02d9072a2507 399
el14jw 3:02d9072a2507 400 // Initialising game parameters
el14jw 3:02d9072a2507 401 pvar.height = 0; // This is the number of pixels that the lcd has 'scrolled' by
el14jw 3:02d9072a2507 402 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 403 pvar.platformWidth = 7 - (pvar.difficulty * 2); // Platform width is based on difficulty and also changed by power ups
el14jw 3:02d9072a2507 404 cell powerUp = {42,-100}; // The first power up can be found at these coordinates
el14jw 3:02d9072a2507 405 pvar.powerUp = powerUp;
el14jw 3:02d9072a2507 406 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 407 pvar.powerUpRadius = 5; // Helpful parameter for detecting collisions
el14jw 3:02d9072a2507 408 pvar.ballRadius = 2; // Also helpful parameter for detecting collisions and is changed in 2 power up cases
el14jw 3:02d9072a2507 409
el14jw 3:02d9072a2507 410 // Initialising platforms
el14jw 3:02d9072a2507 411 pvar.platforms[0].x = 42;
el14jw 3:02d9072a2507 412 pvar.platforms[0].y = 46;
el14jw 3:02d9072a2507 413 for (int i=1; i<20; i++) {
el14jw 3:02d9072a2507 414 pvar.platforms[i].x = rand()%(84-pvar.platformWidth) + (pvar.platformWidth-1)/2;
el14jw 3:02d9072a2507 415 pvar.platforms[i].y = pvar.platforms[i-1].y - (rand()%10 + 5);
el14jw 3:02d9072a2507 416 }
el14jw 3:02d9072a2507 417
el14jw 3:02d9072a2507 418 return pvar;
el14jw 3:02d9072a2507 419 }
el14jw 3:02d9072a2507 420 plinkvar plinkScroll(plinkvar pvar)
el14jw 3:02d9072a2507 421 {
el14jw 3:02d9072a2507 422 // Scrolling Block
el14jw 3:02d9072a2507 423 while (pvar.pos.y < 14) {
el14jw 3:02d9072a2507 424 pvar.pos.y++;
el14jw 3:02d9072a2507 425 pvar.height++;
el14jw 3:02d9072a2507 426 pvar.powerUpHeight++;
el14jw 3:02d9072a2507 427 for (int i=0; i<20; i++) {
el14jw 3:02d9072a2507 428 pvar.platforms[i].y++;
el14jw 3:02d9072a2507 429 }
el14jw 3:02d9072a2507 430 pvar.powerUp.y++;
el14jw 3:02d9072a2507 431 }
el14jw 3:02d9072a2507 432 return pvar;
el14jw 3:02d9072a2507 433 }
el14jw 3:02d9072a2507 434 plinkvar plinkPlatGen(plinkvar pvar)
el14jw 3:02d9072a2507 435 {
el14jw 3:02d9072a2507 436 // Platform generation
el14jw 3:02d9072a2507 437 for (int i=0; i<20; i++) {
el14jw 3:02d9072a2507 438 if (pvar.platforms[i].y > 47) {
el14jw 3:02d9072a2507 439 // Stage 1
el14jw 3:02d9072a2507 440 if (pvar.height <= 500) {
el14jw 3:02d9072a2507 441 if (i == 0) {
el14jw 3:02d9072a2507 442 pvar.platforms[0].x = rand()%(84-pvar.platformWidth) + (pvar.platformWidth-1)/2;
el14jw 3:02d9072a2507 443 pvar.platforms[0].y = pvar.platforms[19].y - (rand()%10 + 5);
el14jw 3:02d9072a2507 444 } else {
el14jw 3:02d9072a2507 445 pvar.platforms[i].x = rand()%(84-pvar.platformWidth) + (pvar.platformWidth-1)/2;
el14jw 3:02d9072a2507 446 pvar.platforms[i].y = pvar.platforms[i-1].y - (rand()%10 + 5);
el14jw 3:02d9072a2507 447 }
el14jw 3:02d9072a2507 448 }
el14jw 3:02d9072a2507 449 // Stage 2
el14jw 3:02d9072a2507 450 else if (500 < pvar.height <= 1000) {
el14jw 3:02d9072a2507 451 if (i == 0) {
el14jw 3:02d9072a2507 452 pvar.platforms[0].x = rand()%(84-pvar.platformWidth) + (pvar.platformWidth-1)/2;
el14jw 3:02d9072a2507 453 pvar.platforms[0].y = pvar.platforms[19].y - (rand()%10 + 10);
el14jw 3:02d9072a2507 454 } else {
el14jw 3:02d9072a2507 455 pvar.platforms[i].x = rand()%(84-pvar.platformWidth) + (pvar.platformWidth-1)/2;
el14jw 3:02d9072a2507 456 pvar.platforms[i].y = pvar.platforms[i-1].y - (rand()%10 + 10);
el14jw 3:02d9072a2507 457 }
el14jw 3:02d9072a2507 458 }
el14jw 3:02d9072a2507 459 //Stage 3
el14jw 3:02d9072a2507 460 else if (pvar.height > 1000) {
el14jw 3:02d9072a2507 461 if (i == 0) {
el14jw 3:02d9072a2507 462 pvar.platforms[0].x = rand()%(84-pvar.platformWidth) + (pvar.platformWidth-1)/2;
el14jw 3:02d9072a2507 463 pvar.platforms[0].y = pvar.platforms[19].y - (rand()%10 + 15);
el14jw 3:02d9072a2507 464 } else {
el14jw 3:02d9072a2507 465 pvar.platforms[i].x = rand()%(84-pvar.platformWidth) + (pvar.platformWidth-1)/2;
el14jw 3:02d9072a2507 466 pvar.platforms[i].y = pvar.platforms[i-1].y - (rand()%10 + 15);
el14jw 3:02d9072a2507 467 }
el14jw 3:02d9072a2507 468 }
el14jw 3:02d9072a2507 469 }
el14jw 3:02d9072a2507 470 }
el14jw 3:02d9072a2507 471 return pvar;
el14jw 3:02d9072a2507 472 }
el14jw 3:02d9072a2507 473 plinkvar plinkCollisions(plinkvar pvar)
el14jw 3:02d9072a2507 474 {
el14jw 3:02d9072a2507 475 // Collisions
el14jw 3:02d9072a2507 476 // Platforms
el14jw 3:02d9072a2507 477 for (int i=0; i<20; i++) {
el14jw 3:02d9072a2507 478 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 479 pvar.vel.y = -25;
el14jw 3:02d9072a2507 480 // Play appropriate sound when bouncing
el14jw 3:02d9072a2507 481 switch (pvar.ballRadius) {
el14jw 3:02d9072a2507 482 case 1:
el14jw 3:02d9072a2507 483 playSound(tune_plinkjump_small);
el14jw 3:02d9072a2507 484 break;
el14jw 3:02d9072a2507 485 case 2:
el14jw 3:02d9072a2507 486 playSound(tune_plinkjump_normal);
el14jw 3:02d9072a2507 487 break;
el14jw 3:02d9072a2507 488 case 4:
el14jw 3:02d9072a2507 489 playSound(tune_plinkjump_big);
el14jw 3:02d9072a2507 490 break;
el14jw 3:02d9072a2507 491 }
el14jw 3:02d9072a2507 492 }
el14jw 3:02d9072a2507 493 }
el14jw 3:02d9072a2507 494 // Walls
el14jw 3:02d9072a2507 495 if (pvar.pos.x <= pvar.ballRadius) {
el14jw 3:02d9072a2507 496 pvar.vel.x = abs(pvar.vel.x);
el14jw 3:02d9072a2507 497 } else if (pvar.pos.x >= 83 - pvar.ballRadius) {
el14jw 3:02d9072a2507 498 pvar.vel.x = -abs(pvar.vel.x);
el14jw 3:02d9072a2507 499 }
el14jw 3:02d9072a2507 500 // Power Up
el14jw 3:02d9072a2507 501 if ((int)pvar.pos.x+pvar.ballRadius >= (pvar.powerUp.x-pvar.powerUpRadius)
el14jw 3:02d9072a2507 502 && (int)pvar.pos.x-pvar.ballRadius <= (pvar.powerUp.x+pvar.powerUpRadius)
el14jw 3:02d9072a2507 503 && (int)pvar.pos.y+pvar.ballRadius >= (pvar.powerUp.y-pvar.powerUpRadius)
el14jw 3:02d9072a2507 504 && (int)pvar.pos.y-pvar.ballRadius <= (pvar.powerUp.y+pvar.powerUpRadius)) {
el14jw 3:02d9072a2507 505 // Create new powerUp box at the next 100 mark
el14jw 3:02d9072a2507 506 pvar.powerUp.x = rand()%(84-1-(pvar.powerUpRadius*2)) + pvar.powerUpRadius;
el14jw 3:02d9072a2507 507 pvar.powerUp.y = -100;
el14jw 3:02d9072a2507 508
el14jw 3:02d9072a2507 509 //reset power up height
el14jw 3:02d9072a2507 510 pvar.powerUpHeight = 0;
el14jw 3:02d9072a2507 511
el14jw 3:02d9072a2507 512 // Choose new power up randomly
el14jw 3:02d9072a2507 513 switch (rand()%4) {
el14jw 3:02d9072a2507 514 case 0:
el14jw 3:02d9072a2507 515 pvar.ballRadius = 4;
el14jw 3:02d9072a2507 516 break;
el14jw 3:02d9072a2507 517 case 1:
el14jw 3:02d9072a2507 518 pvar.ballRadius = 1;
el14jw 3:02d9072a2507 519 break;
el14jw 3:02d9072a2507 520 case 2:
el14jw 3:02d9072a2507 521 pvar.platformWidth = 11;
el14jw 3:02d9072a2507 522 break;
el14jw 3:02d9072a2507 523 case 3:
el14jw 3:02d9072a2507 524 pvar.platformWidth = 5;
el14jw 3:02d9072a2507 525 break;
el14jw 3:02d9072a2507 526 default:
el14jw 3:02d9072a2507 527 error();
el14jw 3:02d9072a2507 528 }
el14jw 4:c2d920b17b14 529 }
el14jw 4:c2d920b17b14 530 // If the powerup has been missed then generate new one
el14jw 4:c2d920b17b14 531 else if (pvar.powerUp.y > 47+pvar.powerUpRadius) {
el14jw 3:02d9072a2507 532 pvar.powerUp.x = rand()%(84-1-(pvar.powerUpRadius*2)) + pvar.powerUpRadius;
el14jw 3:02d9072a2507 533 pvar.powerUp.y = -150;
el14jw 3:02d9072a2507 534 }
el14jw 4:c2d920b17b14 535 // After certain height achieved then cancel power up
el14jw 3:02d9072a2507 536 if (pvar.powerUpHeight > 100) {
el14jw 3:02d9072a2507 537 pvar.ballRadius = 2;
el14jw 3:02d9072a2507 538 pvar.platformWidth = 7 - (pvar.difficulty * 2);
el14jw 3:02d9072a2507 539 }
el14jw 3:02d9072a2507 540 return pvar;
el14jw 3:02d9072a2507 541 }
el14jw 3:02d9072a2507 542 plinkvar plinkPhysicsEngine(plinkvar pvar)
el14jw 3:02d9072a2507 543 {
el14jw 3:02d9072a2507 544 // Physics engine
el14jw 3:02d9072a2507 545 // Acceleration due to joystick
el14jw 3:02d9072a2507 546 if (g_joystick_flag) {
el14jw 3:02d9072a2507 547 if (joystick.direction == LEFT) {
el14jw 3:02d9072a2507 548 pvar.acc.x = -15;
el14jw 3:02d9072a2507 549 } else if (joystick.direction == RIGHT) {
el14jw 3:02d9072a2507 550 pvar.acc.x = 15;
el14jw 3:02d9072a2507 551 } else {
el14jw 3:02d9072a2507 552 pvar.acc.x = 0;
el14jw 3:02d9072a2507 553 }
el14jw 3:02d9072a2507 554 }
el14jw 4:c2d920b17b14 555 // physics iteration
el14jw 3:02d9072a2507 556 pvar.vel.y = pvar.vel.y + (pvar.acc.y * pvar.tickerDelay * 4);
el14jw 3:02d9072a2507 557 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 558 pvar.pos.y = pvar.pos.y + (pvar.vel.y * pvar.tickerDelay * 4);
el14jw 3:02d9072a2507 559 pvar.pos.x = pvar.pos.x + (pvar.vel.x * pvar.tickerDelay * 4);
el14jw 3:02d9072a2507 560 // Boundaries of physics engine
el14jw 3:02d9072a2507 561 if (pvar.pos.y > 48) {
el14jw 3:02d9072a2507 562 pvar.gameOver = 1;
el14jw 3:02d9072a2507 563 }
el14jw 4:c2d920b17b14 564 // If ball is out of boundaries then place it back in boundaries
el14jw 3:02d9072a2507 565 if (pvar.pos.x - pvar.ballRadius < 0) {
el14jw 3:02d9072a2507 566 pvar.pos.x = pvar.ballRadius;
el14jw 3:02d9072a2507 567 } else if (pvar.pos.x + pvar.ballRadius > 83) {
el14jw 3:02d9072a2507 568 pvar.pos.x = 83-pvar.ballRadius;
el14jw 3:02d9072a2507 569 }
el14jw 3:02d9072a2507 570 return pvar;
el14jw 3:02d9072a2507 571 }
el14jw 3:02d9072a2507 572 plinkvar plinkDrawScreen(plinkvar pvar)
el14jw 3:02d9072a2507 573 {
el14jw 3:02d9072a2507 574 // Drawing on lcd
el14jw 3:02d9072a2507 575 lcd.clear();
el14jw 4:c2d920b17b14 576 // Drawing ball/blob
el14jw 3:02d9072a2507 577 // If second blob stage
el14jw 3:02d9072a2507 578 int noPlatform = 1;
el14jw 3:02d9072a2507 579 if (pvar.ballRadius == 2) {
el14jw 3:02d9072a2507 580 for (int i=0; i<20; i++) {
el14jw 3:02d9072a2507 581 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 3:02d9072a2507 582 noPlatform = 0;
el14jw 3:02d9072a2507 583 lcd.drawRect(pvar.pos.x-2,pvar.pos.y-1,4,2,1); // X, Y, Width, Height, Fill
el14jw 3:02d9072a2507 584 lcd.setPixel(pvar.pos.x-1,pvar.pos.y-2);
el14jw 3:02d9072a2507 585 lcd.setPixel(pvar.pos.x,pvar.pos.y-2);
el14jw 3:02d9072a2507 586 lcd.setPixel(pvar.pos.x+1,pvar.pos.y-2);
el14jw 3:02d9072a2507 587 lcd.setPixel(pvar.pos.x-3,pvar.pos.y+1);
el14jw 3:02d9072a2507 588 lcd.setPixel(pvar.pos.x+3,pvar.pos.y+1);
el14jw 3:02d9072a2507 589 }
el14jw 3:02d9072a2507 590 // If third blob stage
el14jw 3:02d9072a2507 591 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 3:02d9072a2507 592 noPlatform = 0;
el14jw 3:02d9072a2507 593 lcd.drawRect(pvar.pos.x-3,pvar.pos.y-1,6,1,1); // X, Y, Width, Height, Fill
el14jw 3:02d9072a2507 594 lcd.setPixel(pvar.pos.x-4,pvar.pos.y);
el14jw 3:02d9072a2507 595 lcd.setPixel(pvar.pos.x+4,pvar.pos.y);
el14jw 3:02d9072a2507 596 lcd.setPixel(pvar.pos.x-2,pvar.pos.y-2);
el14jw 3:02d9072a2507 597 lcd.setPixel(pvar.pos.x-1,pvar.pos.y-2);
el14jw 3:02d9072a2507 598 lcd.setPixel(pvar.pos.x,pvar.pos.y-2);
el14jw 3:02d9072a2507 599 lcd.setPixel(pvar.pos.x+1,pvar.pos.y-2);
el14jw 3:02d9072a2507 600 lcd.setPixel(pvar.pos.x+2,pvar.pos.y-2);
el14jw 3:02d9072a2507 601 }
el14jw 3:02d9072a2507 602 }
el14jw 3:02d9072a2507 603 }
el14jw 3:02d9072a2507 604 // Else default blob stage
el14jw 3:02d9072a2507 605 if (noPlatform == 1) {
el14jw 3:02d9072a2507 606 lcd.drawCircle((int)pvar.pos.x,(int)pvar.pos.y,pvar.ballRadius,1); // X, Y, Radius, Fill
el14jw 3:02d9072a2507 607 lcd.refresh();
el14jw 3:02d9072a2507 608 }
el14jw 4:c2d920b17b14 609 // Platforms and boundaries drawing
el14jw 3:02d9072a2507 610 for (int i=0; i<20; i++) {
el14jw 3:02d9072a2507 611 if (pvar.platforms[i].y > 0) {
el14jw 3:02d9072a2507 612 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 613 }
el14jw 3:02d9072a2507 614 }
el14jw 3:02d9072a2507 615 lcd.drawLine(0,0,0,47,1); // x0,y0,x1,y1,type
el14jw 3:02d9072a2507 616 lcd.drawLine(83,0,83,47,1);
el14jw 4:c2d920b17b14 617 // PowerUp drawing
el14jw 3:02d9072a2507 618 if (pvar.powerUp.y > 0-pvar.powerUpRadius && pvar.powerUp.y < 47+pvar.powerUpRadius) {
el14jw 3:02d9072a2507 619 lcd.drawRect(pvar.powerUp.x-pvar.powerUpRadius,pvar.powerUp.y-pvar.powerUpRadius,10,10,0); // X, Y, Width, Height, Fill
el14jw 3:02d9072a2507 620 lcd.setPixel(pvar.powerUp.x,pvar.powerUp.y+3);
el14jw 3:02d9072a2507 621 lcd.setPixel(pvar.powerUp.x,pvar.powerUp.y+1);
el14jw 3:02d9072a2507 622 lcd.setPixel(pvar.powerUp.x+1,pvar.powerUp.y);
el14jw 3:02d9072a2507 623 lcd.setPixel(pvar.powerUp.x+2,pvar.powerUp.y-1);
el14jw 3:02d9072a2507 624 lcd.setPixel(pvar.powerUp.x+2,pvar.powerUp.y-2);
el14jw 3:02d9072a2507 625 lcd.setPixel(pvar.powerUp.x+1,pvar.powerUp.y-3);
el14jw 3:02d9072a2507 626 lcd.setPixel(pvar.powerUp.x,pvar.powerUp.y-3);
el14jw 3:02d9072a2507 627 lcd.setPixel(pvar.powerUp.x-1,pvar.powerUp.y-3);
el14jw 3:02d9072a2507 628 lcd.setPixel(pvar.powerUp.x-2,pvar.powerUp.y-2);
el14jw 3:02d9072a2507 629 }
el14jw 3:02d9072a2507 630
el14jw 3:02d9072a2507 631 lcd.refresh();
el14jw 3:02d9072a2507 632 // Looks more pleasing when the ball pauses to bounce
el14jw 3:02d9072a2507 633 if (noPlatform == 0) {
el14jw 3:02d9072a2507 634 wait(0.03);
el14jw 3:02d9072a2507 635 }
el14jw 4:c2d920b17b14 636 char buffer[14];
el14jw 4:c2d920b17b14 637 sprintf(buffer,"Score: %d",pvar.height);
el14jw 4:c2d920b17b14 638 lcd.printString(buffer,0,0);
el14jw 3:02d9072a2507 639
el14jw 3:02d9072a2507 640 return pvar;
el14jw 3:02d9072a2507 641 }
el14jw 3:02d9072a2507 642 plinkvar plinkGameOver(plinkvar pvar){
el14jw 3:02d9072a2507 643 // Handle saving high scores to SD card
el14jw 1:c4928de1f922 644 // Read previous highscore if one exists
el14jw 1:c4928de1f922 645 fp = fopen("/sd/plinkhighscore.txt", "r");
el14jw 1:c4928de1f922 646 int current_high_score = -1; // -1 to demonstrate it has changed after reading
el14jw 1:c4928de1f922 647
el14jw 1:c4928de1f922 648 if (fp == NULL) { // if it can't open the file then print error message
el14jw 1:c4928de1f922 649 lcd.printString("Failed Read",0,5);
el14jw 1:c4928de1f922 650 } else { // opened file so can write
el14jw 1:c4928de1f922 651 fscanf(fp,"%d",&current_high_score); // ensure data type matches - note address operator (&)
el14jw 1:c4928de1f922 652 fclose(fp); // ensure you close the file after reading
el14jw 1:c4928de1f922 653 }
el14jw 1:c4928de1f922 654
el14jw 1:c4928de1f922 655 // Writing score to sd card if new high score
el14jw 3:02d9072a2507 656 if (current_high_score < pvar.height && current_high_score != -1) {
el14jw 1:c4928de1f922 657 fp = fopen("/sd/plinkhighscore.txt", "w");
el14jw 1:c4928de1f922 658 if (fp == NULL) { // if it can't open the file then print error message
el14jw 1:c4928de1f922 659 lcd.printString("No SD Card ",0,5);
el14jw 1:c4928de1f922 660 } else { // opened file so can write
el14jw 3:02d9072a2507 661 fprintf(fp,"%d",pvar.height); // ensure data type matches
el14jw 1:c4928de1f922 662 fclose(fp); // ensure you close the file after writing
el14jw 1:c4928de1f922 663 }
el14jw 1:c4928de1f922 664 }
el14jw 1:c4928de1f922 665
el14jw 1:c4928de1f922 666 // Appropriate strings printed to LCD
el14jw 1:c4928de1f922 667 lcd.printString("Game Over",20,0);
el14jw 3:02d9072a2507 668 if (current_high_score != -1 && current_high_score < pvar.height) {
el14jw 1:c4928de1f922 669 lcd.printString("New High Score",0,1);
el14jw 1:c4928de1f922 670 lcd.printString("Previously",0,3);
el14jw 3:02d9072a2507 671 } else if (current_high_score != -1 && current_high_score > pvar.height) {
el14jw 1:c4928de1f922 672 lcd.printString("Score",0,1);
el14jw 1:c4928de1f922 673 lcd.printString("High Score",0,3);
el14jw 1:c4928de1f922 674 } else {
el14jw 1:c4928de1f922 675 lcd.printString("Score:",0,1);
el14jw 1:c4928de1f922 676 lcd.printString("No Previous",0,3);
el14jw 1:c4928de1f922 677 }
el14jw 1:c4928de1f922 678 // Print score
el14jw 1:c4928de1f922 679 char buffer[14];
el14jw 3:02d9072a2507 680 sprintf(buffer,"%d",pvar.height);
el14jw 1:c4928de1f922 681 lcd.printString(buffer,20,2);
el14jw 1:c4928de1f922 682 // Print previous high-score
el14jw 1:c4928de1f922 683 if (current_high_score != -1) {
el14jw 1:c4928de1f922 684 char str[14];
el14jw 1:c4928de1f922 685 sprintf(str,"%d",current_high_score);
el14jw 1:c4928de1f922 686 lcd.printString(str,20,4);
el14jw 1:c4928de1f922 687 }
el14jw 2:80a91a737e17 688
el14jw 1:c4928de1f922 689 playSound(tune_gameOver);
el14jw 0:23a749719479 690 lcd.refresh();
el14jw 1:c4928de1f922 691 wait(3.0);
el14jw 4:c2d920b17b14 692 // Reset all flags so no unexpected behaviour occurs
el14jw 1:c4928de1f922 693 g_buttonA_flag = 0;
el14jw 1:c4928de1f922 694 g_buttonB_flag = 0;
el14jw 1:c4928de1f922 695 g_buttonjoy_flag = 0;
el14jw 3:02d9072a2507 696 return pvar;
el14jw 0:23a749719479 697 }
el14jw 0:23a749719479 698
el14jw 0:23a749719479 699
el14jw 0:23a749719479 700 // ISR's
el14jw 1:c4928de1f922 701 void buttonA_isr()
el14jw 1:c4928de1f922 702 {
el14jw 1:c4928de1f922 703 g_buttonA_flag = 1;
el14jw 1:c4928de1f922 704 }
el14jw 1:c4928de1f922 705 void buttonB_isr()
el14jw 1:c4928de1f922 706 {
el14jw 1:c4928de1f922 707 g_buttonB_flag = 1;
el14jw 1:c4928de1f922 708 }
el14jw 1:c4928de1f922 709 void buttonjoy_isr()
el14jw 1:c4928de1f922 710 {
el14jw 1:c4928de1f922 711 g_buttonjoy_flag = 1;
el14jw 1:c4928de1f922 712 }
el14jw 1:c4928de1f922 713 void gametick_isr()
el14jw 1:c4928de1f922 714 {
el14jw 1:c4928de1f922 715 g_gametick_flag = 1;
el14jw 1:c4928de1f922 716 }
el14jw 0:23a749719479 717
el14jw 4:c2d920b17b14 718
el14jw 0:23a749719479 719 // Initialises Inputs
el14jw 0:23a749719479 720 void initInputs()
el14jw 0:23a749719479 721 {
el14jw 0:23a749719479 722
el14jw 0:23a749719479 723 errorLED = 1;
el14jw 0:23a749719479 724
el14jw 0:23a749719479 725 /// Setting up Interrupt service routines for input buttons
el14jw 0:23a749719479 726 /// PullDown mode is assumed
el14jw 0:23a749719479 727 buttonA.rise(&buttonA_isr);
el14jw 0:23a749719479 728 buttonB.rise(&buttonB_isr);
el14jw 0:23a749719479 729 buttonjoy.rise(&buttonjoy_isr);
el14jw 0:23a749719479 730 buttonA.mode(PullDown);
el14jw 0:23a749719479 731 buttonB.mode(PullDown);
el14jw 0:23a749719479 732 buttonjoy.mode(PullDown);
el14jw 0:23a749719479 733
el14jw 0:23a749719479 734 /// Testing LCD display works (splash screen)
el14jw 0:23a749719479 735 lcd.init();
el14jw 2:80a91a737e17 736 wait(0.5);
el14jw 0:23a749719479 737 lcd.printString("Calibrating",8,0);
el14jw 0:23a749719479 738 lcd.printString("Do not move",8,1);
el14jw 0:23a749719479 739 lcd.printString("Joystick",18,2);
el14jw 0:23a749719479 740 lcd.refresh();
el14jw 0:23a749719479 741
el14jw 0:23a749719479 742 /// Calibrating the Joystick on startup
el14jw 0:23a749719479 743 calibrateJoystick();
el14jw 0:23a749719479 744 /// read joystick 10 times per second
el14jw 0:23a749719479 745 pollJoystick.attach(&updateJoystick,1.0/10.0);
el14jw 2:80a91a737e17 746 // Patch for sd casrd access not working first time
el14jw 2:80a91a737e17 747 fp = fopen("sd/test.txt","w");
el14jw 3:02d9072a2507 748 if (fp != NULL) {
el14jw 3:02d9072a2507 749 fclose(fp);
el14jw 2:80a91a737e17 750 }
el14jw 0:23a749719479 751 wait(1.0);
el14jw 0:23a749719479 752 lcd.clear();
el14jw 0:23a749719479 753 }
el14jw 0:23a749719479 754 // Hangs on an error
el14jw 0:23a749719479 755 void error()
el14jw 0:23a749719479 756 {
el14jw 0:23a749719479 757 while(1) {
el14jw 0:23a749719479 758 errorLED = !errorLED;
el14jw 0:23a749719479 759 wait(0.2);
el14jw 0:23a749719479 760 }
el14jw 0:23a749719479 761 }
el14jw 0:23a749719479 762
el14jw 0:23a749719479 763 // Menu function for handling the printing and selecting of menu screens
el14jw 0:23a749719479 764 int menu(const stringList* menuList,int lines)
el14jw 0:23a749719479 765 {
el14jw 0:23a749719479 766 int select = 0;
el14jw 1:c4928de1f922 767 // While either joystick button or button A or button B are not on then continue selection process
el14jw 1:c4928de1f922 768 // Once either button is on the the selected value is returned
el14jw 1:c4928de1f922 769 while(g_buttonjoy_flag == 0 && g_buttonA_flag == 0 && g_buttonB_flag == 0) {
el14jw 0:23a749719479 770
el14jw 0:23a749719479 771 // Changes the value of variable select determined by what the joystick value is
el14jw 0:23a749719479 772 if (g_joystick_flag) {
el14jw 0:23a749719479 773 if (joystick.direction == UP) {
el14jw 0:23a749719479 774 if (select == 0) {
el14jw 0:23a749719479 775 select = lines-2;
el14jw 0:23a749719479 776 } else {
el14jw 0:23a749719479 777 select--;
el14jw 0:23a749719479 778 }
el14jw 0:23a749719479 779 } else if(joystick.direction == DOWN) {
el14jw 0:23a749719479 780 if (select == lines-2) {
el14jw 0:23a749719479 781 select = 0;
el14jw 0:23a749719479 782 } else {
el14jw 0:23a749719479 783 select++;
el14jw 0:23a749719479 784 }
el14jw 0:23a749719479 785 }
el14jw 0:23a749719479 786 }
el14jw 0:23a749719479 787
el14jw 0:23a749719479 788 // Prints the correct strings
el14jw 0:23a749719479 789 drawStrings(menuList,lines);
el14jw 1:c4928de1f922 790 int line = select + 1;
el14jw 0:23a749719479 791 char buffer[14];
el14jw 1:c4928de1f922 792 sprintf(buffer,">> %s",menuList[line].str);
el14jw 1:c4928de1f922 793 lcd.printString(buffer,menuList[line].offset,line);
el14jw 1:c4928de1f922 794
el14jw 0:23a749719479 795 if (g_joystick_flag) {
el14jw 0:23a749719479 796 g_joystick_flag = 0;
el14jw 1:c4928de1f922 797 // Adds acceptable scrolling delay
el14jw 0:23a749719479 798 wait(0.2);
el14jw 0:23a749719479 799 }
el14jw 0:23a749719479 800 sleep();
el14jw 0:23a749719479 801 }
el14jw 0:23a749719479 802 // Debouncing
el14jw 1:c4928de1f922 803 wait(0.2);
el14jw 0:23a749719479 804 g_buttonjoy_flag = 0;
el14jw 0:23a749719479 805 g_buttonA_flag = 0;
el14jw 1:c4928de1f922 806 // Returns -1 if B is pressed to automatically go back a menu
el14jw 1:c4928de1f922 807 if (g_buttonB_flag) {
el14jw 1:c4928de1f922 808 g_buttonB_flag = 0;
el14jw 1:c4928de1f922 809 select = -1;
el14jw 1:c4928de1f922 810 }
el14jw 0:23a749719479 811 return select;
el14jw 0:23a749719479 812 }
el14jw 1:c4928de1f922 813 // Draw Strings function used for plotting an array of stringList to the LCD
el14jw 0:23a749719479 814 void drawStrings(const stringList* list,int lines)
el14jw 0:23a749719479 815 {
el14jw 0:23a749719479 816 lcd.clear();
el14jw 0:23a749719479 817 for (int i=0; i<lines; i++) {
el14jw 0:23a749719479 818 lcd.printString(list[i].str,list[i].offset,i);
el14jw 0:23a749719479 819 }
el14jw 0:23a749719479 820 }
el14jw 0:23a749719479 821
el14jw 0:23a749719479 822
el14jw 0:23a749719479 823 /// Read default positions of the joystick to calibrate later readings
el14jw 0:23a749719479 824 void calibrateJoystick()
el14jw 0:23a749719479 825 {
el14jw 0:23a749719479 826 // must not move during calibration
el14jw 0:23a749719479 827 joystick.x0 = xPot; /// initial positions in the range 0.0 to 1.0 (0.5 if centred exactly)
el14jw 0:23a749719479 828 joystick.y0 = yPot;
el14jw 0:23a749719479 829 }
el14jw 0:23a749719479 830 void updateJoystick()
el14jw 0:23a749719479 831 {
el14jw 0:23a749719479 832 /// read current joystick values relative to calibrated values (in range -0.5 to 0.5, 0.0 is centred)
el14jw 0:23a749719479 833 joystick.x = xPot - joystick.x0;
el14jw 0:23a749719479 834 joystick.y = yPot - joystick.y0;
el14jw 0:23a749719479 835
el14jw 0:23a749719479 836 // calculate direction depending on x,y values
el14jw 0:23a749719479 837 // tolerance allows a little lee-way in case joystick not exactly in the stated direction
el14jw 0:23a749719479 838 if ( fabs(joystick.y) < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
el14jw 0:23a749719479 839 joystick.direction = CENTRE;
el14jw 2:80a91a737e17 840 } else if ( joystick.y < DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
el14jw 0:23a749719479 841 joystick.direction = UP;
el14jw 2:80a91a737e17 842 } else if ( joystick.y > DIRECTION_TOLERANCE && fabs(joystick.x) < DIRECTION_TOLERANCE) {
el14jw 0:23a749719479 843 joystick.direction = DOWN;
el14jw 0:23a749719479 844 } else if ( joystick.x > DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
el14jw 0:23a749719479 845 joystick.direction = RIGHT;
el14jw 0:23a749719479 846 } else if ( joystick.x < DIRECTION_TOLERANCE && fabs(joystick.y) < DIRECTION_TOLERANCE) {
el14jw 0:23a749719479 847 joystick.direction = LEFT;
el14jw 0:23a749719479 848 } else {
el14jw 0:23a749719479 849 joystick.direction = UNKNOWN;
el14jw 0:23a749719479 850 }
el14jw 0:23a749719479 851
el14jw 0:23a749719479 852 // set flag for printing
el14jw 0:23a749719479 853 g_joystick_flag = 1;
el14jw 0:23a749719479 854 }