University project - accelerometer controlled Arkanoid

Dependencies:   KS0108 MMA8451Q mbed

main.cpp

Committer:
JSindelar
Date:
2015-01-18
Revision:
1:d08d63a7c50d
Parent:
0:9515d58c3408

File content as of revision 1:d08d63a7c50d:

#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);
            }
        }
    }
}