An implementation of "BrickBreaker" for the mbed platform using the uLCD-4DGL display and a 5-Way joystick

Dependencies:   4DGL-uLCD-SE SDFileSystem mbed-rtos mbed wave_player

main.cpp

Committer:
nini1294
Date:
2016-10-31
Revision:
1:b20b76acf0ed
Parent:
0:c9df12bcc92d

File content as of revision 1:b20b76acf0ed:

#include "mbed.h"
#include "uLCD_4DGL.h"
#include "Nav_Switch.h"
#include "rtos.h"
#include "SDFileSystem.h"
#include "wave_player.h"

#define BALL_RADIUS 2
#define MOVE_AMT 5
#define BLOCK_HEIGHT 12
#define BLOCK_WIDTH 16
#define PADDLE_COLOR 0xFF0000

#define EXPLOSION_RED 0xFF0000
#define EXPLOSION_YELLOW 0xFFFF00

Nav_Switch myNav( p9, p6, p7, p5, p8); //pin order on Sparkfun breakout
uLCD_4DGL uLCD(p28,p27,p22);

SDFileSystem sd(p11, p12, p13, p21, "sd"); //SD card
AnalogOut DACout(p18);
wave_player waver(&DACout);

struct Paddle {
    int x1, x2, y1, y2;
};

struct Ball {
    float x, y, xvel, yvel;
};

struct Block {
    int x1, y1, x2, y2;
    bool active;
    int color;
};

struct Explosion {
    int x, y;
    bool active;
    int tick;
};

Paddle p1;
Ball b1;
struct Block blocks[24];
struct Explosion explosions[5];
int gameover = 0;
bool redrawExplosions = true;
bool sound = false;
int old_bx, old_by;
int old_x1, old_x2;
int blocksBroken;
Ticker speedTimeout;
int speedIncreases;

Mutex splosions;

void brickBreak(int, int);
void drawBlocks();

void playPaddle() {
    printf("Paddle1\n");
    FILE *wave_file;
    wave_file=fopen("/sd/mydir/paddle.wav","r");
    waver.play(wave_file);
    fclose(wave_file);
}

void playWall() {
    FILE *wave_file;
    wave_file=fopen("/sd/mydir/wall.wav","r");
    waver.play(wave_file);
    fclose(wave_file);
}

void playExplosion() {
    printf("Boom\n");
    FILE *wave_file;
    
    bool check;
    while (1) {
        splosions.lock();
        check = sound;
        splosions.unlock();
        if (check) {
            printf("Explosion1\n");
            wave_file=fopen("/sd/mydir/explosion.wav","r");
            waver.play(wave_file);
            fclose(wave_file);
            Thread::wait(250);
            printf("Explosion2\n");
        }
        Thread::wait(250);
    }
}

void playGO() {
    printf("GO\n");
    FILE *wave_file;
    wave_file=fopen("/sd/mydir/go.wav","r");
    waver.play(wave_file);
    fclose(wave_file);
}

void createExplosion(int x, int y) {
    for (int i = 0; i < 5; i++) {
        if (!explosions[i].active) {
            explosions[i].active = true;
            explosions[i].x = x;
            explosions[i].y = y;
            explosions[i].tick = 0;
            redrawExplosions = true;
            Thread t2(playExplosion);
            return;
        }
    }
}

void drawExplosions() {
    redrawExplosions = false;
    for (int i = 0; i < 5; i++) {
        if (explosions[i].active) {
            
            redrawExplosions = true;
            splosions.lock();
            sound = true;
            splosions.unlock();
            if (explosions[i].tick > 5) {
                uLCD.filled_circle(explosions[i].x, explosions[i].y, explosions[i].tick + 5, EXPLOSION_RED);
            }
            uLCD.filled_circle(explosions[i].x, explosions[i].y, explosions[i].tick, EXPLOSION_YELLOW);
            explosions[i].tick++;
            if (explosions[i].tick > 10) {
                uLCD.filled_circle(explosions[i].x, explosions[i].y, explosions[i].tick + 8, BLACK);
                explosions[i].tick = 0;
                explosions[i].active = false;
                drawBlocks();
                splosions.lock();
                sound = false;
                splosions.unlock();
            }
        }
    }
}

void movePaddle(int amt) {
    if (p1.x1 + amt <= 0) {
        p1.x1 = 0;
        p1.x2 = 13;
    } else {
        p1.x1 = p1.x1 + amt;
        p1.x2 = p1.x2 + amt;
    }
    if (p1.x2 + amt > 127) {
        p1.x1 = 114;
        p1.x2 = 127;
    } else {
        p1.x1 = p1.x1 + amt;
        p1.x2 = p1.x2 + amt;
    }
}

void drawPaddle() {
    uLCD.filled_rectangle(old_x1, p1.y1, old_x2, p1.y2, BLACK);
    uLCD.filled_rectangle(p1.x1, p1.y1, p1.x2, p1.y2, PADDLE_COLOR);
    old_x1 = p1.x1;
    old_x2 = p1.x2;
}

