University project - accelerometer controlled Arkanoid

Dependencies:   KS0108 MMA8451Q mbed

Revision:
0:9515d58c3408
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun Jan 18 19:27:16 2015 +0000
@@ -0,0 +1,279 @@
+#include    "mbed.h"
+#include    "KS0108.h"
+#include    "Arial12.h"
+#include    "SystemFont5x7.h"
+#include    "stdbool.h"
+#include    "MMA8451Q.h"
+#include    <time.h>
+#include    <stdlib.h>
+#include    <math.h>
+#include    <inttypes.h>
+ 
+#define minX        (125)
+#define maxX        (39)
+#define minY        (2)
+#define maxY        (62)
+#define PadLength   (10)
+#define PadY        (59)
+#define LowSpeed    (2)
+#define HighSpeed   (4)
+#define XPadInit    ((uint8_t)(0.5*(minX+maxX-PadLength)))
+#define XBallInit   ((uint8_t)(XPadInit+0.5*PadLength))
+#define BallD       (1)
+#define YBallInit   ((uint8_t)(PadY-BallD))
+
+#define BrickH      (4)
+#define BrickW      (20)
+#define columns     (4)
+#define rows        (3)
+
+#define maxangle    (25)
+#define velocity    (3)
+#define pi          (3.14)
+
+#define round(x)    ((x)>=0?(int8_t)((x)+0.5):(int8_t)((x)-0.5))
+
+#define AccTres1    (0.12)
+#define AccTres2    (0.25)
+
+#define MMA8451_I2C_ADDRESS (0x1d<<1)
+ 
+KS0108 display (PTE22,PTE23, PTE29, PTE30, PTE20, PTE21, PTC7, PTC0, PTC3, PTC4, PTC5, PTC6, PTC10, PTC11);
+
+//prototypes of functions
+void DrawBorder();                      //function for drawing border around gaming area
+void DrawBall(uint8_t* X, uint8_t* Y, int8_t* dx, int8_t* dy, uint8_t D, uint8_t PaddlePos, bool* Start, uint8_t* lives);       //function for drawing the ball
+void MovePad(uint8_t* Pad_ptr, bool Start);     //function for drawing the accelerometer controlled pad
+void DrawLogo(void);                            //function for drawing logo
+void DrawTable(int8_t sc, int8_t liv);          //function for drawing table with score and number of lives
+void reset(uint8_t* XBall, uint8_t* YBall, int8_t* dxBall, int8_t* dyBall, uint8_t* XPaddle, bool* Start, uint8_t *score, uint8_t *lives, uint8_t* col, uint8_t* ro, bool* Exists); //function for reset the game - after the ball was lost, game has been won or lost
+void CreateGrid(uint8_t* col, uint8_t* ro, bool* Exists);       //function for preparing the grid for array of bricks
+void DrawBricks(uint8_t col[columns], uint8_t ro[rows], bool exists[rows*columns]);     //drawing the array of bricks
+void BounceBricks(uint8_t XBall, uint8_t YBall, int8_t* dxBall, int8_t* dyBall, bool* BrickExists, uint8_t ro[rows], uint8_t col[columns], uint8_t* score, uint8_t lives, bool* Start); //function detecting hits, erasing bricks, counting score etc...
+
+MMA8451Q acc(PTE25, PTE24, MMA8451_I2C_ADDRESS);
+//main program
+int main() {
+    srand(time(NULL));                      //random seed - will be used for random reflection angle when the game starts/was reset                  
+    display.ClearScreen();
+
+    uint8_t score = 0;                      //initial score and number of lives
+    uint8_t lives = 3;
+    DrawLogo();                             //drawing ARM-kanoid title
+    DrawTable(score,lives);                 //drawing table with score and number of lives
+    DrawBorder();                           //drawing border of the playing area
+    
+    uint8_t XBall = XBallInit;              //initial ball position
+    uint8_t YBall = YBallInit;
+    int8_t Balldx;
+    int8_t Balldy;
+  
+    uint8_t PadPos = XPadInit;              //initializing position of the paddle
+    bool StartFlag = true;                  //start flag will be used for reseting the game
+
+    uint8_t column[columns];                //arrays of brick positions on the display - will be filled by function CreateGrid(...)
+    uint8_t row[rows];
+    bool BrickExists[columns*rows];         //array of bool flags for bricks - true = brick exists, false = brick was already destroyed... will be also filled by function CreateGrid(...)
+    
+    CreateGrid(&(column[0]),  &(row[0]), &(BrickExists[0]));                           //creating grid for bricks
+    DrawBricks(column, row, BrickExists);                                              //drawing bricks
+    
+    while(1) { 
+        display.TurnOn();
+        if (StartFlag){
+            reset(&XBall, &YBall, &Balldx, &Balldy, &PadPos, &StartFlag, &score, &lives, &(column[0]), &(row[0]), &(BrickExists[0]));   //reset in case lost ball, lost or won game
+        }
+        BounceBricks(XBall, YBall, &Balldx, &Balldy, &(BrickExists[0]), row, column, &score, lives, &StartFlag);
+        DrawBall(&XBall, &YBall, &Balldx, &Balldy, BallD, PadPos, &StartFlag, &lives);      //function for drawing the ball, computing its movement, bounces etc.
+        MovePad(&PadPos, StartFlag);                //function for paddle drawing and its control by accelerometer
+        wait(0.05);                                 //waiting time was set empirically - according to feel about the display refresh rate    
+    }
+}
+
+void DrawLogo(void){                        //draws the logo (ARM-kanoid)
+    display.SelectFont(Arial12,BLACK,ReadData);   
+    display.GotoXY(8,8);
+    display.PrintString("ARM"); 
+    display.GotoXY(4,24);
+    display.PrintString("kanoid"); 
+}
+
+void DrawTable(int8_t sc, int8_t liv){      //draws table with score and lives    
+    static char score[5];
+    static char lives[5];
+    display.EmptyRectangle(4,38, (maxX-6),56, BLACK);
+    display.FullRectangle(20,39,(maxX-7), 55, WHITE);
+    display.SelectFont(System5x7,BLACK,ReadData);  
+    sprintf(score,"S:%2d",sc);
+    sprintf(lives,"L:%2d",liv);
+    display.GotoXY(8,40);
+    display.PrintString(score);
+    display.GotoXY(8,48);
+    display.PrintString(lives);
+}
+    
+void DrawBorder(void){          //draws border around gaming area
+    display.HLine(maxX-2, 127,0,BLACK);
+    display.VLine(maxX-2, 0,63,BLACK);
+    display.VLine(minX+2, 0,63,BLACK);
+}
+
+void DrawBall(uint8_t* X, uint8_t* Y, int8_t* dx, int8_t* dy, uint8_t D, uint8_t PaddlePos, bool* Start, uint8_t* lives){   //draws the ball, computes reflections from border of gaming area
+    
+    display.FullCircle(*X, *Y, D, WHITE);
+    
+    (*X) += (*dx);
+    (*Y) += (*dy);
+    display.FullCircle(*X, *Y, D, BLACK);
+    if ((((uint8_t)(*X+D)) >= minX)||(((int8_t)(*X-D)) <= maxX)){
+        *dx = -(*dx);
+    }
+    if (((uint8_t)(*Y-D)) <= minY){
+       *dy = -(*dy);
+    }
+    if (((int8_t)(*Y+D)) >= PadY){
+        if ((((uint8_t)(*X+D)) <= (PaddlePos+PadLength+2))&&(((uint8_t)(*X-D)) >= (PaddlePos-2))){
+            *dy = -(*dy);
+        }else{
+            *Start = true;
+            if (*lives > 0){
+                (*lives)--;
+            }    
+        }
+    }
+}
+
+void MovePad(uint8_t* Pad_ptr, bool Start){     //drawing the accelerometer-controlled pad
+    uint8_t PaddleDif;
+    if ((abs(acc.getAccY()))>AccTres1){
+    display.FullRectangle(*Pad_ptr, PadY, *Pad_ptr+PadLength ,PadY+2,WHITE);
+    if(Start){
+        *Pad_ptr = XPadInit;
+    }else{
+        if ((abs(acc.getAccY()))>AccTres2){
+            PaddleDif = HighSpeed;
+            }else{
+                PaddleDif = LowSpeed;
+            }
+            if ((acc.getAccY() > 0)&&((*Pad_ptr+PadLength) < (minX - 3))){
+                *Pad_ptr += PaddleDif;   
+            }
+            if ((acc.getAccY() < 0)&&(*Pad_ptr > (maxX + 1))){
+            *Pad_ptr -= PaddleDif;   
+            }
+        }
+    }
+    display.FullRectangle(*Pad_ptr, PadY, *Pad_ptr+PadLength ,PadY+2,BLACK);
+}
+
+void reset(uint8_t* XBall, uint8_t* YBall, int8_t* dxBall, int8_t* dyBall, uint8_t* XPaddle, bool* Start, uint8_t *score, uint8_t *lives, uint8_t* col, uint8_t* ro, bool* Exists){ //resets the game in case of lost ball, lost or won game
+    display.FullCircle(*XBall, *YBall, BallD, WHITE);
+    *XBall = XBallInit;
+    *YBall = YBallInit;
+    display.FullRectangle(*XPaddle, PadY, *XPaddle+PadLength ,PadY+2,WHITE);
+    *XPaddle = XPadInit;
+    wait(1);
+    if (*score == (rows*columns)){
+        display.ClearScreen();
+        display.GotoXY(32,32);
+        display.PrintString("YOU WIN!!!");
+        wait(3);
+        *score = 0;
+        *lives = 3;
+        display.ClearScreen();
+        DrawLogo();                             //drawing ARM-kanoid title
+        DrawTable(*score,*lives);                 //drawing table with score and number of lives
+        DrawBorder();                           //drawing border of the playing area
+        CreateGrid(&(*col), &(*ro), &(*Exists));
+        DrawBricks(col, ro, Exists);
+    }else if (*lives <= 0){
+        display.ClearScreen();
+        display.GotoXY(32,32);
+        display.PrintString("GAME OVER!!!");
+        wait(3);
+        *score = 0;
+        *lives = 3;
+        display.ClearScreen();
+        DrawLogo();                             //drawing ARM-kanoid title
+        DrawTable(*score,*lives);                 //drawing table with score and number of lives
+        DrawBorder();                           //drawing border of the playing area
+        CreateGrid(&(*col), &(*ro), &(*Exists));
+        DrawBricks(col, ro, Exists);
+
+    }else{
+        display.FullCircle(*XBall, *YBall, BallD, BLACK);
+        display.FullRectangle(*XPaddle, PadY, *XPaddle+PadLength ,PadY+2,BLACK);
+        DrawTable(*score, *lives);
+        float angle = (pi/180)*(90+(rand()%(2*maxangle)));
+        *dxBall = (round(velocity*cos(angle)));
+        if (*dxBall == 0){
+            *dxBall = 1;
+        }
+        *dyBall = (-round(velocity*sin(angle)));
+        display.GotoXY(0,0);
+        display.PrintNumber(*dxBall);
+        display.GotoXY(15,0);
+        display.PrintNumber(*dyBall);
+        wait(1);
+        *Start = false;
+    }
+}
+
+void CreateGrid(uint8_t* col, uint8_t* ro, bool* exists){       //creates grid that will be later used for drawing bricks
+    int8_t i;
+    for (i = 0; i < columns; i++){
+        *(col+i) = maxX + i*(BrickW + 2);
+    }
+    for (i = 0; i < rows; i++){
+        *(ro+i) = minY + i*(BrickH + 2);
+    }
+    int8_t j;
+    for (i = 0; i < rows; i++){
+        for (j = 0; j < columns; j++){
+            *(exists+i*columns+j)=true;
+        }
+    }
+}
+
+void DrawBricks(uint8_t col[columns], uint8_t ro[rows], bool exists[rows*columns]){ //draws bricks in prepared grid - these two functions are separated in case of creating another levels
+
+    int8_t i;
+    int8_t j;
+    for (j = 0; j < rows; j++){
+        for (i = 0; i < columns; i++){
+            display.FullRectangle(col[i], ro[j], (col[i] + BrickW), (ro[j] + BrickH) ,((exists[j*columns+i])? BLACK:WHITE));
+        }
+    }
+}
+
+void BounceBricks(uint8_t XBall, uint8_t YBall, int8_t* dxBall, int8_t* dyBall, bool* BrickExists, uint8_t ro[rows], uint8_t col[columns], uint8_t* score, uint8_t lives, bool* Start){ //computes reflections from bricks, destroys bricks, counts score etc...
+    if (YBall <= (ro[rows-1]+BrickH)){
+        int8_t i, j;
+        for (j = rows - 1; j >= 0; j--){
+            if (((YBall-BallD) <= (ro[j]+BrickH))&&((YBall+BallD) > ro[j])){
+                break;
+            }
+        }
+        for (i = columns - 1; i >= 0; i--){
+            if (((XBall-BallD) <= (col[i]+BrickW))&&((XBall+BallD) > col[i])){
+                break;
+            }
+        }
+        if (*(BrickExists+j*columns+i)){
+            *(BrickExists+j*columns+i) = false;
+            display.FullRectangle(col[i], ro[j], (col[i] + BrickW), (ro[j] + BrickH), WHITE);
+            (*score)++;
+            if (*score == (rows*columns)){
+                *Start = true;
+            }
+            DrawTable(*score, lives);
+            if (!((YBall-*dyBall) <= (minY))){
+                *dyBall = -(*dyBall);
+            }
+        }else{
+            if ((YBall-BallD) <= (minY+1)){
+                *dyBall = -(*dyBall);
+            }
+        }
+    }
+}
\ No newline at end of file