Hugo Hu / Mbed 2 deprecated BRAVEHEART

Dependencies:   mbed N5110 ShiftReg PinDetect

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Game.cpp Source File

Game.cpp

Go to the documentation of this file.
00001 #include "Game.h "
00002 
00003 /// @file Game.cpp
00004 
00005 Game::~Game()
00006 {
00007     clearAll();
00008 }
00009 
00010 void Game::clearAll()
00011 {
00012     // Free allocated memory from bullets
00013     for (std::vector<Point*>::iterator it = gameProperty.bullets.begin(); it != gameProperty.bullets.end(); ++it)
00014         delete *it;
00015     
00016     gameProperty.bullets.clear();
00017     
00018     // Free allocated memory from enemies
00019     for (std::vector<Enemy*>::iterator it = gameProperty.enemies.begin(); it != gameProperty.enemies.end(); ++it)
00020         delete *it;
00021     
00022     gameProperty.enemies.clear();
00023     
00024     // Set initial values for the player
00025     gameProperty.player.width = gameProperty.player.height = 5;
00026     
00027     gameProperty.player.vx = 0;
00028     gameProperty.player.vy = 0;
00029     
00030     gameProperty.player.dead = false;
00031     
00032     gameProperty.player.facingLeft = false;
00033 }    
00034 
00035 void Game::init()
00036 {   
00037     if (gameProperty.currentLayer == 1){
00038         Global::score = 0;
00039         gameProperty.paused = false;
00040         gameProperty.livesLeft = 3; 
00041         memcpy(&mapProperty,&mapProperty1,sizeof(mapProperty1));
00042     } 
00043     else 
00044     {
00045         clearAll();
00046         switch(gameProperty.currentLayer)
00047         {
00048             case 2:
00049                 memcpy(&mapProperty,&mapProperty2,sizeof(mapProperty2));
00050                 break;
00051             case 3:
00052                 
00053             break;
00054             case 4:
00055                 
00056             break;  
00057         }
00058     
00059     }
00060     const int seven_seg_array [] = {
00061         0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71
00062     };
00063     shift.write(seven_seg_array[gameProperty.livesLeft]);
00064     
00065     respawnPlayer();
00066 
00067     spawnEnemy();
00068 }
00069 
00070 
00071 
00072 void Game::spawnEnemy()
00073 {
00074     
00075     // Get random spawn point
00076     int r = rand() % 3;
00077     int x = mapProperty.enermyPosition[r][0];
00078     int y = mapProperty.enermyPosition[r][1];
00079     
00080     // Spawn random enemy
00081     int randPercent = (rand() % 100);
00082     Enemy::Type type;
00083         
00084     if (randPercent >= 40)      // 60% probability
00085         type = Enemy::JUMPER;
00086     else if (randPercent >= 15) // 25% probablitiy
00087         type = Enemy::SIMPLE;
00088     else                        // 15 % probability
00089         type = Enemy::RUNNER;
00090         
00091     // Create enemy
00092     Enemy *enemy = new Enemy(x, y, true, type);
00093     gameProperty.enemies.push_back(enemy);
00094 }
00095 
00096 // Functions
00097 void Game::update(float dt)
00098 {    
00099     // Pause button input
00100     if (input->read(Input::ButtonC))
00101     {
00102         if (releasedBtnC)
00103         {
00104             gameProperty.paused = !gameProperty.paused;
00105             releasedBtnC = false;
00106         }
00107     }
00108     else
00109         releasedBtnC = true;
00110         
00111     // Skip the rest if paused
00112     if (gameProperty.paused) return;  
00113     
00114     // if successfully reach the end
00115     if (gameProperty.player.x == mapProperty.succeedPosition[0] && gameProperty.player.y == mapProperty.succeedPosition[1])
00116     {
00117         gameProperty.currentLayer += 1;
00118         init();
00119     }
00120     
00121     // if respawn new enermy
00122     if ((rand() % 100) < mapProperty.spawnRate && !gameProperty.player.dead && gameProperty.enemies.size() <= mapProperty.maxEnermy)
00123         spawnEnemy();
00124 
00125         
00126     // Handle input, should be its own function
00127     switch(input->joystick->getDirection())
00128     {
00129         case LEFT:
00130             gameProperty.player.vx = -1;
00131             gameProperty.player.facingLeft = true;
00132         break;
00133         case UP_LEFT:
00134             gameProperty.player.vx = -1;
00135             gameProperty.player.vy = -1;
00136             gameProperty.player.facingLeft = true;
00137         break;
00138         case DOWN_LEFT:
00139             gameProperty.player.vx = -1;
00140             gameProperty.player.vy = 1;
00141             gameProperty.player.facingLeft = true;
00142         break;
00143         case RIGHT:
00144             gameProperty.player.vx = 1;
00145             gameProperty.player.facingLeft = false;
00146         break;
00147         case UP_RIGHT:
00148             gameProperty.player.vx = 1;
00149             gameProperty.player.vy = -1;
00150             gameProperty.player.facingLeft = false;
00151         break;
00152         case DOWN_RIGHT:
00153             gameProperty.player.vx = 1;
00154             gameProperty.player.vy = 1;
00155             gameProperty.player.facingLeft = false;
00156         break;
00157         case UP:
00158             gameProperty.player.vy = -1;
00159             gameProperty.player.facingLeft = false;
00160         break;
00161         case DOWN:
00162             gameProperty.player.vy = 1;
00163             gameProperty.player.facingLeft = false;
00164         break;
00165         case CENTER:
00166             gameProperty.player.vx = 0;
00167             gameProperty.player.vy = 0;
00168         break;
00169     }
00170     
00171     if (!gameProperty.player.dead)
00172     {
00173         switch(gameProperty.currentLayer)
00174         {
00175             case 1:
00176                 moveWithCollisionTest(&gameProperty.player, map1);
00177                 break;
00178             case 2:
00179                 moveWithCollisionTest(&gameProperty.player, map2);
00180                 break;
00181         }
00182     }
00183     else // move without testing collision agains the map
00184     {
00185         gameProperty.player.x += gameProperty.player.vx;
00186         gameProperty.player.y += 4;
00187     }
00188     
00189     moveEnemies();
00190     
00191     // Check if bullet should be fired
00192     if (input->read(Input::ButtonB) && releasedBtnB && !gameProperty.player.dead)
00193     {
00194         // Create a new bullet and give it initial values
00195         Point* bullet = new Point;
00196         bullet->x = (int)(gameProperty.player.x + (gameProperty.player.width / 2)); 
00197         bullet->y = gameProperty.player.y + 2;
00198         bullet->vx = (gameProperty.player.facingLeft) ? -4 : 4;
00199         bullet->vy = 0;
00200         
00201         gameProperty.bullets.push_back(bullet);
00202         releasedBtnB = false;
00203         
00204         // Play sound
00205         // sound->playNote(SFX::BULLET_FIRED);
00206     }
00207     else if (!input->read(Input::ButtonB))
00208         releasedBtnB = true;
00209     
00210     // Loop through bullets and move them + collision test
00211     for (std::vector<Point*>::iterator it = gameProperty.bullets.begin(); it != gameProperty.bullets.end();)
00212     {
00213         Point* bullet = *it;
00214         
00215         int x0; // left border of collision rect
00216         int x1; // right border of collision rect
00217         
00218         int oldX = bullet->x;
00219         int newX = bullet->x + bullet->vx;
00220         
00221         x0 = min(oldX, newX);
00222         x1 = max(oldX, newX);
00223             
00224         // Collision rect for bullet in this time step
00225         Rectangle bulletColRect(x0, bullet->y, (x1-x0)+1, 1);
00226         
00227         bool col = false;
00228         // Delete if outside screen
00229         switch(gameProperty.currentLayer)
00230         {
00231             case 1:
00232                 if (newX < 0 || newX > WIDTH || bulletHitMap(bulletColRect, map1)) // if outside screen
00233                     col = true;
00234                 else
00235                 {
00236                     // loop through all enemies
00237                     for (std::vector<Enemy*>::iterator ite = gameProperty.enemies.begin(); ite != gameProperty.enemies.end(); ++ite)
00238                     {
00239                         Enemy *enemy = *ite;
00240                         
00241                         // If bullet hits enemy
00242                         //if (!enemy->dead && bullet->x >= enemy->x && bullet->x <= enemy->getRight() && bullet->y >= enemy->y && bullet->y <= enemy->getBottom()) 
00243                         
00244                         Rectangle enemyColRect(enemy->x, enemy->y, enemy->width, enemy->height); // collision rectangle for enemy
00245                         
00246                         if (!enemy->dead && hitTestRect(bulletColRect, enemyColRect))
00247                         {
00248                             col = true;
00249                             
00250                             enemy->dead = true;
00251                             enemy->vx = bullet->vx / 2; // sends the dead enemy in the same direction as the incoming bullet
00252                             enemy->vy = -3;             // sends the dead enemy upwards in the air, because of impact
00253                             
00254                             Global::score += 5 * enemy->difficulty; // increase the score
00255                             
00256                             // sound->playNote(SFX::ENEMY_DEAD);
00257                         }
00258                     }
00259                 }
00260                 break;
00261             case 2:
00262                 if (newX < 0 || newX > WIDTH || bulletHitMap(bulletColRect, map2)) // if outside screen
00263                     col = true;
00264                 else
00265                 {
00266                     // loop through all enemies
00267                     for (std::vector<Enemy*>::iterator ite = gameProperty.enemies.begin(); ite != gameProperty.enemies.end(); ++ite)
00268                     {
00269                         Enemy *enemy = *ite;
00270                         
00271                         // If bullet hits enemy
00272                         //if (!enemy->dead && bullet->x >= enemy->x && bullet->x <= enemy->getRight() && bullet->y >= enemy->y && bullet->y <= enemy->getBottom()) 
00273                         
00274                         Rectangle enemyColRect(enemy->x, enemy->y, enemy->width, enemy->height); // collision rectangle for enemy
00275                         
00276                         if (!enemy->dead && hitTestRect(bulletColRect, enemyColRect))
00277                         {
00278                             col = true;
00279                             
00280                             enemy->dead = true;
00281                             enemy->vx = bullet->vx / 2; // sends the dead enemy in the same direction as the incoming bullet
00282                             enemy->vy = -3;             // sends the dead enemy upwards in the air, because of impact
00283                             
00284                             Global::score += 5 * enemy->difficulty; // increase the score
00285                             
00286                             // sound->playNote(SFX::ENEMY_DEAD);
00287                         }
00288                     }
00289                 }
00290                 break; 
00291         }
00292         
00293         
00294         if (!col)
00295         {
00296             ++it;   // go to next element
00297             bullet->x += bullet->vx; // update position
00298         }
00299         else
00300         {
00301             delete bullet;
00302             it = gameProperty.bullets.erase(it); // go to next element
00303         }
00304     }
00305     
00306     // Check if player hits enemy
00307     Rectangle playerRect(gameProperty.player.x, gameProperty.player.y, gameProperty.player.width, gameProperty.player.height);
00308     for (std::vector<Enemy*>::iterator it = gameProperty.enemies.begin(); it != gameProperty.enemies.end(); ++it)
00309     {
00310         Enemy *enemy = *it;
00311         
00312         if (enemy->dead) continue; // only test against living enemies
00313         
00314         Rectangle enemyRect(enemy->x, enemy->y, enemy->width, enemy->height);
00315         
00316         if (hitTestRect(playerRect, enemyRect))
00317         {
00318             gameProperty.player.dead = true;
00319             gameProperty.player.vx = 0;
00320             gameProperty.player.vy = 4;
00321             --gameProperty.livesLeft;
00322             // Show the livesleft
00323             int seven_seg_array [] = {
00324                 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71
00325             };
00326             shift.write(seven_seg_array[gameProperty.livesLeft]);
00327             
00328             // sound->playNote(SFX::PLAYER_DEAD);
00329             break;
00330         }
00331     }
00332     
00333     if (gameProperty.player.dead)
00334     {
00335         // remove all enemies (let them fall off)
00336         for (std::vector<Enemy*>::iterator it = gameProperty.enemies.begin(); it != gameProperty.enemies.end(); ++it)
00337         {
00338             Enemy *enemy = *it;
00339             enemy->dead = true;
00340             enemy->vy = 4;
00341         }
00342         
00343         if (gameProperty.player.y >= HEIGHT && !gameProperty.enemies.size()) // when all enemies are removed
00344         {
00345             if (gameProperty.livesLeft)
00346             {
00347                 respawnPlayer(); // Respawn player if it still have lives left
00348                 spawnEnemy();   // Spawn an enemy right away
00349             }
00350             else
00351             {
00352                 if (Global::score > Global::highscores[2].score) // If new high score
00353                     requestStateChange(SUBMIT_HIGHSCORE);
00354                 else
00355                     requestStateChange(GAME_OVER);
00356             }
00357         }
00358     }
00359 }
00360 
00361 void Game::render()
00362 {
00363     
00364     if (!gameProperty.player.dead)
00365     {
00366         // Draw map
00367         switch(gameProperty.currentLayer)
00368         {
00369             case 1:
00370                 drawImage(map1);
00371                 break;
00372             case 2:
00373                 drawImage(map2);
00374                 break;
00375             case 3:
00376                 drawImage(map_chest);
00377                 break;
00378             case 4:
00379                 drawImage(map_big1);
00380                 break;
00381         }
00382         // Draw ladder
00383         drawImage(Image::Ladder, mapProperty.succeedPosition[0], mapProperty.succeedPosition[1], false, false, false);
00384         
00385         // Draw respawnCircle
00386         drawImage(Image::RespawnSign, mapProperty.respawnPosition[0], mapProperty.respawnPosition[1], false, false, false);
00387         
00388         // Draw player
00389         drawImage(Image::Player, gameProperty.player.x, gameProperty.player.y, false, !gameProperty.player.facingLeft, gameProperty.player.dead);
00390     
00391         // Draw enemies
00392         
00393         for (std::vector<Enemy*>::iterator it = gameProperty.enemies.begin(); it != gameProperty.enemies.end(); ++it)
00394         {
00395             Enemy *enemy = *it;
00396             
00397             switch (enemy->type)
00398             {
00399                 case Enemy::SIMPLE:
00400                     drawImage(Image::EnemySimple, enemy->x, enemy->y, false, !enemy->facingLeft, enemy->dead);    
00401                 break;
00402                 
00403                 case Enemy::JUMPER:
00404                     drawImage(Image::EnemyJumper, enemy->x, enemy->y, false, !enemy->facingLeft, enemy->dead);
00405                 break;
00406                 
00407                 case Enemy::RUNNER:
00408                     drawImage(Image::EnemyRunner, enemy->x, enemy->y, false, !enemy->facingLeft, enemy->dead);
00409                 break;
00410                 
00411                 default:
00412                     ; // should not happen, don't render
00413             }
00414         }    
00415         
00416     
00417         // Render bullets
00418         for (std::vector<Point*>::iterator it = gameProperty.bullets.begin(); it != gameProperty.bullets.end(); ++it)
00419         {
00420             int x, y;
00421             x = (*it)->x;
00422             y = (*it)->y;
00423             
00424             if (x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT) // Boundary check
00425                 lcd->setPixel(x,y);
00426         }
00427     }
00428     else
00429     {
00430         // Print lives left
00431         std::stringstream ss;
00432         ss << "Lives left: " << gameProperty.livesLeft;
00433         lcd->printString(ss.str().c_str(), 4, 2);
00434     }
00435     
00436     
00437     // Draw pause
00438     if (gameProperty.paused)
00439     {
00440         lcd->drawRect(25, 14, 35, 13, 1); // create shadow at the bottom layer
00441         lcd->drawRect(24, 13, 35, 13, 0); // outline
00442         lcd->drawRect(25, 14, 33, 11, 2); // white fill
00443         lcd->printString("Pause", 27, 2); // text
00444     }
00445     
00446     // GUI
00447     // renderScore();
00448 }
00449 
00450 // Collision test between entites and map
00451 void Game::moveWithCollisionTest(Entity* entity, const bool map[HEIGHT][WIDTH])
00452 {   
00453     int x = entity->x;
00454     int y = entity->y;
00455     int steps = abs(entity->vx); // how many units (pixels) the entity should move in said direction
00456     bool collision; // true if colliding
00457     
00458     // Check x-axis
00459     if (entity->vx > 0) // moving right
00460     {
00461         int entityRight = x + entity->width - 1; // Need to check right border of entity, since it is moving right
00462         
00463         while(steps--) // While it still have more movement left
00464         {
00465             collision = false;
00466             
00467             // Wrapping
00468             if (entityRight+1 >= WIDTH)
00469                 entityRight = -1;// wants entityRight = -1, so next check is entityRight 0*/
00470             
00471             for (int i = 0; i < entity->height; ++i) // Loop through all vertical points on the right hand side of the entity (y+i)
00472             {
00473                 if (map[y+i][entityRight+1]) // If moving to the right leads to collision for given y+i
00474                 {
00475                     // Slope + allows player to climb to top of platform by going right if it hits close to top of wall.
00476                     if (!map[y+i-1][entityRight+1])
00477                     {
00478                         entity->vy = -1;
00479                     }
00480                     else
00481                     {
00482                         collision = true; // Then collision is true
00483                         break;            // Skip the for loop, no need for further testing
00484                     }
00485                         
00486                 }
00487             }
00488             
00489             if (collision) // If collision
00490                 break;     // skip the while loop, entity can not move further, even though its velocity is higher
00491             else
00492                 ++entityRight;  // Move entity one px to the right
00493         }
00494         
00495         // If wrap didn't work, make sure entity is on the correct side of the map
00496         if (entityRight < 0)
00497             entityRight = WIDTH-1;
00498             
00499         entity->x = entityRight - (entity->width - 1); // Update entity's position. Need to set upper-left pixel.
00500     }
00501     else // moving left
00502     {
00503         while(steps--) // While still movement left
00504         {
00505             collision = false;
00506             
00507             // Wrap around map
00508             if (x-1 < 0)
00509                 x = WIDTH; // causes x-1 in the next check to be WIDTH - 1
00510             
00511             // Check for all y-positions
00512             for (int i = 0; i < entity->height; ++i)
00513             {
00514                 
00515                 if (map[y+i][x-1])                  // If solid block
00516                 {
00517                     if (!map[y+i-1][x-1]) // If slope or close to top of wall (=> can climb by going left).
00518                     {
00519                         entity->vy = -1;   
00520                     }
00521                     else
00522                     {
00523                         collision = true;
00524                         break;                          // Collision detected, no further testing required
00525                     }
00526                 }
00527             }
00528             
00529             if (collision)
00530                 break;
00531             else
00532                 --x;    // Move to the left if no collision is detected
00533         }
00534         
00535         x %= WIDTH; // In case wrapping caused entity to crash with wall on other side, x should be 0 instead of WIDTH (invalid).
00536         
00537         entity->x = x; // update position
00538     }
00539     
00540     // Check collision with map in y-direction - works the same way as the x-axis, except for other axis
00541     x = entity->x;
00542     y = entity->y;
00543     steps = abs(entity->vy);
00544     
00545     if (entity->vy > 0) // downwards
00546     {
00547         int entityBottom = y + entity->height - 1; // Need to check if bottom part collides
00548         while(steps--)  // Still movement left
00549         {
00550             collision = false;
00551 
00552             for (int i = 0; i < entity->width; ++i)  // Loop through all x-position on lower part of entity
00553             {   
00554                 if (map[(entityBottom+1) % HEIGHT][x+i])       // If moving the entity one step down for a given (x+i)-position gives a collision
00555                 {
00556                     collision = true;
00557                     break;                          // No further testing required
00558                 }
00559             }
00560             
00561             if (collision)                          // If collision
00562             {
00563                 entity->vy = 0;                      // Set vertical velocity to 0 (playe
00564                 break;                               // Skip the while loop as the entity can not move further downwards
00565             }
00566             else                // Can safely move entity without collision
00567             {
00568                 ++entityBottom; // Move entity one step down
00569             }
00570         }
00571         
00572         // Wrapping
00573         y = (entityBottom - (entity->height - 1));
00574         if (y >= HEIGHT)            // if completely outside map
00575             y = -entity->height;    // wrap to top of map
00576             
00577         entity->y = y; // (entityBottom - (entity->height - 1));      // Update position when done moving, remember that entity.y refers to upper part of the entity
00578     }
00579     else // moving up, check collision from top
00580     {
00581         while(steps--)  // Still movement left
00582         {
00583             collision = false;
00584                             
00585             for (int i = 0; i < entity->width; ++i) // Check for all x-positions
00586             {
00587                 int y1 = ((y-1) + HEIGHT) % HEIGHT; // In case negative, because of wrapping
00588                 
00589                 if (map[y1][x+i])                  // If moving upwards gives collision for a given x+i
00590                 {
00591                     collision = true;               // Then we have a collision
00592                     break;                          // No further testing needed, skip for loop
00593                 }
00594             }
00595             
00596             if (collision)  // If collision was detected
00597             {
00598                 entity->vy = 0;  // Set vertical velocity to zero
00599                 break;          // Skip while loop as entity can not move further up
00600             }
00601             else            // If safe to move for all x-values
00602                 --y;        // Move entity one step up
00603         }
00604         
00605         // Wrapping
00606         if (y + (entity->height - 1) < 0)          // completely outside map (bottom of entity over top of map)
00607             y = HEIGHT-1 - entity->height - 1;     // Sets the altitude.
00608             
00609         entity->y = y;       // Update vertical position of entity
00610     }    
00611 }
00612 
00613 bool Game::hitTestRect(Rectangle r1, Rectangle r2)
00614 {
00615     return ((r1.x + r1.width > r2.x)       // r1's right edge to the right of r2's left edge
00616         &&  (r1.x < r2.x + r2.width)       // r1's left edge to the left of r2's right edge
00617         &&  (r1.y + r2.height > r2.y)      // r1's bottom lower than r2's top
00618         &&  (r1.y < r2.y + r2.height));    // r1's top higher than r2's bottom
00619     
00620 }
00621 
00622 bool Game::bulletHitMap(Rectangle &bulletColRect, const bool map[HEIGHT][WIDTH])
00623 {
00624     for (int j = 0; j < bulletColRect.width; ++j)
00625     {
00626         if (map[bulletColRect.y][bulletColRect.x + j])
00627             return true;
00628     }
00629     
00630     return false;
00631 }
00632 
00633 void Game::moveEnemies()
00634 {
00635     for (std::vector<Enemy*>::iterator it = gameProperty.enemies.begin(); it != gameProperty.enemies.end(); )
00636     {   
00637         Enemy *enemy = *it;
00638         
00639         if (!enemy->dead)
00640         {
00641             // Random movement for enemies
00642             if ((rand() % 100) < 20) // 20% chance
00643             {
00644                 enemy->vy = -1;
00645             }
00646             else if ((rand() % 100) > 90) // 10% chance
00647             {
00648                 // switch direction
00649                 enemy->vx *= -1;
00650                 enemy->facingLeft = (enemy->vx < 0);
00651             }
00652             
00653             switch(gameProperty.currentLayer)
00654             { 
00655                 case 1:
00656                     moveWithCollisionTest(enemy, map1);
00657                     break;
00658                 case 2:
00659                     moveWithCollisionTest(enemy, map2);
00660                     break;
00661             }
00662             
00663             
00664             // Enemy AI
00665             if (enemy->y >= 0)
00666             {
00667                 int nextRight = enemy->getRight() + 1;   // Next position of right edge if enemy moves to the right
00668                 nextRight %= WIDTH; // wrapping
00669                 bool flag = true;
00670                 for (int i = 0; i < enemy->height && flag; ++i)  // Check for all heights
00671                 {
00672                     // Check if crashing if moving right or left. Bounds should already be limited by moveWithCollisionTest!
00673                     switch(gameProperty.currentLayer)
00674                     { 
00675                         case 1:
00676                             if (map1[enemy->y + i][nextRight] || map1[enemy->y + i][enemy->x - 1])
00677                             {
00678                                 enemy->vx *= -1; // move in opposite direction
00679                                 enemy->facingLeft = !enemy->facingLeft; // toggle direction
00680                                 flag = false;          // no further testing required
00681                             }
00682                             break;
00683                         case 2:
00684                             if (map2[enemy->y + i][nextRight] || map2[enemy->y + i][enemy->x - 1])
00685                             {
00686                                 enemy->vx *= -1; // move in opposite direction
00687                                 enemy->facingLeft = !enemy->facingLeft; // toggle direction
00688                                 flag = false;         // no further testing required
00689                             }
00690                             break;
00691                     }
00692                 }
00693             }
00694             
00695             ++it;   // go to next enemy
00696         }
00697         else    // if enemy is dead
00698         {
00699             enemy->y += enemy->vy;
00700             enemy->x += enemy->vx;
00701             
00702             if (enemy->y >= HEIGHT) // if outside map (and dead)
00703             {
00704                 delete enemy;
00705                 it = gameProperty.enemies.erase(it); // remove and go to next enemy
00706             }
00707             else
00708                 ++it;   // go to next enemy
00709         }
00710     }   
00711 }
00712 
00713 void Game::renderScore()
00714 {
00715     int s = (Global::score < 100000) ? Global::score : 99999; // Max possible score is 99999.
00716     
00717     // Read digits
00718     int digits[5]; // max five
00719     // Count the number of digits in the score
00720     int numDigits = 0;
00721     do
00722     {
00723         digits[numDigits] = s % 10;
00724         s /= 10;
00725         ++numDigits;
00726     } while (s != 0 && numDigits < 5);
00727     
00728     
00729     // Draw score
00730     int xStart = 79;
00731     int xStep = 4; // width + 1
00732     int y = 2;
00733     int x;
00734     
00735     for (int i = 0; i < numDigits; ++i)
00736     {
00737         x = xStart - i * xStep;
00738         
00739         switch (digits[i])
00740         {
00741             case 1:
00742                 drawImage(Number::One, x, y);
00743             break;
00744             
00745             case 2:
00746                 drawImage(Number::Two, x, y);
00747             break;
00748             
00749             case 3:
00750                 drawImage(Number::Three, x, y);
00751             break;
00752             
00753             case 4:
00754                 drawImage(Number::Four, x, y);
00755             break;
00756             
00757             case 5:
00758                 drawImage(Number::Five, x, y);
00759             break;
00760             
00761             case 6:
00762                 drawImage(Number::Six, x, y);
00763             break;
00764             
00765             case 7:
00766                 drawImage(Number::Seven, x, y);
00767             break;
00768             
00769             case 8:
00770                 drawImage(Number::Eight, x, y);
00771             break;
00772             
00773             case 9:
00774                 drawImage(Number::Nine, x, y);
00775             break;
00776             
00777             case 0:
00778             default:
00779                 drawImage(Number::Zero, x, y);
00780             break;
00781         }
00782                 
00783     }
00784 }
00785 
00786 void Game::respawnPlayer()
00787 {
00788     gameProperty.player.x = mapProperty.respawnPosition[0];
00789     gameProperty.player.y = mapProperty.respawnPosition[1];
00790 
00791     gameProperty.player.vx = gameProperty.player.vy = 0;
00792     gameProperty.player.facingLeft = true;   
00793     gameProperty.player.dead = false;
00794 }