A implementation of a simple bomberman game

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

Fork of rtos_basic by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "SDFileSystem.h"
00003 #include "wave_player.h"
00004 #include "myBMP.h"
00005 #include <string>
00006 #include "navSwitch.h"
00007 #include <mpr121.h>
00008 #include "rtos.h"
00009 
00010 float gameTime = 0.0;
00011 
00012 string startText = "Loading";
00013 
00014 bool gameRestart = false;
00015 
00016 SDFileSystem sd(p11, p12, p13, p16, "sd"); //SD card
00017 
00018 AnalogOut DACout(p18);
00019 
00020 wave_player waver(&DACout);
00021 
00022 uLCD_4DGL uLCD(p28,p27,p30);
00023 
00024 int BACK = 0x2E0059;
00025 
00026 char grid[7][7];
00027 
00028 int o_p1I=0, o_p1J=0, o_p2I=6, o_p2J=6;
00029 int p1I=0, p1J=0, p2I=6, p2J=6;
00030 
00031 Nav_Switch myNav( p17, p6, p7, p5, p8);
00032 bool navUpPress = false, navLeftPress = false,
00033      navRightPress = false, navDownPress = false, navFirePress = false;
00034 
00035 I2C i2c(p9, p10);
00036 Mpr121 pad(&i2c, Mpr121::ADD_VSS);
00037 
00038 bool padUpPress = false, padLeftPress = false,
00039      padRightPress = false, padDownPress = false, padFirePress = false;
00040 
00041 struct Bomb {
00042     float createTime;
00043     int playerId;
00044     int startI, startJ;
00045     int power;
00046     int minX, maxX, minY, maxY;
00047     bool exploded, soundPlayed;
00048     float cookTime, expTime;
00049     int decay,color;
00050     int o_decay;
00051 };
00052 
00053 Bomb bombs[10];
00054 int bombIndex=0, numBombs = 0;
00055 int bufferSize = 10;
00056 
00057 int p1Bombs=1, p2Bombs=1;
00058 int p1Power=1, p2Power=1;
00059 
00060 void resetVars(){
00061     gameRestart = false;
00062     
00063     o_p1I=0;
00064     o_p1J=0;
00065     o_p2I=6; 
00066     o_p2J=6;
00067     p1I=0;
00068     p1J=0;
00069     p2I=6;
00070     p2J=6;
00071     
00072     numBombs = 0;
00073     bombIndex = 0;
00074     
00075     p1Bombs = 1;
00076     p1Power = 1;
00077     p2Bombs = 1;
00078     p2Power = 1;
00079 }
00080 
00081 bool outOfBounds(int i, int j){
00082    return i < 0 || i > 6 || j < 0 || j > 6;
00083 }
00084 
00085 bool valid(int i, int j)
00086 {
00087     if(outOfBounds(i,j)){
00088         return false;    
00089     }
00090 
00091     return grid[i][j] != 'b' && grid[i][j] != 's';
00092 }
00093 
00094 int getX(int j)
00095 {
00096     return 8+16*j;
00097 }
00098 
00099 int getY(int i)
00100 {
00101     return 8+16*i;
00102 }
00103 
00104 void createBomb(int pId, int i, int j)
00105 {
00106     Bomb *b = &bombs[(bombIndex + numBombs)%bufferSize];
00107     numBombs++;
00108 
00109     b->playerId = pId;
00110     b->createTime = gameTime;
00111     b->startI = i;
00112     b->startJ = j;
00113     b->power = (pId == 1)? p1Power : p2Power;
00114     if(pId == 1) {
00115         p1Bombs--;
00116     } else {
00117         p2Bombs--;
00118     }
00119     b->exploded = false;
00120     b->cookTime = 1.5;
00121     b->expTime = .8;
00122     b->decay = 0;
00123     b->o_decay = 0;
00124     b->soundPlayed = false;
00125 }
00126 
00127 void resetBlock(int i, int j){
00128     if(grid[i][j] == ' '){
00129         grid[i][j] = 'c';
00130         return;
00131     }
00132     int rr = (int)(gameTime * 1000) + 1023 * i + 523 * j;
00133     if(rr%3 == 0){
00134         grid[i][j] = 'k';
00135     }else if(rr%3 == 1){
00136         grid[i][j] = 'd';
00137     }else{
00138         grid[i][j] = 'c'; 
00139     }
00140 }
00141 
00142 void clearArea(Bomb *b)
00143 {
00144     //find minX
00145     int p = b->power;
00146     int i = b->startI;
00147     int j = b->startJ;
00148     while(p>0) {
00149         if(outOfBounds(i,j-1) || grid[i][j-1] == 's') {
00150             break;
00151         }           
00152         resetBlock(i,j-1);
00153         j--;
00154         p--;
00155     }
00156     b->minX = getX(j) + ((p==0)?3:0);
00157 
00158     //find maxX
00159     p = b->power;
00160     i = b->startI;
00161     j = b->startJ;
00162     while(p>0) {
00163         if(outOfBounds(i,j+1) || grid[i][j+1] == 's') {
00164             break;
00165         }
00166         resetBlock(i,j+1);
00167         j++;
00168         p--;
00169     }
00170     b->maxX = getX(j+1)+((p==0)?-3:0);
00171 
00172     //find minY
00173     p = b->power;
00174     i = b->startI;
00175     j = b->startJ;
00176     while(p>0) {
00177         if(outOfBounds(i-1,j) || grid[i-1][j] == 's') {
00178             break;
00179         }
00180         resetBlock(i-1,j);
00181         i--;
00182         p--;
00183     }
00184     b->minY = getY(i) + ((p==0)?3:0);
00185 
00186     //find maxY
00187     p = b->power;
00188     i = b->startI;
00189     j = b->startJ;
00190     while(p>0) {
00191         if(outOfBounds(i+1,j) || grid[i+1][j] == 's') {
00192             break;
00193         }
00194         resetBlock(i+1,j);
00195         i++;
00196         p--;
00197     }
00198     b->maxY = getY(i+1) + ((p==0)?-3:0);
00199 }
00200 
00201 void playExplosion()
00202 {
00203     while(true){
00204         bool expFound = false;
00205         while(!expFound){
00206             for(int i = 0; i < numBombs; i++) {
00207                 Bomb *b = &bombs[(bombIndex + i)%bufferSize]; 
00208                 if(b->exploded && !b->soundPlayed){
00209                     expFound = true;
00210                     b->soundPlayed = true;
00211                 }
00212             }
00213             Thread::wait(100);
00214         }
00215         FILE *explosion;
00216         explosion=fopen("/sd/explosion.wav","r");
00217         waver.play(explosion);
00218         fclose(explosion);
00219     }
00220 }
00221 
00222 void updateBombs()
00223 {
00224     for(int i = 0; i < numBombs; i++) {
00225         Bomb *b = &bombs[(bombIndex + i)%bufferSize];
00226         if(!b->exploded && (gameTime - b->createTime) > b->cookTime) {
00227             b->exploded = true;
00228             clearArea(b);
00229             
00230         }
00231         if(!b->exploded) {
00232             int index = (int)((gameTime - b->createTime)/.15);
00233             if((index & 0x11) == 0) {
00234                 b->color = WHITE;
00235             } else {
00236                 b->color = BLACK;
00237             }
00238         } else {
00239             int index = (int)((gameTime - b->createTime - b->cookTime)/.2);
00240             if(index == 0) {
00241                 b->color = WHITE;
00242             }
00243             if(index == 1) {
00244                 b->color = 0xFFFF00;
00245             }
00246             if(index == 2) {
00247                 b->color = 0xFF8800;
00248             }
00249             if(index >= 3) {
00250                 b->color = RED;
00251             }
00252             index = (int)((gameTime - b->createTime - b->cookTime)/.25);
00253             b->decay = index;
00254         }
00255     }
00256 }
00257 
00258 void drawBombs()
00259 {
00260     for(int i = 0; i < numBombs; i++) {
00261         Bomb *b = &bombs[(bombIndex + i)%bufferSize];
00262         int x = getX(b->startJ);
00263         int y = getY(b->startI);
00264         if(!b->exploded) {
00265             if(b->color == WHITE) {
00266                 uLCD.filled_circle(x+8,y+8,5, WHITE);
00267                 uLCD.filled_rectangle(x+7,y+1,x+9,y+3, WHITE);
00268             } else {
00269                 uLCD.filled_circle(x+8,y+8,5, BLACK);
00270                 uLCD.filled_rectangle(x+7,y+1,x+9,y+3, 0xFFFF00);
00271             }
00272         } else {
00273             if(b->o_decay != b->decay){
00274                 b->o_decay = b->decay;
00275                 uLCD.filled_rectangle(b->minX,y+3,b->maxX,y+13, BACK);
00276                 uLCD.filled_rectangle(x+3,b->minY,x+13,b->maxY, BACK);
00277             }
00278 
00279             if(gameTime - b->createTime < (b->cookTime + b->expTime)) {
00280                 uLCD.filled_rectangle(b->minX+b->decay,y+3+b->decay,b->maxX-b->decay,y+13-b->decay, b->color);
00281                 uLCD.filled_rectangle(x+3+b->decay,b->minY+b->decay,x+13-b->decay,b->maxY-b->decay, b->color);
00282             } else {
00283                 uLCD.filled_rectangle(b->minX,y+3,b->maxX,y+13, BACK);
00284                 uLCD.filled_rectangle(x+3,b->minY,x+13,b->maxY, BACK);
00285                 if(b->playerId == 1) {
00286                     p1Bombs++;
00287                 } else {
00288                     p2Bombs++;
00289                 }
00290                 bombIndex=(bombIndex+1)%bufferSize;
00291                 numBombs--;
00292             }
00293         }
00294     }
00295 }
00296 
00297 void generateGrid()
00298 {
00299     //init empty
00300     for(int i = 0; i < 7; i++) {
00301         for(int j = 0; j < 7; j++) {
00302             grid[i][j] = ' ';
00303         }
00304     }
00305     //generate solids
00306     for(int i = 1; i < 7; i+=2) {
00307         for(int j = 1; j < 7; j+=2) {
00308             grid[i][j] = 's';
00309         }
00310     }
00311     //generate breakables
00312     for(int i = 0; i < 7; i++) {
00313         for(int j = 0; j < 7; j++) {
00314             if(grid[i][j] == 's') {
00315                 continue;
00316             }
00317             bool hasBreakable = (i*17+j*349)%4 != 0;
00318             if(hasBreakable) {
00319                 grid[i][j] = 'b';
00320             }
00321         }
00322     }
00323     //clear player regions
00324     grid[0][0] = ' ';
00325     grid[1][0] = ' ';
00326     grid[0][1] = ' ';
00327     grid[6][6] = ' ';
00328     grid[5][6] = ' ';
00329     grid[6][5] = ' ';
00330 }
00331 
00332 void drawImg(string imgName, int x, int y)
00333 {
00334     RGBApixel *Colors = new RGBApixel [2];
00335     string file = "/sd/" + imgName;
00336     ReadBMPFromFile(x,y, file.c_str(), Colors, &uLCD);
00337 }
00338 
00339 void drawPlayer(int id)
00340 {
00341     int col_prim, col_sec, x, y;
00342     if(id == 1) {
00343         col_prim = 0xFFD8B2;
00344         col_sec = 0xFFB2B2;
00345         x = getX(p1J);
00346         y = getY(p1I);
00347     }
00348     if(id == 2) {
00349         col_prim = 0xC6B2FF;
00350         col_sec = 0xFFB2FF;
00351         x = getX(p2J);
00352         y = getY(p2I);
00353     }
00354     uLCD.filled_rectangle(x+3,y+3,x+13,y+10, col_prim);
00355     uLCD.filled_rectangle(x+5,y+5,x+6,y+8, BLACK);
00356     uLCD.filled_rectangle(x+10,y+5,x+11,y+8, BLACK);
00357     uLCD.filled_rectangle(x+5,y+10,x+7,y+13, col_sec);
00358     uLCD.filled_rectangle(x+9,y+10,x+11,y+13, col_sec);
00359 }
00360 
00361 void initialDraw()
00362 {
00363     uLCD.baudrate(3000000);
00364     uLCD.filled_rectangle(0,0,128,128, BACK);
00365     uLCD.text_width(2);
00366     uLCD.text_height(2);
00367     uLCD.color(WHITE);
00368     uLCD.locate(1,4);
00369     uLCD.printf("%s",startText);
00370     for(int i = -1; i < 8; i++){
00371         for(int j = -1; j < 8; j++){
00372             string img;
00373             int c = -1;
00374             if(i == -1 || j == -1 || i == 7 || j == 7){
00375                img = "wall.bmp";
00376                //c = BLACK;
00377             }else{
00378                 if(grid[i][j] == ' '){
00379                     c = BACK;
00380                 }
00381                 if(grid[i][j] == 'b'){
00382                     img = "break.bmp";
00383                     //c = 0x888888;
00384                 }
00385                 if(grid[i][j] == 's'){
00386                     img = "wall.bmp";
00387                     //c = BLACK;
00388                 }
00389             }
00390             int x = getX(j);
00391             int y = getY(i);
00392             if(c != -1){
00393                 uLCD.filled_rectangle(x,y,x+16,y+16, c);
00394             }else{
00395                 drawImg(img, x, y);
00396             }
00397         
00398         }
00399     }
00400     drawPlayer(1);
00401     drawPlayer(2);
00402 }
00403 
00404 
00405 void updateP1()
00406 {
00407     if(!navUpPress && myNav.up()) {
00408         p1I++;
00409         navUpPress = true;
00410     }
00411     if(!navDownPress && myNav.down()) {
00412         p1I--;
00413         navDownPress = true;
00414     }
00415     if(!navLeftPress && myNav.left()) {
00416         p1J++;
00417         navLeftPress = true;
00418     }
00419     if(!navRightPress && myNav.right()) {
00420         p1J--;
00421         navRightPress = true;
00422     }
00423     if(!navFirePress && myNav.fire() && p1Bombs >0) {
00424         createBomb(1,p1I,p1J);
00425         navFirePress = true;
00426     }
00427 
00428     if(!valid(p1I,p1J)) {
00429         p1I = o_p1I;
00430         p1J = o_p1J;
00431     }
00432     
00433     if(grid[p1I][p1J] == 'f'){
00434         p1Power++;   
00435         grid[p1I][p1J] = 'c'; 
00436     }
00437     if(grid[p1I][p1J] == 'i'){
00438         p1Bombs++;    
00439         grid[p1I][p1J] = 'c';
00440     }
00441 
00442     if(!myNav.up()) {
00443         navUpPress = false;
00444     }
00445     if(!myNav.down()) {
00446         navDownPress = false;
00447     }
00448     if(!myNav.left()) {
00449         navLeftPress = false;
00450     }
00451     if(!myNav.right()) {
00452         navRightPress = false;
00453     }
00454     if(!myNav.fire()) {
00455         navFirePress = false;
00456     }
00457 }
00458 
00459 bool isOne(int val, int pos)
00460 {
00461     return val >> pos & 0x01;
00462 }
00463 
00464 void updateP2()
00465 {
00466     int value=pad.read(0x00);
00467     value +=pad.read(0x01)<<8;
00468 
00469     bool up =  isOne(value,5);
00470     bool down =  isOne(value,7);
00471     bool left = isOne(value,10);
00472     bool right = isOne(value,2);
00473     bool fire = isOne(value,6);
00474 
00475     if(!padUpPress && up) {
00476         p2I--;
00477         padUpPress = true;
00478     }
00479     if(!padDownPress && down) {
00480         p2I++;
00481         padDownPress = true;
00482     }
00483     if(!padLeftPress && left) {
00484         p2J--;
00485         padLeftPress = true;
00486     }
00487     if(!padRightPress && right) {
00488         p2J++;
00489         padRightPress = true;
00490     }
00491     if(!padFirePress && fire && p2Bombs > 0) {
00492         createBomb(2,p2I,p2J);
00493         padFirePress = true;
00494     }
00495 
00496     if(!valid(p2I,p2J)) {
00497         p2I = o_p2I;
00498         p2J = o_p2J;
00499     }
00500     
00501     if(grid[p2I][p2J] == 'f'){
00502         p2Power++;   
00503         grid[p2I][p2J] = 'c'; 
00504     }
00505     if(grid[p2I][p2J] == 'i'){
00506         p2Bombs++;    
00507         grid[p2I][p2J] = 'c';
00508     }
00509     
00510     if(!up) {
00511         padUpPress = false;
00512     }
00513     if(!down) {
00514         padDownPress = false;
00515     }
00516     if(!left) {
00517         padLeftPress = false;
00518     }
00519     if(!right) {
00520         padRightPress = false;
00521     }
00522     if(!fire) {
00523         padFirePress = false;
00524     }
00525 }
00526 
00527 void draw()
00528 {
00529     for(int i = 0; i < 7; i++){
00530         for(int j = 0; j < 7; j++){
00531             if(grid[i][j] == 'c' || grid[i][j] == 'd' || grid[i][j] == 'k'){
00532                 if(grid[i][j] == 'c') grid[i][j] = ' ';
00533                 if(grid[i][j] == 'd') grid[i][j] = 'f';
00534                 if(grid[i][j] == 'k') grid[i][j] = 'i';
00535                 uLCD.filled_rectangle(getX(j),getY(i),getX(j+1),getY(i+1), BACK);
00536             }
00537             if(grid[i][j] == 'f'){
00538                 uLCD.filled_circle(getX(j)+8,getY(i)+8,3,RED);
00539             }
00540             if(grid[i][j] == 'i'){
00541                 uLCD.filled_circle(getX(j)+8,getY(i)+8,3,0xFFFF00);
00542             }
00543         }    
00544     }
00545     if(p1I != o_p1I || p1J != o_p1J) {
00546         int o_x = getX(o_p1J);
00547         int o_y = getY(o_p1I);
00548         uLCD.filled_rectangle(o_x,o_y,o_x+16,o_y+16, BACK);
00549         o_p1I = p1I;
00550         o_p1J = p1J;
00551     }
00552     if(p2I != o_p2I || p2J != o_p2J) {
00553         int o_x = getX(o_p2J);
00554         int o_y = getY(o_p2I);
00555         uLCD.filled_rectangle(o_x,o_y,o_x+16,o_y+16, BACK);
00556         o_p2I = p2I;
00557         o_p2J = p2J;
00558     }
00559     drawBombs();
00560     drawPlayer(1);
00561     drawPlayer(2);
00562 }
00563 
00564 void checkPlayerDeath(int pid){
00565     if(gameRestart) return;
00566     int centerX = getX((pid == 1)?(p1J):(p2J))+8;
00567     int centerY = getY((pid == 1)?(p1I):(p2I))+8;
00568     for(int i = 0; i < numBombs; i++) {
00569         Bomb *b = &bombs[(bombIndex + i)%bufferSize];
00570         if(b->exploded){
00571             int bx = getX(b->startJ);
00572             int by = getY(b->startI);
00573             if(b->minX < centerX && centerX < b->maxX && by < centerY && centerY < by+16){
00574                 gameRestart = true;
00575             }
00576             if(b->minY < centerY && centerY < b->maxY && bx < centerX && centerX < bx+16){
00577                 gameRestart = true;
00578             }
00579         }
00580     }
00581     if(gameRestart){
00582         if(pid == 1){
00583             startText = "P1 Died";
00584         }else{
00585             startText = "P2 Died";
00586         }
00587     }
00588 }
00589 
00590 int main()
00591 {
00592     Thread thr(playExplosion);
00593     while(true){
00594         resetVars();
00595         generateGrid();
00596         initialDraw();
00597         while(!gameRestart) {
00598             updateP1();
00599             updateP2();
00600             updateBombs();
00601             checkPlayerDeath(1);
00602             checkPlayerDeath(2);
00603             draw();
00604             gameTime+=.02;
00605             wait(.02);
00606         }
00607         wait(3);
00608     }
00609 }