A implementation of a simple bomberman game
Dependencies: 4DGL-uLCD-SE SDFileSystem mbed-rtos mbed wave_player
Fork of rtos_basic by
Diff: main.cpp
- 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); + } +}