A implementation of a simple bomberman game

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

Fork of rtos_basic by mbed official

Revision:
7:12f7fd2b1a13
Parent:
3:c92e21f305d8
--- a/main.cpp	Tue Jun 04 16:01:32 2013 +0100
+++ b/main.cpp	Mon Oct 31 19:33:11 2016 +0000
@@ -1,21 +1,609 @@
 #include "mbed.h"
+#include "SDFileSystem.h"
+#include "wave_player.h"
+#include "myBMP.h"
+#include <string>
+#include "navSwitch.h"
+#include <mpr121.h>
 #include "rtos.h"
- 
-DigitalOut led1(LED1);
-DigitalOut led2(LED2);
- 
-void led2_thread(void const *args) {
-    while (true) {
-        led2 = !led2;
-        Thread::wait(1000);
+
+float gameTime = 0.0;
+
+string startText = "Loading";
+
+bool gameRestart = false;
+
+SDFileSystem sd(p11, p12, p13, p16, "sd"); //SD card
+
+AnalogOut DACout(p18);
+
+wave_player waver(&DACout);
+
+uLCD_4DGL uLCD(p28,p27,p30);
+
+int BACK = 0x2E0059;
+
+char grid[7][7];
+
+int o_p1I=0, o_p1J=0, o_p2I=6, o_p2J=6;
+int p1I=0, p1J=0, p2I=6, p2J=6;
+
+Nav_Switch myNav( p17, p6, p7, p5, p8);
+bool navUpPress = false, navLeftPress = false,
+     navRightPress = false, navDownPress = false, navFirePress = false;
+
+I2C i2c(p9, p10);
+Mpr121 pad(&i2c, Mpr121::ADD_VSS);
+
+bool padUpPress = false, padLeftPress = false,
+     padRightPress = false, padDownPress = false, padFirePress = false;
+
+struct Bomb {
+    float createTime;
+    int playerId;
+    int startI, startJ;
+    int power;
+    int minX, maxX, minY, maxY;
+    bool exploded, soundPlayed;
+    float cookTime, expTime;
+    int decay,color;
+    int o_decay;
+};
+
+Bomb bombs[10];
+int bombIndex=0, numBombs = 0;
+int bufferSize = 10;
+
+int p1Bombs=1, p2Bombs=1;
+int p1Power=1, p2Power=1;
+
+void resetVars(){
+    gameRestart = false;
+    
+    o_p1I=0;
+    o_p1J=0;
+    o_p2I=6; 
+    o_p2J=6;
+    p1I=0;
+    p1J=0;
+    p2I=6;
+    p2J=6;
+    
+    numBombs = 0;
+    bombIndex = 0;
+    
+    p1Bombs = 1;
+    p1Power = 1;
+    p2Bombs = 1;
+    p2Power = 1;
+}
+
+bool outOfBounds(int i, int j){
+   return i < 0 || i > 6 || j < 0 || j > 6;
+}
+
+bool valid(int i, int j)
+{
+    if(outOfBounds(i,j)){
+        return false;    
+    }
+
+    return grid[i][j] != 'b' && grid[i][j] != 's';
+}
+
+int getX(int j)
+{
+    return 8+16*j;
+}
+
+int getY(int i)
+{
+    return 8+16*i;
+}
+
+void createBomb(int pId, int i, int j)
+{
+    Bomb *b = &bombs[(bombIndex + numBombs)%bufferSize];
+    numBombs++;
+
+    b->playerId = pId;
+    b->createTime = gameTime;
+    b->startI = i;
+    b->startJ = j;
+    b->power = (pId == 1)? p1Power : p2Power;
+    if(pId == 1) {
+        p1Bombs--;
+    } else {
+        p2Bombs--;
+    }
+    b->exploded = false;
+    b->cookTime = 1.5;
+    b->expTime = .8;
+    b->decay = 0;
+    b->o_decay = 0;
+    b->soundPlayed = false;
+}
+
+void resetBlock(int i, int j){
+    if(grid[i][j] == ' '){
+        grid[i][j] = 'c';
+        return;
+    }
+    int rr = (int)(gameTime * 1000) + 1023 * i + 523 * j;
+    if(rr%3 == 0){
+        grid[i][j] = 'k';
+    }else if(rr%3 == 1){
+        grid[i][j] = 'd';
+    }else{
+        grid[i][j] = 'c'; 
+    }
+}
+
+void clearArea(Bomb *b)
+{
+    //find minX
+    int p = b->power;
+    int i = b->startI;
+    int j = b->startJ;
+    while(p>0) {
+        if(outOfBounds(i,j-1) || grid[i][j-1] == 's') {
+            break;
+        }           
+        resetBlock(i,j-1);
+        j--;
+        p--;
+    }
+    b->minX = getX(j) + ((p==0)?3:0);
+
+    //find maxX
+    p = b->power;
+    i = b->startI;
+    j = b->startJ;
+    while(p>0) {
+        if(outOfBounds(i,j+1) || grid[i][j+1] == 's') {
+            break;
+        }
+        resetBlock(i,j+1);
+        j++;
+        p--;
+    }
+    b->maxX = getX(j+1)+((p==0)?-3:0);
+
+    //find minY
+    p = b->power;
+    i = b->startI;
+    j = b->startJ;
+    while(p>0) {
+        if(outOfBounds(i-1,j) || grid[i-1][j] == 's') {
+            break;
+        }
+        resetBlock(i-1,j);
+        i--;
+        p--;
+    }
+    b->minY = getY(i) + ((p==0)?3:0);
+
+    //find maxY
+    p = b->power;
+    i = b->startI;
+    j = b->startJ;
+    while(p>0) {
+        if(outOfBounds(i+1,j) || grid[i+1][j] == 's') {
+            break;
+        }
+        resetBlock(i+1,j);
+        i++;
+        p--;
+    }
+    b->maxY = getY(i+1) + ((p==0)?-3:0);
+}
+
+void playExplosion()
+{
+    while(true){
+        bool expFound = false;
+        while(!expFound){
+            for(int i = 0; i < numBombs; i++) {
+                Bomb *b = &bombs[(bombIndex + i)%bufferSize]; 
+                if(b->exploded && !b->soundPlayed){
+                    expFound = true;
+                    b->soundPlayed = true;
+                }
+            }
+            Thread::wait(100);
+        }
+        FILE *explosion;
+        explosion=fopen("/sd/explosion.wav","r");
+        waver.play(explosion);
+        fclose(explosion);
+    }
+}
+
+void updateBombs()
+{
+    for(int i = 0; i < numBombs; i++) {
+        Bomb *b = &bombs[(bombIndex + i)%bufferSize];
+        if(!b->exploded && (gameTime - b->createTime) > b->cookTime) {
+            b->exploded = true;
+            clearArea(b);
+            
+        }
+        if(!b->exploded) {
+            int index = (int)((gameTime - b->createTime)/.15);
+            if((index & 0x11) == 0) {
+                b->color = WHITE;
+            } else {
+                b->color = BLACK;
+            }
+        } else {
+            int index = (int)((gameTime - b->createTime - b->cookTime)/.2);
+            if(index == 0) {
+                b->color = WHITE;
+            }
+            if(index == 1) {
+                b->color = 0xFFFF00;
+            }
+            if(index == 2) {
+                b->color = 0xFF8800;
+            }
+            if(index >= 3) {
+                b->color = RED;
+            }
+            index = (int)((gameTime - b->createTime - b->cookTime)/.25);
+            b->decay = index;
+        }
+    }
+}
+
+void drawBombs()
+{
+    for(int i = 0; i < numBombs; i++) {
+        Bomb *b = &bombs[(bombIndex + i)%bufferSize];
+        int x = getX(b->startJ);
+        int y = getY(b->startI);
+        if(!b->exploded) {
+            if(b->color == WHITE) {
+                uLCD.filled_circle(x+8,y+8,5, WHITE);
+                uLCD.filled_rectangle(x+7,y+1,x+9,y+3, WHITE);
+            } else {
+                uLCD.filled_circle(x+8,y+8,5, BLACK);
+                uLCD.filled_rectangle(x+7,y+1,x+9,y+3, 0xFFFF00);
+            }
+        } else {
+            if(b->o_decay != b->decay){
+                b->o_decay = b->decay;
+                uLCD.filled_rectangle(b->minX,y+3,b->maxX,y+13, BACK);
+                uLCD.filled_rectangle(x+3,b->minY,x+13,b->maxY, BACK);
+            }
+
+            if(gameTime - b->createTime < (b->cookTime + b->expTime)) {
+                uLCD.filled_rectangle(b->minX+b->decay,y+3+b->decay,b->maxX-b->decay,y+13-b->decay, b->color);
+                uLCD.filled_rectangle(x+3+b->decay,b->minY+b->decay,x+13-b->decay,b->maxY-b->decay, b->color);
+            } else {
+                uLCD.filled_rectangle(b->minX,y+3,b->maxX,y+13, BACK);
+                uLCD.filled_rectangle(x+3,b->minY,x+13,b->maxY, BACK);
+                if(b->playerId == 1) {
+                    p1Bombs++;
+                } else {
+                    p2Bombs++;
+                }
+                bombIndex=(bombIndex+1)%bufferSize;
+                numBombs--;
+            }
+        }
     }
 }
- 
-int main() {
-    Thread thread(led2_thread);
+
+void generateGrid()
+{
+    //init empty
+    for(int i = 0; i < 7; i++) {
+        for(int j = 0; j < 7; j++) {
+            grid[i][j] = ' ';
+        }
+    }
+    //generate solids
+    for(int i = 1; i < 7; i+=2) {
+        for(int j = 1; j < 7; j+=2) {
+            grid[i][j] = 's';
+        }
+    }
+    //generate breakables
+    for(int i = 0; i < 7; i++) {
+        for(int j = 0; j < 7; j++) {
+            if(grid[i][j] == 's') {
+                continue;
+            }
+            bool hasBreakable = (i*17+j*349)%4 != 0;
+            if(hasBreakable) {
+                grid[i][j] = 'b';
+            }
+        }
+    }
+    //clear player regions
+    grid[0][0] = ' ';
+    grid[1][0] = ' ';
+    grid[0][1] = ' ';
+    grid[6][6] = ' ';
+    grid[5][6] = ' ';
+    grid[6][5] = ' ';
+}
+
+void drawImg(string imgName, int x, int y)
+{
+    RGBApixel *Colors = new RGBApixel [2];
+    string file = "/sd/" + imgName;
+    ReadBMPFromFile(x,y, file.c_str(), Colors, &uLCD);
+}
+
+void drawPlayer(int id)
+{
+    int col_prim, col_sec, x, y;
+    if(id == 1) {
+        col_prim = 0xFFD8B2;
+        col_sec = 0xFFB2B2;
+        x = getX(p1J);
+        y = getY(p1I);
+    }
+    if(id == 2) {
+        col_prim = 0xC6B2FF;
+        col_sec = 0xFFB2FF;
+        x = getX(p2J);
+        y = getY(p2I);
+    }
+    uLCD.filled_rectangle(x+3,y+3,x+13,y+10, col_prim);
+    uLCD.filled_rectangle(x+5,y+5,x+6,y+8, BLACK);
+    uLCD.filled_rectangle(x+10,y+5,x+11,y+8, BLACK);
+    uLCD.filled_rectangle(x+5,y+10,x+7,y+13, col_sec);
+    uLCD.filled_rectangle(x+9,y+10,x+11,y+13, col_sec);
+}
+
+void initialDraw()
+{
+    uLCD.baudrate(3000000);
+    uLCD.filled_rectangle(0,0,128,128, BACK);
+    uLCD.text_width(2);
+    uLCD.text_height(2);
+    uLCD.color(WHITE);
+    uLCD.locate(1,4);
+    uLCD.printf("%s",startText);
+    for(int i = -1; i < 8; i++){
+        for(int j = -1; j < 8; j++){
+            string img;
+            int c = -1;
+            if(i == -1 || j == -1 || i == 7 || j == 7){
+               img = "wall.bmp";
+               //c = BLACK;
+            }else{
+                if(grid[i][j] == ' '){
+                    c = BACK;
+                }
+                if(grid[i][j] == 'b'){
+                    img = "break.bmp";
+                    //c = 0x888888;
+                }
+                if(grid[i][j] == 's'){
+                    img = "wall.bmp";
+                    //c = BLACK;
+                }
+            }
+            int x = getX(j);
+            int y = getY(i);
+            if(c != -1){
+                uLCD.filled_rectangle(x,y,x+16,y+16, c);
+            }else{
+                drawImg(img, x, y);
+            }
+        
+        }
+    }
+    drawPlayer(1);
+    drawPlayer(2);
+}
+
+
+void updateP1()
+{
+    if(!navUpPress && myNav.up()) {
+        p1I++;
+        navUpPress = true;
+    }
+    if(!navDownPress && myNav.down()) {
+        p1I--;
+        navDownPress = true;
+    }
+    if(!navLeftPress && myNav.left()) {
+        p1J++;
+        navLeftPress = true;
+    }
+    if(!navRightPress && myNav.right()) {
+        p1J--;
+        navRightPress = true;
+    }
+    if(!navFirePress && myNav.fire() && p1Bombs >0) {
+        createBomb(1,p1I,p1J);
+        navFirePress = true;
+    }
+
+    if(!valid(p1I,p1J)) {
+        p1I = o_p1I;
+        p1J = o_p1J;
+    }
     
-    while (true) {
-        led1 = !led1;
-        Thread::wait(500);
+    if(grid[p1I][p1J] == 'f'){
+        p1Power++;   
+        grid[p1I][p1J] = 'c'; 
+    }
+    if(grid[p1I][p1J] == 'i'){
+        p1Bombs++;    
+        grid[p1I][p1J] = 'c';
+    }
+
+    if(!myNav.up()) {
+        navUpPress = false;
+    }
+    if(!myNav.down()) {
+        navDownPress = false;
+    }
+    if(!myNav.left()) {
+        navLeftPress = false;
+    }
+    if(!myNav.right()) {
+        navRightPress = false;
+    }
+    if(!myNav.fire()) {
+        navFirePress = false;
     }
 }
+
+bool isOne(int val, int pos)
+{
+    return val >> pos & 0x01;
+}
+
+void updateP2()
+{
+    int value=pad.read(0x00);
+    value +=pad.read(0x01)<<8;
+
+    bool up =  isOne(value,5);
+    bool down =  isOne(value,7);
+    bool left = isOne(value,10);
+    bool right = isOne(value,2);
+    bool fire = isOne(value,6);
+
+    if(!padUpPress && up) {
+        p2I--;
+        padUpPress = true;
+    }
+    if(!padDownPress && down) {
+        p2I++;
+        padDownPress = true;
+    }
+    if(!padLeftPress && left) {
+        p2J--;
+        padLeftPress = true;
+    }
+    if(!padRightPress && right) {
+        p2J++;
+        padRightPress = true;
+    }
+    if(!padFirePress && fire && p2Bombs > 0) {
+        createBomb(2,p2I,p2J);
+        padFirePress = true;
+    }
+
+    if(!valid(p2I,p2J)) {
+        p2I = o_p2I;
+        p2J = o_p2J;
+    }
+    
+    if(grid[p2I][p2J] == 'f'){
+        p2Power++;   
+        grid[p2I][p2J] = 'c'; 
+    }
+    if(grid[p2I][p2J] == 'i'){
+        p2Bombs++;    
+        grid[p2I][p2J] = 'c';
+    }
+    
+    if(!up) {
+        padUpPress = false;
+    }
+    if(!down) {
+        padDownPress = false;
+    }
+    if(!left) {
+        padLeftPress = false;
+    }
+    if(!right) {
+        padRightPress = false;
+    }
+    if(!fire) {
+        padFirePress = false;
+    }
+}
+
+void draw()
+{
+    for(int i = 0; i < 7; i++){
+        for(int j = 0; j < 7; j++){
+            if(grid[i][j] == 'c' || grid[i][j] == 'd' || grid[i][j] == 'k'){
+                if(grid[i][j] == 'c') grid[i][j] = ' ';
+                if(grid[i][j] == 'd') grid[i][j] = 'f';
+                if(grid[i][j] == 'k') grid[i][j] = 'i';
+                uLCD.filled_rectangle(getX(j),getY(i),getX(j+1),getY(i+1), BACK);
+            }
+            if(grid[i][j] == 'f'){
+                uLCD.filled_circle(getX(j)+8,getY(i)+8,3,RED);
+            }
+            if(grid[i][j] == 'i'){
+                uLCD.filled_circle(getX(j)+8,getY(i)+8,3,0xFFFF00);
+            }
+        }    
+    }
+    if(p1I != o_p1I || p1J != o_p1J) {
+        int o_x = getX(o_p1J);
+        int o_y = getY(o_p1I);
+        uLCD.filled_rectangle(o_x,o_y,o_x+16,o_y+16, BACK);
+        o_p1I = p1I;
+        o_p1J = p1J;
+    }
+    if(p2I != o_p2I || p2J != o_p2J) {
+        int o_x = getX(o_p2J);
+        int o_y = getY(o_p2I);
+        uLCD.filled_rectangle(o_x,o_y,o_x+16,o_y+16, BACK);
+        o_p2I = p2I;
+        o_p2J = p2J;
+    }
+    drawBombs();
+    drawPlayer(1);
+    drawPlayer(2);
+}
+
+void checkPlayerDeath(int pid){
+    if(gameRestart) return;
+    int centerX = getX((pid == 1)?(p1J):(p2J))+8;
+    int centerY = getY((pid == 1)?(p1I):(p2I))+8;
+    for(int i = 0; i < numBombs; i++) {
+        Bomb *b = &bombs[(bombIndex + i)%bufferSize];
+        if(b->exploded){
+            int bx = getX(b->startJ);
+            int by = getY(b->startI);
+            if(b->minX < centerX && centerX < b->maxX && by < centerY && centerY < by+16){
+                gameRestart = true;
+            }
+            if(b->minY < centerY && centerY < b->maxY && bx < centerX && centerX < bx+16){
+                gameRestart = true;
+            }
+        }
+    }
+    if(gameRestart){
+        if(pid == 1){
+            startText = "P1 Died";
+        }else{
+            startText = "P2 Died";
+        }
+    }
+}
+
+int main()
+{
+    Thread thr(playExplosion);
+    while(true){
+        resetVars();
+        generateGrid();
+        initialDraw();
+        while(!gameRestart) {
+            updateP1();
+            updateP2();
+            updateBombs();
+            checkPlayerDeath(1);
+            checkPlayerDeath(2);
+            draw();
+            gameTime+=.02;
+            wait(.02);
+        }
+        wait(3);
+    }
+}