University project - accelerometer controlled Arkanoid
Dependencies: KS0108 MMA8451Q mbed
Diff: main.cpp
- 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