new mods upon mods by devhammer: - Added paddle control using tilting of the console - Finished mute function - Reduced flickering See game.cpp for full info.

Dependencies:   mbed

Fork of RETRO_Pong_Mod by G. Andrew Duthie

This is a mod of the official Pong game released with the RETRO game console.

Revision:
4:9ad3bc45b6ce
Parent:
3:2f09c90a732d
--- a/Game.cpp	Thu Jan 15 12:48:21 2015 +0000
+++ b/Game.cpp	Thu Jan 15 14:34:59 2015 +0000
@@ -1,11 +1,20 @@
 // Updated version of the official firmware for the Outrageous Circuits RETRO
-// Modified by G. Andrew Duthie (devhammer)
+//
+// mod150106 - Modified by G. Andrew Duthie (devhammer)
 // Changes:
 // - Added sounds for all ball bounces
 // - Changed ball from square to circle
 // - Adjusted collision detection to add ball speed every 10 paddle hits
 // - Added scoring
 // - Added mute function (not fully implemented...needs to be set up on a button).
+//
+// mod150115 - Modified by Maxint
+// Changes:
+// - Upped the I2C frequency to make the Accelerometer useable in actual gameplay
+// - Added paddle control using tilting of the console
+// - Changed left-right button control to make it a bit more logical
+// - tied mute function to the circle button and added el cheapo debouncing
+// - reduced flickering by only redrawing paddle and ball when changed position
 
 #include "Game.h"
 
@@ -21,9 +30,11 @@
     
     this->lastUp = false;
     this->lastDown = false;
-    this->mode = true;
+    this->mode = true;      // true=game, false=accelerometer
     
-    this->i2c.frequency(400);
+    //this->i2c.frequency(400);       // Really? Is this a joke? 400 Hz is much too slow. Reading the XYZ now takes 210 ms
+    this->i2c.frequency(400000);      // fast I2C is 400 KHz, not 400 Hz. Default frequency is 100 KHz, but the faster, the less delay...
+
     this->writeRegister(0x2A, 0x01); 
     
     this->colors[0] = DisplayN18::RED;
@@ -104,6 +115,7 @@
     this->initializeBall();
         
     this->paddleX = DisplayN18::WIDTH / 2 - Game::PADDLE_WIDTH / 2;
+    this->paddleXprev=this->paddleX;
     this->pwmTicksLeft = 0;
     this->lives = 4;
     this->score = 0;
@@ -118,6 +130,8 @@
 void Game::initializeBall() {
     this->ballX = DisplayN18::WIDTH / 2 - Game::BALL_RADIUS;
     this->ballY = DisplayN18::HEIGHT / 4 - Game::BALL_RADIUS;
+    this->ballXprev=this->ballX;
+    this->ballYprev=this->ballY;
     
     this->ballSpeedX = Game::BALL_STARTING_SPEED;
     this->ballSpeedY = Game::BALL_STARTING_SPEED;
@@ -130,16 +144,16 @@
     this->checkButtons();
     
     if (this->mode) {
-        this->clearPaddle();
-        this->clearBall();
+        //this->clearPaddle();
+        //this->clearBall();
         
         this->updatePaddle();
         this->updateBall();
     
         this->checkCollision();
         
-        this->drawPaddle();        
-        this->drawBall();
+        this->redrawPaddle();        
+        this->redrawBall();
         
         this->checkPwm();
         this->checkLives(); 
@@ -156,12 +170,25 @@
         this->drawPoint(1, y);
         this->drawPoint(2, z);
         this->graphX++;
+
+        wait_ms(100);   // added delay after upping the I2C frequency to a usable value
     } 
 }
 
+
+int Game::checkTilt()
+{    // check the orientation of the console to allow tilt-control
+    double x, y, z;
+    
+    this->getXYZ(x, y, z);
+
+    if(x<-0.07) return(-1);     // Using 0.1 requires too much an angle for nice gameplay. 0.07 is more subtle.
+    else if(x>0.07) return(1);
+    else return(0);
+}
+
 void Game::checkButtons() {
     if (!this->square.read()) {
-        //this->muted = !this->muted;
         this->mode = !this->mode;
         
         this->disp.clear();
@@ -172,11 +199,14 @@
             this->drawAxes();
         }
         
-        //this->led1.write(this->muted);
-        //this->led2.write(!this->muted);
-        this->led1.write(this->mode);
-        this->led2.write(!this->mode);
-    }  
+        this->led1.write(!this->mode);
+    }
+    else if(!this->circle.read()) { 
+        // use ship-button to mute
+        this->muted = !this->muted;
+        this->led2.write(this->muted);
+        wait_ms(250);   // el-cheapo deboounce
+    }
     
     bool xDir = this->ballSpeedX > 0;
     bool yDir = this->ballSpeedY > 0;
