
Ball drop game with menus and highscore tracking developed for ELEC2645 at the University of Leeds.
Dependencies: N5110 mbed PowerControl
Game developed for ELEC 2645.
Extremely detailed report outlining all aspects of project found below. /media/uploads/AppleJuice/projectreport.pdf
Revision 19:97e0516dd6b2, committed 2015-05-08
- Comitter:
- AppleJuice
- Date:
- Fri May 08 12:17:39 2015 +0000
- Parent:
- 18:0e8b1cc24706
- Child:
- 20:2c8bf36d1702
- Commit message:
- complete. Added power control aswell
Changed in this revision
--- a/GameScreen.cpp Thu May 07 20:34:14 2015 +0000 +++ b/GameScreen.cpp Fri May 08 12:17:39 2015 +0000 @@ -233,12 +233,26 @@ printString("Hi Ball,",maxX_ - 2,-1); printString("You are",maxX_ - 2,7); printString("TRAPPED!",maxX_ - 2,15); - printString("Use the ",maxX_ - 2,23); - printString("joystick",maxX_ - 2,32); - printString("to move.",maxX_ - 2,39); - printString("Don't",maxX_ - 2,47); - printString("hit the",maxX_ - 2,55); - printString("roof!",maxX_ - 2,63); + printString("Hit the",maxX_ - 2,23); + printString("roof and",maxX_ - 2,32); + printString("you'll",maxX_ - 2,39); + printString("surely",maxX_ - 2,47); + printString("DIE!!",maxX_ - 2,55); + printString("------->",maxX_ - 2,75); + refresh(); +} + +void GameScreen::displayInstructionScreen2() +{ + clear(); + printString("CONTROLS",maxX_ - 2,-1); + printString("Use the",maxX_ - 2,15); + printString("joystick",maxX_ - 2,23); + printString("to move",maxX_ - 2,32); + printString("left or",maxX_ - 2,39); + printString("right.",maxX_ - 2,47); + printString("Click to",maxX_ - 2,55); + printString("Pause!",maxX_ - 2,63); printString("------->",maxX_ - 2,75); refresh(); } @@ -315,13 +329,13 @@ char buffer[10]; - sprintf(buffer,"1.%s %d",s_hs0,d_hs[0]); + sprintf(buffer,"%s %d",s_hs0,d_hs[0]); printString(buffer,maxX_ - 2,15); - sprintf(buffer,"2.%s %d",s_hs1,d_hs[1]); + sprintf(buffer,"%s %d",s_hs1,d_hs[1]); printString(buffer,maxX_ - 2,33); - sprintf(buffer,"3.%s %d",s_hs2,d_hs[2]); + sprintf(buffer,"%s %d",s_hs2,d_hs[2]); printString(buffer,maxX_ - 2,51); printString("Click to",maxX_ - 2,68); @@ -329,3 +343,16 @@ refresh(); } +void GameScreen::displayPauseScreen(int *cursor,char isSound) +{ + clear(); + printString("PAUSED",maxX_ - 2,7); + + char buffer[10]; + sprintf(buffer,"Sound? %c",isSound); + printString(buffer,maxX_ - 2,30,cursor[0]); + printString("Restart",maxX_ - 2,45,cursor[1]); + printString("Return",maxX_ - 2,61,cursor[2]); + refresh(); +} +
--- a/GameScreen.h Thu May 07 20:34:14 2015 +0000 +++ b/GameScreen.h Fri May 08 12:17:39 2015 +0000 @@ -176,6 +176,19 @@ */ void displayHighScores(char *s_hs0,char *s_hs1,char *s_hs2,int *d_hs); + /** Display Second instruction Screen + * + */ + void displayInstructionScreen2(); + + /** Display Pause Menu Screen + * + *@param cursor - array of ints used to highlight selection + *@param isSound - toggle for "yes" or "no" text for sound + * + */ + void displayPauseScreen(int *cursor, char isSound); + /** Sets Ball Position * *@param x - new x coordinate of ball (right side)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PowerControl.lib Fri May 08 12:17:39 2015 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/JST2011/code/PowerControl/#d0fa2aeb02a4
--- a/main.cpp Thu May 07 20:34:14 2015 +0000 +++ b/main.cpp Fri May 08 12:17:39 2015 +0000 @@ -10,16 +10,23 @@ int main() { + lcd.Initialize(); - + powerSave(); + lcd.displayStartScreen(); while(!isRight()) {} //wait until right button pressed wait(0.5); //just to ignore layover from first button press. + lcd.displayInstructionScreen(); while(!isRight()) {} //wait until right button pressed. + + wait(0.5); + lcd.displayInstructionScreen2(); + while(!isRight()) {} //wait until right button pressed. - //lcd.displayCountdown(); + lcd.displayCountdown(); lcd.clear(); bool refresh = false; @@ -39,6 +46,12 @@ if(clockCount %(gameSpeed) == 0) { //advance platforms advancePlatforms(numPixelsToJump); + numPlatformShifts ++; + + if (numPlatformShifts%5 == 0) + { + gameLevel ++; + } refresh = true; } @@ -65,32 +78,43 @@ isFirstHit = true; } } - - if (clockCount %500 == 0) { - gameLevel++; - - if (gameLevel%4 == 0) - if (gameLevel > 60) - gameSpeed -=1; - else - gameSpeed -= 2; - + + if ((clockCount%(-45*gameSpeed + 2045) == 0)) { //starting levels are quick to progress, later slower. + if (isFirstSpeedUp) //skip first accepted modulus! + isFirstSpeedUp = false; + else { + gameSpeed --; + isFirstSpeedUp = true; + } + } + + if (joystickButton.read()) //pause menu! + { + int oldClock = clockCount; //save the clock count! + pauseScreenController(); + clockCount = oldClock; + wait(0.3); + lcd.clear(); + refresh = true; } if (refresh) { lcd.drawBall(); lcd.drawAllPlatforms(); - sprintf(buffer,"lvl: %d",gameLevel); + sprintf(buffer,"lvl:%d",gameLevel); lcd.printString(buffer,lcd.getMaxX() - 2,-1); lcd.refresh(); refresh = false; } + //check if ball hit roof if (lcd.getBallY() == 7) { break; } + + isFirstCheck = false; } } @@ -112,13 +136,14 @@ lcd.shiftAllPlatforms(n); lcd.drawAllPlatforms(); + //if ball is on platform if(!isBallFalling(lcd.getBallY()-n)) { - //move ball up with platform + //auditory feedback if first collision if (isFirstHit) { - //beep(); + boop(); isFirstHit = false; } - + //move ball up with platform lcd.eraseBall(); lcd.setBallPos(lcd.getBallX(),lcd.getBallY() -n); } @@ -153,10 +178,6 @@ bool isBallDirClear(int dir) { - - //find next platform lower than ball - //check Y pos to see if ball is on platform, return false if on plat - //check X pos to see if ball is over gap, return true if over gap Platform closestPlatform = lcd.nextClosestPlatform(lcd.getBallY() - lcd.getBallR()+2); int ballRight = lcd.getBallX(); @@ -187,6 +208,7 @@ { double count = 0.0; double total = 0.0; + //obtain an average to negate outliers while (count < 10) { count ++; total += joystickX.read(); @@ -201,7 +223,7 @@ { double count = 0.0; double total = 0.0; - + //obtain an average to negate outliers while (count < 10) { count ++; total += joystickX.read(); @@ -216,7 +238,7 @@ { double count = 0.0; double total = 0.0; - + //obtain an average to negate outliers while (count < 10) { count ++; total += joystickY.read(); @@ -231,7 +253,7 @@ { double count = 0.0; double total = 0.0; - + //obtain an average to negate outliers while (count < 10) { count ++; total += joystickY.read(); @@ -244,49 +266,59 @@ void clockCounter () { + //increment clock count! clockCount ++; isFirstCheck = true; - //serial.printf("%d mod 12 = %d \n",clockCount,clockCount%12); } void endScreenController() { int cursorLoc = 0; + //cursor location array. int cursorArray[3][3] = { {1,0,0}, {0,1,0}, {0,0,1} }; + //check if user achieved high score bool record = isRecord(); + + //if not a record move mouse start to second option + if (!record) + cursorLoc = 1; + lcd.displayEndScreen(gameLevel,cursorArray[cursorLoc],record); - bool change = false; - + bool change = false; + while (true) { if (isUp()) { - cursorLoc ++; + cursorLoc ++; //advance cursor menu change = true; } else if (isDown()) { - cursorLoc --; + cursorLoc --; //move back cursor menu change = true; } + //cyclical cursor management if (cursorLoc == 3) cursorLoc = 1-record; else if (cursorLoc == (-record)) cursorLoc = 2; + //if theres a change to buffer, show it if (change) { lcd.displayEndScreen(gameLevel,cursorArray[cursorLoc],record); wait(0.5); change = false; } + //menu selection manager if (joystickButton.read()) { switch(cursorLoc) { case 0: //take to initial entry page! (only allow if score > top 3) - wait(0.1); + wait(0.3); highScoreEditor(recordEntryController(),record); wait(1); @@ -313,10 +345,13 @@ char* recordEntryController() { + //array of letters to traverse char *letters = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ"}; + //array of ints, each corresponding to letter in letters array int ptr[3] = {0,0,0}; - + + //cursor management variables int cursorLoc = 0; int cursorArray[3][3] = { {1,0,0}, @@ -336,16 +371,17 @@ cursorLoc --; change = true; } else if (isLeft()) { + //cyclical letter management if (ptr[cursorLoc] == 0) - ptr[cursorLoc] = 25; + ptr[cursorLoc] = 25; //last letter else - ptr[cursorLoc] --; + ptr[cursorLoc] --; //previous letter change = true; } else if (isRight()) { if (ptr[cursorLoc] == 25) - ptr[cursorLoc] = 0; + ptr[cursorLoc] = 0; //first letter else - ptr[cursorLoc] ++; + ptr[cursorLoc] ++; //next letter change = true; } @@ -357,7 +393,7 @@ if (change) { lcd.displayRecordScreen(cursorArray[cursorLoc],letters[ptr[0]],letters[ptr[1]],letters[ptr[2]]); - wait(0.1); + wait(0.2); change = false; } @@ -377,16 +413,31 @@ char s_hs0[3],s_hs1[3],s_hs2[3]; int d_hs[3]; - char buffer[2]; + + //if file exists, parse it + if (fp != NULL) { - fscanf(fp,"%3s,%s",s_hs0,buffer); - d_hs[0] = atoi(buffer); - fscanf(fp,"%3s,%s",s_hs1,buffer); - d_hs[1] = atoi(buffer); - fscanf(fp,"%3s,%s",s_hs2,buffer); - d_hs[2] = atoi(buffer); - - fclose(fp); + char buffer[2]; + + fscanf(fp,"%3s,%s",s_hs0,buffer); + d_hs[0] = atoi(buffer); + fscanf(fp,"%3s,%s",s_hs1,buffer); + d_hs[1] = atoi(buffer); + fscanf(fp,"%3s,%s",s_hs2,buffer); + d_hs[2] = atoi(buffer); + + fclose(fp); + } + //else set arbitrary values! + else { + d_hs[0] = 0; + d_hs[1] = 0; + d_hs[2] = 0; + + strcpy(s_hs0,"---"); + strcpy(s_hs1,"---"); + strcpy(s_hs2,"---"); + } if (isRecord) { @@ -421,7 +472,11 @@ { //check if lvl is in top 3 FILE *fp = fopen("/local/scores.csv","r"); //open for reading. - + + //if file doesn't exist, then player has a highscore! + if (fp == NULL) + return true; + int highScore; char buffer[2]; char temp[3]; @@ -437,3 +492,88 @@ fclose(fp); return 0; } + +void boop () +{ + if (isSound == 'Y') + { + buzzer.write(1); + lowFlipper.attach_us(&pwmLow,pwmCount); + } +} + +void pwmLow() +{ + if (pwmCount != 4000) + { + buzzer.write(0); + highFlipper.attach_us(&boop,pwmCount); + pwmCount += 50; + } + else + pwmCount = 1000; + +} + +//can toggle sound or quit game. +void pauseScreenController() +{ + int cursorLoc = 0; + int cursorArray[3][3] = { + {1,0,0}, + {0,1,0}, + {0,0,1} + }; + + lcd.displayPauseScreen(cursorArray[cursorLoc],isSound); + + bool change = false; + bool resume = false; + + while (!resume) { + if (isUp()) { + cursorLoc ++; + change = true; + } else if (isDown()) { + cursorLoc --; + change = true; + } else if (isLeft() || isRight()) { + if (isSound == 'Y') + isSound = 'N'; + else + isSound = 'Y'; + change = true; + } + + //cyclical mouse management + if (cursorLoc == 3) + cursorLoc = 0; + else if (cursorLoc == -1) + cursorLoc = 2; + + if (change) { + lcd.displayPauseScreen(cursorArray[cursorLoc],isSound); + wait(0.2); + change = false; + } + + if (joystickButton.read()) { + switch (cursorLoc) { + case 1: + mbed_reset(); + break; + case 2: + resume = true; + break; + default: + break; + } + } + } +} + +void powerSave() +{ + PHY_PowerDown(); //power down ethernet + //mbed automatically manages peripheral power, no need to manually disable each +}
--- a/main.h Thu May 07 20:34:14 2015 +0000 +++ b/main.h Fri May 08 12:17:39 2015 +0000 @@ -10,6 +10,8 @@ #include "mbed.h" #include "GameScreen.h" +#include "PowerControl/PowerControl.h" +#include "PowerControl/EthernetPowerControl.h" /** @namespace serial @@ -65,14 +67,30 @@ */ Ticker gameClock; +/** +@namespace lowFlipper +@brief used for PWM speaker control, triggers pin low. +*/ +Timeout lowFlipper; + +/** +@namespace highFlipper +@brief used for PWM speaker control, triggers pin high. +*/ +Timeout highFlipper; + //##############GLOBAL VARIABLES##################// int clockCount = 0; ///< master clock counter bool isFirstCheck = true; ///< first check in clock cycle? bool isFirstHit = true; ///< first hit on a platform? +bool isFirstSpeedUp = true; ///< first game speed up? int gameLevel = 0; ///< current game level -int gameSpeed = 50; ///< current game speed +int gameSpeed = 41; ///< current game speed int numPixelsToJump = 1; ///< number of pixels ball/plat moves per animation +int numPlatformShifts = 0; ///< number of times platforms shifted, used for score calculation +int pwmCount = 1000; ///< pwm count for platform collision sound +char isSound = 'Y'; ///< sound toggle, 'Y' for sound enabled. //#############FUNCTION PROTOTYPES##################// @@ -164,6 +182,30 @@ */ void highScoreEditor(char *playerInitials,bool isRecord); +/** Pause Screen Controller +* +* Displays pause screen and allows user interaction to toggle sound,restart, and resume game. +*/ +void pauseScreenController(); + +/** PWM speaker control function +* +* makes a boop sound used for collisions with platforms. +*/ +void boop (); + +/** Boop Helper function +* +* sets pin low when called, then starts timer to recall Boop(); +*/ +void pwmLow(); + +/** Power Saving Mode +* +* Powers down unused peripherals & ethernet +*/ +void powerSave(); + #endif