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

Files at this revision

API Documentation at this revision

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

GameScreen.cpp Show annotated file Show diff for this revision Revisions of this file
GameScreen.h Show annotated file Show diff for this revision Revisions of this file
PowerControl.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
main.h Show annotated file Show diff for this revision Revisions of this file
--- 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