@@ -219,6 +249,7 @@
        
     while (this->circle.read())
         wait_ms(1);
+    wait_ms(250);   // el-cheapo deboounce
         
     this->disp.clear();
 }
@@ -231,12 +262,30 @@
     this->disp.fillRect(this->paddleX, DisplayN18::HEIGHT - Game::PADDLE_HEIGHT, Game::PADDLE_WIDTH, Game::PADDLE_HEIGHT, DisplayN18::BLUE);    
 }
 
+void Game::redrawPaddle()
+{   // draw the paddle, but only clear when changed to reduce flickering
+    if(this->paddleXprev!=this->paddleX)
+    {
+        this->disp.fillRect(this->paddleXprev, DisplayN18::HEIGHT - Game::PADDLE_HEIGHT, Game::PADDLE_WIDTH, Game::PADDLE_HEIGHT, DisplayN18::BLACK);    
+    }
+    this->disp.fillRect(this->paddleX, DisplayN18::HEIGHT - Game::PADDLE_HEIGHT, Game::PADDLE_WIDTH, Game::PADDLE_HEIGHT, DisplayN18::BLUE);    
+}
+
 void Game::updatePaddle() {
-    if (this->left.read())
+    // see if the paddle position needs changing
+    this->paddleXprev=this->paddleX;
+    if(!this->left.read())  // note: button.read() is LOW (0) when button pressed
+        this->paddleX -= Game::PADDLE_SPEED;
+    else if(!this->right.read())
         this->paddleX += Game::PADDLE_SPEED;
-        
-    if (this->right.read())
-        this->paddleX -= Game::PADDLE_SPEED;
+    else
+    {
+        int nTilt=this->checkTilt();        // don't call too often as this I2C is slow and will delay the game
+        if(nTilt>0)
+            this->paddleX += Game::PADDLE_SPEED;
+        else if(nTilt<0)
+            this->paddleX -= Game::PADDLE_SPEED;
+    }
 }
 
 void Game::clearBall() {   
@@ -246,6 +295,12 @@
     this->disp.setPixel(this->ballX, this->ballY, DisplayN18::BLACK);
 }
 
+void Game::clearBallPrev()
+{   // clear the ball from previous position
+    this->disp.fillCircle(this->ballXprev, this->ballYprev, Game::BALL_RADIUS, DisplayN18::BLACK);
+    this->disp.setPixel(this->ballXprev, this->ballYprev, DisplayN18::BLACK);
+}
+
 void Game::drawBall() {
     //this->disp.fillRect(this->ballX - Game::BALL_RADIUS, ballY - Game::BALL_RADIUS, Game::BALL_RADIUS * 2, Game::BALL_RADIUS * 2, DisplayN18::RED);
     //this->disp.fillCircle(this->ballX - Game::BALL_RADIUS, ballY - Game::BALL_RADIUS, Game::BALL_RADIUS, DisplayN18::RED);
@@ -253,7 +308,20 @@
     this->disp.setPixel(this->ballX, this->ballY, DisplayN18::GREEN);
 }
 
+void Game::redrawBall()
+{   // redraw the ball, but only clear when changed to reduce flickering
+    if(this->ballX!=this->ballXprev || this->ballY!=this->ballYprev)
+    {
+        this->disp.fillCircle(this->ballXprev, this->ballYprev, Game::BALL_RADIUS, DisplayN18::BLACK);
+        this->disp.setPixel(this->ballXprev, this->ballYprev, DisplayN18::BLACK);
+    }
+    this->disp.fillCircle(this->ballX, ballY, Game::BALL_RADIUS, DisplayN18::RED);
+    this->disp.setPixel(this->ballX, this->ballY, DisplayN18::GREEN);
+}
+
 void Game::updateBall() {
+    this->ballXprev=this->ballX;
+    this->ballYprev=this->ballY;
     this->ballX += this->ballSpeedX;
     this->ballY += this->ballSpeedY;
 }
@@ -284,6 +352,7 @@
         
     if (this->ballY + Game::BALL_RADIUS >= DisplayN18::HEIGHT - Game::PADDLE_HEIGHT && this->ballSpeedY > 0) {
         if (this->ballY + Game::BALL_RADIUS >= DisplayN18::HEIGHT) {
+            this->clearBallPrev();
             this->initializeBall();
             
             this->lives--;