void moveBall() {
    int newx = b1.x + b1.xvel;
    int newy = b1.y - b1.yvel;
//    printf("x: %d xvel: %d y: %d yvel: %d\n",newx, b1.xvel, newy, b1.yvel);
    if (newx < 2 || newx > 125) {
        b1.xvel = - b1.xvel;
    } if (newy <= 2) {
        b1.yvel = -b1.yvel;
    } if (newy > 122) {
        if (newx >= p1.x1 && newx < p1.x2) {
            b1.yvel = - b1.yvel;
        } else {
            gameover = -1;
        }
    }
    brickBreak(newx, newy);
    b1.x = b1.x + b1.xvel;
    b1.y = b1.y - b1.yvel;
}

void decrementIncreases() {
    if (speedIncreases > 0) {
        speedIncreases--;
    }
}

void incSpeed() {
    if (speedIncreases < 4) {
        b1.xvel += b1.xvel * 1.1;
        b1.yvel += b1.yvel * 1.1;
    }
    printf("x:%f y:%f", b1.xvel, b1.yvel);
}

void checkWin() {
    if (blocksBroken == 24) {
        gameover = 1;
    }
}

void brickBreak(int nx, int ny) {
    for (int i = 0; i < 24; i++) {
        if (blocks[i].active) {
            if (nx > blocks[i].x1 && nx < blocks[i].x2) {
                if (ny < blocks[i].y2) {
                    blocks[i].active = false;
                    b1.yvel = -b1.yvel;
                    uLCD.filled_rectangle(blocks[i].x1, blocks[i].y1, blocks[i].x2, blocks[i].y2, BLACK);
                    createExplosion(nx, ny);
                    blocksBroken++;
                    checkWin();
                }
            }
        }
    }
}

void drawBall() {
    uLCD.filled_circle(old_bx, old_by, BALL_RADIUS, BLACK);
    uLCD.filled_circle(b1.x, b1.y, BALL_RADIUS, WHITE);
    old_bx = b1.x;
    old_by = b1.y;
}

void initBlocks() {
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 3; j++) {
//            printf("%d\n", j * 8 + i);
            blocks[j * 8 + i].x1 = i * BLOCK_WIDTH;
            blocks[j * 8 + i].y1 = j * BLOCK_HEIGHT;
            blocks[j * 8 + i].x2 = i * BLOCK_WIDTH + BLOCK_WIDTH;
            blocks[j * 8 + i].y2 = j * BLOCK_HEIGHT + BLOCK_HEIGHT;
            blocks[j * 8 + i].active = true;
            blocks[j * 8 + i].color = (i + j) % 2 == 0 ? GREEN : BLUE;
        }
    }
}

void drawBlocks() {
    for (int i = 0; i < 24 ; i++) {
        Block tmp = blocks[i];
        if (tmp.active) {
//            printf("%d %d %d %d\n", tmp.x1, tmp.y1, tmp.x2, tmp.y2);
            uLCD.filled_rectangle(tmp.x1, tmp.y1, tmp.x2, tmp.y2, tmp.color);
        }
    }
}

void startGame() {
    p1.x1 = 56;
    p1.x2 = 70;
    p1.y1 = 124;
    p1.y2 = 127;
    b1.x = 63;
    b1.y = 121;
    b1.xvel = 0;
    b1.yvel = 0;
    blocksBroken = 0;
    speedIncreases = 0;
    splosions.lock();
    sound = false;
    splosions.unlock();
    drawPaddle();
    drawBall();
    initBlocks();
    drawBlocks();
    while(gameover == 0) {
        myNav.read();
        if(myNav.right()) {
            movePaddle(MOVE_AMT);
            drawPaddle();
            if (b1.xvel == 0 && b1.yvel == 0) {
                b1.x = (p1.x1 + p1.x2) / 2;
                drawBall();
            }
//          printf("%d\n", p1.x1);
        }
        if (myNav.left()) {
            movePaddle(-MOVE_AMT);
            drawPaddle();
            if (b1.xvel == 0 || b1.yvel == 0) {
                b1.x = (p1.x1 + p1.x2) / 2;
                drawBall();
            }
//          printf("%d\n", p1.x1);
        }
        if (myNav.fire()) {
            b1.xvel = 1 + rand() % 7 - 4;
            b1.yvel = 1 + rand() % 3;
        }
        if (myNav.down()) {
            gameover = 1;
        }
        if (myNav.up()) {
            incSpeed();
        }
        moveBall();
        if (b1.xvel != 0 || b1.yvel != 0) {
            drawBall();
        }
        if (redrawExplosions) {
            drawExplosions();
        }
        wait(0.1);
    }
}

int main() {
    uLCD.baudrate(3000000);
    Thread t2(playExplosion);
    Thread t1(playPaddle);
    speedTimeout.attach(&decrementIncreases, 5.0);
    while(1) {
        startGame();
        printf("Over\n");
        if (gameover == -1) { 
            uLCD.text_string("GAME OVER", 5, 8, 1, RED);
        } else if (gameover == 1) {
            uLCD.text_string("YOU WIN!", 5, 8, 1, RED);
        }
        playGO();
        wait(2);
        uLCD.cls();
        printf("Out\n");
        gameover = 0;
    }
}