Maxint R&D / Mbed 2 deprecated RETRO_BallAndHoles

Dependencies:   LCD_ST7735 MusicEngine RETRO_BallsAndThings mbed

Revision:
2:d4de5a5866fe
Parent:
1:c1ee4c699517
Child:
3:ca8b21da67dc
diff -r c1ee4c699517 -r d4de5a5866fe Game.cpp
--- a/Game.cpp	Sun Feb 01 16:21:24 2015 +0000
+++ b/Game.cpp	Tue Feb 03 19:02:27 2015 +0000
@@ -2,9 +2,9 @@
 
 const char* Game::LOSE_1 = "You lose.";
 const char* Game::LOSE_2 = "Press ship to restart.";
-const char* Game::SPLASH_1 = "Press ship to start.";
-const char* Game::SPLASH_2 = "Press robot to switch.";
-const char* Game::SPLASH_3 = "mod:Tilt by Maxint.";
+const char* Game::SPLASH_1 = "-*- Balls and paddle -*-";
+const char* Game::SPLASH_2 = "Press ship to start.";
+const char* Game::SPLASH_3 = "Made by Maxint";
 
 
 #define WHITE Color565::White
@@ -21,7 +21,7 @@
 
 
 Game::Game() : left(P0_14, PullUp), right(P0_11, PullUp), down(P0_12, PullUp), up(P0_13, PullUp), square(P0_16, PullUp), circle(P0_1, PullUp), led1(P0_9), led2(P0_8), 
-    pwm(P0_18), ain(P0_15), i2c(P0_5, P0_4), disp(P0_19, P0_20, P0_7, P0_21, P0_22, P1_15, P0_2, LCD_ST7735::RGB), accel(this->I2C_ADDR, &disp), vGravity(0, 0.1), ball(&disp), paddle(&disp)
+    ain(P0_15), i2c(P0_5, P0_4), disp(P0_19, P0_20, P0_7, P0_21, P0_22, P1_15, P0_2, LCD_ST7735::RGB), accel(this->I2C_ADDR, &disp), vGravity(0, 0.1), ball(&disp), paddle(&disp)
 {
     this->disp.setOrientation(LCD_ST7735::Rotate270, false);
     this->disp.setForegroundColor(WHITE);
@@ -34,10 +34,16 @@
     this->lastDown = false;
     this->mode = true;
 
-    this->initialize();
+
+    //this->aBalls[2]={ Ball(&disp),  Ball(&disp) };
+    for(int i=0; i<NUM_BALLS; i++)
+        this->aBalls[i]=Ball(&(this->disp));
+
+    //this->initialize();
 }
 
-void Game::printDouble(double value, int x, int y) {
+void Game::printDouble(double value, int x, int y)
+{
     char buffer[10];
     int len = sprintf(buffer, "%.1f ", value);
     
@@ -48,33 +54,145 @@
 {
     this->disp.clearScreen();
 
-    this->initializeBall();     // start first ball
+//    this->initializeBall();     // start first ball
+//    this->initializeBalls();     // start first ball
+
+    this->setNoBalls();     // reset all balls
+    this->newBall();     // start first ball
     this->initializePaddle();
+    //this->paddle.draw();
+
        
 //    this->paddleX = WIDTH / 2 - Game::PADDLE_WIDTH / 2;
-    this->pwmTicksLeft = 0;
+    this->snd.reset();
     this->nLives = 4;
     this->nScore = 0;
     
-    this->pwm.period_ms(1);
-    this->pwm.write(0.00);
-
     this->tWait.start();      // start the timer
     
 }
-    
+
+
+void Game::initializePaddle()
+{
+    this->paddle.initialize(WIDTH / 2 - Game::PADDLE_WIDTH/2, HEIGHT - Game::PADDLE_HEIGHT, Game::PADDLE_WIDTH, Game::PADDLE_HEIGHT);
+    this->paddle.draw();
+}
+
+
+void Game::updatePaddle()
+{
+    if (!this->left.read())  // note: read is LOW (0) when button pressed
+        this->paddle.move(Vector(-1 * Game::PADDLE_SPEED, 0));
+    else if (!this->right.read())
+        this->paddle.move(Vector(Game::PADDLE_SPEED, 0));
+    else
+    {
+        int i=this->checkTilt();
+        if(i>0)
+            this->paddle.move(Vector(Game::PADDLE_SPEED, 0));
+        else if(i<0)
+            this->paddle.move(Vector(-1 * Game::PADDLE_SPEED, 0));
+        else if(this->paddle.hasChanged())
+            paddle.move(Vector(0, 0));  // move to same place to restrict redraws
+    }
+}
+
+
+
+
+/*
 void Game::initializeBall()
 {
     this->ball.initialize(WIDTH / 2 - Game::BALL_RADIUS, HEIGHT / 4 - Game::BALL_RADIUS, Game::BALL_RADIUS, Color565::fromRGB(0xFF, 0x33, 0x33));
     this->ball.setSpeed(rand() % 2 ? 1 : -1, rand() % 2 ? 1 : -1);
 }
+*/
 
-void Game::initializePaddle()
+/*
+void Game::initializeBalls()
+{
+    for(int i=0; i<NUM_BALLS; i++)
+    {
+        this->aBalls[i].initialize(WIDTH / 2 - Game::BALL_RADIUS, HEIGHT / 4 - Game::BALL_RADIUS, Game::BALL_RADIUS, Color565::fromRGB(i==0?0xFF:0x33, i==1?0xFF:0x33, i==2?0xFF:0x33));
+        //float ftRandX=rand() % 2 ? 1 : -1;
+        float ftRandX=((rand() % 20) - 10)/10 ;
+        float ftRandY=rand() % 2 ? 1 : -1;
+        this->aBalls[i].setSpeed(ftRandX, ftRandY);
+    }
+}
+*/
+
+void Game::setNoBalls()
 {
-    this->paddle.initialize(WIDTH / 2 - Game::PADDLE_WIDTH/2, HEIGHT - Game::PADDLE_HEIGHT, Game::PADDLE_WIDTH, Game::PADDLE_HEIGHT);
+    for(int i=0; i<NUM_BALLS; i++)
+        this->aBalls[i].fActive=false;
+}
+
+void Game::newBall()
+{
+    for(int i=0; i<NUM_BALLS; i++)
+    {
+        if(this->aBalls[i].fActive)
+            continue;
+        else
+        {
+            this->aBalls[i].initialize(WIDTH / 2 - Game::BALL_RADIUS, HEIGHT / 4 - Game::BALL_RADIUS, Game::BALL_RADIUS, Color565::fromRGB(i==0?0xFF:0x33, i==1?0xFF:0x33, i==2?0xFF:0x33));
+            //float ftRandX=rand() % 2 ? 1 : -1;
+            //float ftRandY=rand() % 2 ? 1 : -1;
+            float ftRandX=((rand() % 20) - 10)/5.0;
+            float ftRandY=((rand() % 10) - 10)/5.0;
+            //this->aBalls[i].setSpeed(ftRandX, ftRandY);
+            this->aBalls[i].vSpeed.set(ftRandX, ftRandY);
+            this->aBalls[i].fActive=true;
+            break;
+        }
+    }
 }
 
-void Game::tick() {  
+void Game::updateBalls()
+{
+    for(int i=0; i<NUM_BALLS; i++)
+    {
+        if(!this->aBalls[i].fActive)
+            continue;
+
+        this->aBalls[i].update();                    // update the ball position 
+
+        // add downward gravity
+        if(this->aBalls[i].vSpeed.getSize() != 0 && this->aBalls[i].vSpeed.getSize()<10.0)            // TODO: added if statement to allow zero speed pause of ball
+            this->aBalls[i].vSpeed.add(this->vGravity);    // add some gravity
+
+    }
+}
+
+void Game::redrawBalls()
+{
+    for(int i=0; i<NUM_BALLS; i++)
+    {
+        if(!this->aBalls[i].fActive)
+            continue;
+        this->aBalls[i].redraw();                    // update the ball position 
+    }
+}
+
+int Game::countBalls()
+{
+    int nResult=0;
+    for(int i=0; i<NUM_BALLS; i++)
+    {
+        if(this->aBalls[i].fActive)
+            nResult++;
+    }
+    return(nResult);
+}
+
+
+
+
+
+void Game::tick()
+{  
     this->checkButtons();
     
     if (this->mode) {
@@ -85,15 +203,26 @@
             this->tWait.reset();
         }
 */
+
+/*
+        if(this->ball.vSpeed.getSize() != 0)            // TODO: added if statement to allow zero speed pause of ball
+            this->ball.vSpeed.add(this->vGravity);    // add some gravity
+            //this->ball.vSpeed.add(Vector(0, 0.1));    // add some gravity
+        this->ball.update();                    // update the ball position 
+*/
+
+        this->updateBalls();                    // update the ball positions
+
         this->updatePaddle();
-        this->ball.vSpeed.add(Vector(0, 0.1));    // add some gravity
-        this->ball.update();                    // update the ball position 
     
-        this->checkCollision();
+//        this->checkCollision();
+        this->checkPaddle();
+        this->checkBallsCollision();
+//        this->ball.redraw();
+        this->redrawBalls();
         this->paddle.redraw();
-        this->ball.redraw();
         
-        this->checkPwm();
+        this->snd.checkPwm();
         //this->checkScore(); 
         this->checkLives(); 
         
@@ -192,25 +321,101 @@
         wait_ms(1);
     }
         
-    this->disp.clearScreen();
+    //this->disp.clearScreen();
+    this->initialize();     // start a new game
 }
 
 
-void Game::updatePaddle() {
-    if (!this->left.read())  // note: read is LOW (0) when button pressed
-        this->paddle.move(Vector(-1 * Game::PADDLE_SPEED, 0));
-    else if (!this->right.read())
-        this->paddle.move(Vector(Game::PADDLE_SPEED, 0));
-    else
+
+void Game::checkBallsCollision()
+{
+    Rectangle rTop=Rectangle(0, -10, WIDTH, 0);                // Rectangle(0, 0, WIDTH, 1);       // top wall
+    Rectangle rBottom=Rectangle(0, HEIGHT, WIDTH, HEIGHT+10);  // Rectangle(0, HEIGHT, WIDTH, HEIGHT);       // bottom gap
+    Rectangle rLeft=Rectangle(-10, 0, 0, HEIGHT);              // Rectangle(0, 0, 0, HEIGHT);       // left wall
+    Rectangle rRight=Rectangle(WIDTH, 0, WIDTH+10, HEIGHT);       // Rectangle(WIDTH, 0, WIDTH, HEIGHT);       // right wall
+    Rectangle rPaddle=Rectangle(paddle.pos.getX(), paddle.pos.getY(), paddle.pos.getX() + Game::PADDLE_WIDTH, HEIGHT+10);       // Rectangle(this->paddleX, HEIGHT - Game::PADDLE_HEIGHT, this->paddleX + Game::PADDLE_WIDTH, HEIGHT);       // paddle
+    Rectangle rPaddleLeft=Rectangle(paddle.pos.getX(), paddle.pos.getY(), paddle.pos.getX() + Game::PADDLE_WIDTH/3, HEIGHT+10);      // paddle left part
+    Rectangle rPaddleRight=Rectangle(paddle.pos.getX()+ Game::PADDLE_WIDTH/3 + Game::PADDLE_WIDTH/3, paddle.pos.getY(), paddle.pos.getX() + Game::PADDLE_WIDTH, HEIGHT+10);      // paddle right part
+    //Rectangle rScreen=Rectangle(0,0, WIDTH, HEIGHT);            // screen boundary
+
+    Ball* pBall;
+    for(int i=0; i<NUM_BALLS; i++)
     {
-        int i=this->checkTilt();        // don't call too often as this I2C is slow and will delay the game
-        if(i>0)
-            this->paddle.move(Vector(Game::PADDLE_SPEED, 0));
-        else if(i<0)
-            this->paddle.move(Vector(-1 * Game::PADDLE_SPEED, 0));
+        if(!this->aBalls[i].fActive)
+            continue;
+
+        pBall=&(this->aBalls[i]);
+
+        if(pBall->collides(rTop) && pBall->vSpeed.isUp())      // top wall
+        {
+            pBall->Bounce(Vector(1,-1));        // bounce vertical
+            this->snd.beepShort();
+        }
+        if(pBall->collides(rRight) && pBall->vSpeed.isRight())      // right wall
+        {
+            pBall->Bounce(Vector(-1,1));        // bounce horizontal
+            this->snd.beepShort();
+        }
+        if(pBall->collides(rLeft) && pBall->vSpeed.isLeft())      // left wall
+        {
+            pBall->Bounce(Vector(-1,1));        // bounce horizontal
+            this->snd.beepShort();
+        }
+        if(pBall->collides(rPaddle) && pBall->vSpeed.isDown())      // paddle
+        {
+            if(pBall->collides(rPaddleLeft))   pBall->vSpeed.add(Vector(-1,0));       // left side of paddle has bias to the left
+            if(pBall->collides(rPaddleRight))  pBall->vSpeed.add(Vector(1,0));       // right side of paddle has bias to the right
+    
+            
+            // increase the speed of the ball when hitting the paddle to increase difficulty
+            //pBall->Bounce(Vector(1,-1));        // bounce vertical at same speed
+            float ftSpeedMax=3.0;
+            if(this->nScore>50)
+                ftSpeedMax=5.0;
+            if(this->nScore>100)
+                ftSpeedMax=10.0;
+            if(this->nScore>150)
+                ftSpeedMax=999.0;
+            if(pBall->vSpeed.getSize()<ftSpeedMax)            // TODO: added if statement to allow zero speed pause of ball
+                pBall->Bounce(Vector(1,-1.02));        // bounce from paddle at higher speed
+            else
+                pBall->Bounce(Vector(1,-1));        // bounce vertical at same speed
+    
+            this->snd.beepLong();
+            this->nScore++;
+            this->printf(100, 0, "Score: %d ", this->nScore);   
+
+            if(this->nScore>0 && this->nScore%10==0)
+            {
+                this->newBall();
+                this->nLives++;
+            }
+        }
+        if(pBall->collides(rBottom) && pBall->vSpeed.isDown())      // bottom gap
+        {
+            pBall->clearPrev();   // clear the ball from its previous position
+            pBall->clear();   // clear the ball from its current position
+            pBall->vSpeed.set(0,0);
+            pBall->fActive=false;
+            this->nLives--;
+            //this->initializeBall();     // start a new ball
+            if(countBalls()==0)
+            {
+                this->newBall();     // start a new ball
+                this->snd.beepLow();
+            }
+        }
     }
 }
 
+void Game::checkPaddle()
+{
+    Rectangle rScreen=Rectangle(0,0, WIDTH, HEIGHT);            // screen boundary
+
+    this->paddle.checkBoundary(rScreen);
+}
+
+/*
 void Game::checkCollision()
 {
     Rectangle rTop=Rectangle(0, -10, WIDTH, 0);                // Rectangle(0, 0, WIDTH, 1);       // top wall
@@ -222,38 +427,32 @@
     Rectangle rPaddleRight=Rectangle(paddle.pos.getX()+ Game::PADDLE_WIDTH/3 + Game::PADDLE_WIDTH/3, paddle.pos.getY(), paddle.pos.getX() + Game::PADDLE_WIDTH, HEIGHT+10);      // paddle right part
     Rectangle rScreen=Rectangle(0,0, WIDTH, HEIGHT);            // screen boundary
 
-/*
-    if (this->paddle.pos.getX() < 0)
-        this->paddle.pos.setX(0);
-    if (this->paddle.pos.getX() + Game::PADDLE_WIDTH > WIDTH)
-        this->paddle.pos.setX(WIDTH - Game::PADDLE_WIDTH);
-*/
     this->paddle.checkBoundary(rScreen);
    
     if(ball.collides(rTop) && this->ball.vSpeed.isUp())      // top wall
     {
         this->ball.Bounce(Vector(1,-1));        // bounce vertical
-        this->pwmTicksLeft = Game::BOUNCE1_SOUND_TICKS;
+        this->snd.beepShort();
     }
     if(ball.collides(rRight) && this->ball.vSpeed.isRight())      // right wall
     {
         this->ball.Bounce(Vector(-1,1));        // bounce horizontal
-        this->pwmTicksLeft = Game::BOUNCE1_SOUND_TICKS;
+        this->snd.beepShort();
     }
     if(ball.collides(rLeft) && this->ball.vSpeed.isLeft())      // left wall
     {
         this->ball.Bounce(Vector(-1,1));        // bounce horizontal
-        this->pwmTicksLeft = Game::BOUNCE1_SOUND_TICKS;
+        this->snd.beepShort();
     }
     if(ball.collides(rPaddle) && this->ball.vSpeed.isDown())      // paddle
     {
         if(ball.collides(rPaddleLeft))   ball.vSpeed.add(Vector(-1,0));       // left side of paddle has bias to the left
         if(ball.collides(rPaddleRight))  ball.vSpeed.add(Vector(1,0));       // right side of paddle has bias to the right
 
-        //this->ball.Bounce(Vector(1,-1));        // bounce vertical at same speed
-        ball.Bounce(Vector(1,-1.1));        // bounce from paddle at higher speed
+        ball.Bounce(Vector(1,-1));        // bounce vertical at same speed
+        //ball.Bounce(Vector(1,-1.05));        // bounce from paddle at higher speed
 
-        this->pwmTicksLeft = Game::BOUNCE2_SOUND_TICKS;
+        this->snd.beepLong();
         this->nScore++;
         this->printf(100, 0, "Score: %d ", this->nScore);   
     }
@@ -264,16 +463,7 @@
         this->initializeBall();     // start a new ball
     }
 }
-
-void Game::checkPwm() {
-    if (this->pwmTicksLeft == 0) {
-        this->pwm.write(0.0);
-    }
-    else {
-        this->pwmTicksLeft--;
-        this->pwm.write(0.5); 
-    }
-}
+*/
 
 void Game::printf(int x, int y, const char *szFormat, ...)
 {
@@ -294,6 +484,7 @@
         this->drawString(Game::LOSE_1, HEIGHT / 2 - CHAR_HEIGHT); 
         this->drawString(Game::LOSE_2, HEIGHT / 2);  
         
+        this->snd.playTune();
         while (this->circle.read())
             wait_ms(1);