A simple one-level platform game. Developed as part of ELEC2645 at University of Leeds, spring 2015.

Dependencies:   N5110 PinDetect PowerControl mbed

An ARM mbed LPC1768 microcontroller have been used to develop a handheld arcade game in the style of an old-school platformer. This project is entirely my own independent work in all stages of the development; including design, defining project specifications, breadboard prototyping, schematic and PCB layout using CAD, assembly, testing and software development. Due to this being part of the ELEC2645 Embedded Systems Project module at University of Leeds, spring 2015, limitations were given on the available hardware components. Credit is due to the authors of the dependent libraries (N5110, Pin Detect, PowerControl and mbed). I would also like to thank the author of Game Programming Patterns as well as the authors of SFML Game Development for providing me with useful sources for programming design patterns.

/media/uploads/Siriagus/game_assembled.jpg

Project aims

  • Implement simple gameplay:
    • A single, fixed (no scrolling) level.
    • Player can move left to right, jump and shoot.
    • Enemies will drop from the top of the screen.
    • The player gets points for shooting enemies.
    • The player dies when it gets hits by an enemy.
  • Implement a simple menu system.
  • Enable the user to adjust the brightness of the display.
  • Output sound to enhance the user experience.

Software

The program flow is controlled by a finite state machine. The implemented design was inspired by the State design pattern from the books Game Programming Patterns and SFML Game Development. The StateManager class is responsible for updating and rendering the current selected state. It also changes the state based on request from the current state. The framework built for the state machine used in this project makes it easy to add new screens. The different main states (indicated by the background colour) and how the user interaction is shown below: /media/uploads/Siriagus/arcadegameuserinteraction.png

Hardware

Schematic:

/media/uploads/Siriagus/schematic.png

Printed circuit board (PCB):

/media/uploads/Siriagus/pcb.png

Images

A seperate program was written to convert images (png) to text-representation of the maps. Enemies and numbers on the screen are also collected from a sprite-sheet created in the same manner.

/media/uploads/Siriagus/unileeds3.png /media/uploads/Siriagus/newmap2.png

Committer:
Siriagus
Date:
Mon May 11 04:40:23 2015 +0000
Revision:
18:709ea375b0df
Parent:
17:d6a3b29cab31
Fixed some formatting errors in documentation.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Siriagus 7:678873947b29 1 #include "Game.h"
Siriagus 7:678873947b29 2
Siriagus 17:d6a3b29cab31 3 /// @file Game.cpp
Siriagus 17:d6a3b29cab31 4
Siriagus 17:d6a3b29cab31 5 Game::~Game()
Siriagus 17:d6a3b29cab31 6 {
Siriagus 17:d6a3b29cab31 7 // Free allocated memory from bullets
Siriagus 17:d6a3b29cab31 8 for (std::vector<Point*>::iterator it = bullets.begin(); it != bullets.end(); ++it)
Siriagus 17:d6a3b29cab31 9 delete *it;
Siriagus 17:d6a3b29cab31 10
Siriagus 17:d6a3b29cab31 11 bullets.clear();
Siriagus 17:d6a3b29cab31 12
Siriagus 17:d6a3b29cab31 13 // Free allocated memory from enemies
Siriagus 17:d6a3b29cab31 14 for (std::vector<Enemy*>::iterator it = enemies.begin(); it != enemies.end(); ++it)
Siriagus 17:d6a3b29cab31 15 delete *it;
Siriagus 17:d6a3b29cab31 16
Siriagus 17:d6a3b29cab31 17 enemies.clear();
Siriagus 17:d6a3b29cab31 18 }
Siriagus 8:9ac6a428fa26 19
Siriagus 8:9ac6a428fa26 20 void Game::init()
Siriagus 16:caf613d5b85e 21 {
Siriagus 17:d6a3b29cab31 22 Global::score = 0;
Siriagus 15:d5eb13c4c1c6 23 paused = false;
Siriagus 17:d6a3b29cab31 24 livesLeft = 2;
Siriagus 15:d5eb13c4c1c6 25
Siriagus 12:8178fad5e660 26 // Set initial values for the player
Siriagus 13:7ab71c7c311b 27 player.width = player.height = 5; // important that this is correct, see size of Image::Player in Resources.h
Siriagus 12:8178fad5e660 28 player.onGround = false;
Siriagus 17:d6a3b29cab31 29 respawnPlayer();
Siriagus 17:d6a3b29cab31 30
Siriagus 17:d6a3b29cab31 31 spawnRate = 2; // Probability for spawning a new enemy in percent
Siriagus 17:d6a3b29cab31 32 spawnEnemy();
Siriagus 16:caf613d5b85e 33 }
Siriagus 16:caf613d5b85e 34
Siriagus 17:d6a3b29cab31 35 // temporary move to game
Siriagus 17:d6a3b29cab31 36 const int Game::spawnPoints[3][2] = {{27,20}, {2,29}, {24,45}};
Siriagus 17:d6a3b29cab31 37
Siriagus 16:caf613d5b85e 38 void Game::spawnEnemy()
Siriagus 16:caf613d5b85e 39 {
Siriagus 17:d6a3b29cab31 40 // Get random spawn point
Siriagus 17:d6a3b29cab31 41 int r = rand() % 3;
Siriagus 17:d6a3b29cab31 42 int x = Game::spawnPoints[r][0];
Siriagus 17:d6a3b29cab31 43 int y = Game::spawnPoints[r][1];
Siriagus 17:d6a3b29cab31 44
Siriagus 17:d6a3b29cab31 45 // Spawn random enemy
Siriagus 17:d6a3b29cab31 46 int randPercent = (rand() % 100);
Siriagus 17:d6a3b29cab31 47 Enemy::Type type;
Siriagus 17:d6a3b29cab31 48
Siriagus 17:d6a3b29cab31 49 if (randPercent >= 40) // 60% probability
Siriagus 17:d6a3b29cab31 50 type = Enemy::JUMPER;
Siriagus 17:d6a3b29cab31 51 else if (randPercent >= 15) // 25% probablitiy
Siriagus 17:d6a3b29cab31 52 type = Enemy::SIMPLE;
Siriagus 17:d6a3b29cab31 53 else // 15 % probability
Siriagus 17:d6a3b29cab31 54 type = Enemy::RUNNER;
Siriagus 17:d6a3b29cab31 55
Siriagus 17:d6a3b29cab31 56 // Create enemy
Siriagus 17:d6a3b29cab31 57 Enemy *enemy = new Enemy(x, y, true, type);
Siriagus 16:caf613d5b85e 58 enemies.push_back(enemy);
Siriagus 8:9ac6a428fa26 59 }
Siriagus 8:9ac6a428fa26 60
Siriagus 8:9ac6a428fa26 61 // Functions
Siriagus 7:678873947b29 62 void Game::update(float dt)
Siriagus 16:caf613d5b85e 63 {
Siriagus 15:d5eb13c4c1c6 64 // Pause button input
Siriagus 15:d5eb13c4c1c6 65 if (input->read(Input::ButtonC))
Siriagus 15:d5eb13c4c1c6 66 {
Siriagus 15:d5eb13c4c1c6 67 if (releasedBtnC)
Siriagus 15:d5eb13c4c1c6 68 {
Siriagus 15:d5eb13c4c1c6 69 paused = !paused;
Siriagus 15:d5eb13c4c1c6 70 releasedBtnC = false;
Siriagus 15:d5eb13c4c1c6 71 }
Siriagus 15:d5eb13c4c1c6 72 }
Siriagus 15:d5eb13c4c1c6 73 else
Siriagus 15:d5eb13c4c1c6 74 releasedBtnC = true;
Siriagus 15:d5eb13c4c1c6 75
Siriagus 15:d5eb13c4c1c6 76 // Skip the rest if paused
Siriagus 17:d6a3b29cab31 77 if (paused) return;
Siriagus 15:d5eb13c4c1c6 78
Siriagus 17:d6a3b29cab31 79 if ((rand() % 100) < spawnRate )
Siriagus 16:caf613d5b85e 80 spawnEnemy();
Siriagus 16:caf613d5b85e 81
Siriagus 8:9ac6a428fa26 82 // Handle input, should be its own function
Siriagus 8:9ac6a428fa26 83 switch(input->joystick->getDirection())
Siriagus 8:9ac6a428fa26 84 {
Siriagus 8:9ac6a428fa26 85 case LEFT:
Siriagus 8:9ac6a428fa26 86 case UP_LEFT:
Siriagus 8:9ac6a428fa26 87 case DOWN_LEFT:
Siriagus 8:9ac6a428fa26 88 player.vx = -2;
Siriagus 11:adb68da98262 89 player.facingLeft = true;
Siriagus 8:9ac6a428fa26 90 break;
Siriagus 8:9ac6a428fa26 91
Siriagus 8:9ac6a428fa26 92 case RIGHT:
Siriagus 8:9ac6a428fa26 93 case UP_RIGHT:
Siriagus 8:9ac6a428fa26 94 case DOWN_RIGHT:
Siriagus 8:9ac6a428fa26 95 player.vx = 2;
Siriagus 11:adb68da98262 96 player.facingLeft = false;
Siriagus 8:9ac6a428fa26 97 break;
Siriagus 8:9ac6a428fa26 98
Siriagus 8:9ac6a428fa26 99 case CENTER:
Siriagus 8:9ac6a428fa26 100 player.vx = 0;
Siriagus 8:9ac6a428fa26 101 break;
Siriagus 8:9ac6a428fa26 102 }
Siriagus 7:678873947b29 103
Siriagus 16:caf613d5b85e 104
Siriagus 16:caf613d5b85e 105 // MOVE: Random enemies
Siriagus 13:7ab71c7c311b 106
Siriagus 13:7ab71c7c311b 107 // Gravity
Siriagus 11:adb68da98262 108 player.vy += 1;
Siriagus 8:9ac6a428fa26 109
Siriagus 11:adb68da98262 110 // Check if player is trying to jump. Player can only jump if it's on the ground
Siriagus 12:8178fad5e660 111 if (input->read(Input::ButtonA) && player.onGround)
Siriagus 8:9ac6a428fa26 112 {
Siriagus 8:9ac6a428fa26 113 player.vy = -4;
Siriagus 12:8178fad5e660 114 player.onGround = false;
Siriagus 17:d6a3b29cab31 115 sound->playNote(SFX::PLAYER_JUMP);
Siriagus 8:9ac6a428fa26 116 }
Siriagus 8:9ac6a428fa26 117
Siriagus 11:adb68da98262 118 // Terminal velocity 3 px/update
Siriagus 14:b4fed570abaf 119 if (player.vy > TERMINAL_VELOCITY) player.vy = TERMINAL_VELOCITY;
Siriagus 8:9ac6a428fa26 120
Siriagus 17:d6a3b29cab31 121 if (!player.dead)
Siriagus 17:d6a3b29cab31 122 moveWithCollisionTest(&player, map);
Siriagus 17:d6a3b29cab31 123 else // move without testing collision agains the map
Siriagus 17:d6a3b29cab31 124 {
Siriagus 17:d6a3b29cab31 125 player.x += player.vx;
Siriagus 17:d6a3b29cab31 126 player.y += player.vy;
Siriagus 17:d6a3b29cab31 127 }
Siriagus 11:adb68da98262 128
Siriagus 17:d6a3b29cab31 129
Siriagus 17:d6a3b29cab31 130 moveEnemies();
Siriagus 8:9ac6a428fa26 131
Siriagus 11:adb68da98262 132 // Check if bullet should be fired
Siriagus 9:da608ae65df9 133 if (input->read(Input::ButtonB) && releasedBtnB)
Siriagus 8:9ac6a428fa26 134 {
Siriagus 11:adb68da98262 135 // Create a new bullet and give it initial values
Siriagus 8:9ac6a428fa26 136 Point* bullet = new Point;
Siriagus 15:d5eb13c4c1c6 137 bullet->x = (int)(player.x + (player.width / 2)); //(player.facingLeft) ? (player.x-1) : (player.x + player.width);
Siriagus 8:9ac6a428fa26 138 bullet->y = player.y + 2;
Siriagus 11:adb68da98262 139 bullet->vx = (player.facingLeft) ? -4 : 4;
Siriagus 9:da608ae65df9 140 bullet->vy = 0;
Siriagus 8:9ac6a428fa26 141
Siriagus 8:9ac6a428fa26 142 bullets.push_back(bullet);
Siriagus 9:da608ae65df9 143 releasedBtnB = false;
Siriagus 17:d6a3b29cab31 144
Siriagus 17:d6a3b29cab31 145 // Play sound
Siriagus 17:d6a3b29cab31 146 sound->playNote(SFX::BULLET_FIRED);
Siriagus 8:9ac6a428fa26 147 }
Siriagus 9:da608ae65df9 148 else if (!input->read(Input::ButtonB))
Siriagus 9:da608ae65df9 149 releasedBtnB = true;
Siriagus 8:9ac6a428fa26 150
Siriagus 15:d5eb13c4c1c6 151 // Loop through bullets and move them + collision test
Siriagus 9:da608ae65df9 152 for (std::vector<Point*>::iterator it = bullets.begin(); it != bullets.end();)
Siriagus 8:9ac6a428fa26 153 {
Siriagus 15:d5eb13c4c1c6 154 Point* bullet = *it;
Siriagus 15:d5eb13c4c1c6 155
Siriagus 15:d5eb13c4c1c6 156 int x0; // left border of collision rect
Siriagus 15:d5eb13c4c1c6 157 int x1; // right border of collision rect
Siriagus 15:d5eb13c4c1c6 158
Siriagus 15:d5eb13c4c1c6 159 int oldX = bullet->x;
Siriagus 15:d5eb13c4c1c6 160 int newX = bullet->x + bullet->vx;
Siriagus 15:d5eb13c4c1c6 161
Siriagus 15:d5eb13c4c1c6 162 x0 = min(oldX, newX);
Siriagus 15:d5eb13c4c1c6 163 x1 = max(oldX, newX);
Siriagus 15:d5eb13c4c1c6 164
Siriagus 15:d5eb13c4c1c6 165 // Collision rect for bullet in this time step
Siriagus 15:d5eb13c4c1c6 166 Rectangle bulletColRect(x0, bullet->y, (x1-x0)+1, 1);
Siriagus 9:da608ae65df9 167
Siriagus 15:d5eb13c4c1c6 168 bool col = false;
Siriagus 15:d5eb13c4c1c6 169 // Delete if outside screen
Siriagus 15:d5eb13c4c1c6 170 if (newX < 0 || newX > WIDTH || bulletHitMap(bulletColRect, map)) // if outside screen
Siriagus 15:d5eb13c4c1c6 171 {
Siriagus 15:d5eb13c4c1c6 172 col = true;
Siriagus 15:d5eb13c4c1c6 173 }
Siriagus 15:d5eb13c4c1c6 174 else
Siriagus 9:da608ae65df9 175 {
Siriagus 15:d5eb13c4c1c6 176 // loop through all enemies
Siriagus 17:d6a3b29cab31 177 for (std::vector<Enemy*>::iterator ite = enemies.begin(); ite != enemies.end(); ++ite)
Siriagus 15:d5eb13c4c1c6 178 {
Siriagus 17:d6a3b29cab31 179 Enemy *enemy = *ite;
Siriagus 15:d5eb13c4c1c6 180
Siriagus 17:d6a3b29cab31 181 // If bullet hits enemy
Siriagus 17:d6a3b29cab31 182 //if (!enemy->dead && bullet->x >= enemy->x && bullet->x <= enemy->getRight() && bullet->y >= enemy->y && bullet->y <= enemy->getBottom())
Siriagus 17:d6a3b29cab31 183
Siriagus 17:d6a3b29cab31 184 Rectangle enemyColRect(enemy->x, enemy->y, enemy->width, enemy->height); // collision rectangle for enemy
Siriagus 17:d6a3b29cab31 185
Siriagus 17:d6a3b29cab31 186 if (!enemy->dead && hitTestRect(bulletColRect, enemyColRect))
Siriagus 16:caf613d5b85e 187 {
Siriagus 16:caf613d5b85e 188 col = true;
Siriagus 17:d6a3b29cab31 189
Siriagus 17:d6a3b29cab31 190 enemy->dead = true;
Siriagus 16:caf613d5b85e 191 enemy->vx = bullet->vx / 2; // sends the dead enemy in the same direction as the incoming bullet
Siriagus 16:caf613d5b85e 192 enemy->vy = -3; // sends the dead enemy upwards in the air, because of impact
Siriagus 16:caf613d5b85e 193
Siriagus 17:d6a3b29cab31 194 Global::score += 5 * enemy->difficulty; // increase the score
Siriagus 17:d6a3b29cab31 195
Siriagus 17:d6a3b29cab31 196 sound->playNote(SFX::ENEMY_DEAD);
Siriagus 16:caf613d5b85e 197 }
Siriagus 15:d5eb13c4c1c6 198 }
Siriagus 15:d5eb13c4c1c6 199 }
Siriagus 15:d5eb13c4c1c6 200
Siriagus 15:d5eb13c4c1c6 201 if (!col)
Siriagus 15:d5eb13c4c1c6 202 {
Siriagus 15:d5eb13c4c1c6 203 ++it; // go to next element
Siriagus 15:d5eb13c4c1c6 204 bullet->x += bullet->vx; // update position
Siriagus 15:d5eb13c4c1c6 205 }
Siriagus 15:d5eb13c4c1c6 206 else
Siriagus 15:d5eb13c4c1c6 207 {
Siriagus 15:d5eb13c4c1c6 208 delete bullet;
Siriagus 9:da608ae65df9 209 it = bullets.erase(it); // go to next element
Siriagus 9:da608ae65df9 210 }
Siriagus 17:d6a3b29cab31 211 }
Siriagus 17:d6a3b29cab31 212
Siriagus 17:d6a3b29cab31 213 // Check if player hits enemy
Siriagus 17:d6a3b29cab31 214 Rectangle playerRect(player.x, player.y, player.width, player.height);
Siriagus 17:d6a3b29cab31 215 for (std::vector<Enemy*>::iterator it = enemies.begin(); it != enemies.end(); ++it)
Siriagus 17:d6a3b29cab31 216 {
Siriagus 17:d6a3b29cab31 217 Enemy *enemy = *it;
Siriagus 8:9ac6a428fa26 218
Siriagus 17:d6a3b29cab31 219 if (enemy->dead) continue; // only test against living enemies
Siriagus 17:d6a3b29cab31 220
Siriagus 17:d6a3b29cab31 221 Rectangle enemyRect(enemy->x, enemy->y, enemy->width, enemy->height);
Siriagus 17:d6a3b29cab31 222
Siriagus 17:d6a3b29cab31 223 if (hitTestRect(playerRect, enemyRect))
Siriagus 17:d6a3b29cab31 224 {
Siriagus 17:d6a3b29cab31 225 player.dead = true;
Siriagus 17:d6a3b29cab31 226 player.vx = 0;
Siriagus 17:d6a3b29cab31 227 player.vy = -4;
Siriagus 17:d6a3b29cab31 228 player.onGround = false;
Siriagus 17:d6a3b29cab31 229 --livesLeft;
Siriagus 17:d6a3b29cab31 230
Siriagus 17:d6a3b29cab31 231 sound->playNote(SFX::PLAYER_DEAD);
Siriagus 17:d6a3b29cab31 232 break;
Siriagus 17:d6a3b29cab31 233 }
Siriagus 17:d6a3b29cab31 234 }
Siriagus 17:d6a3b29cab31 235
Siriagus 17:d6a3b29cab31 236 if (player.dead)
Siriagus 17:d6a3b29cab31 237 {
Siriagus 17:d6a3b29cab31 238 // remove all enemies (let them fall off)
Siriagus 17:d6a3b29cab31 239 for (std::vector<Enemy*>::iterator it = enemies.begin(); it != enemies.end(); ++it)
Siriagus 17:d6a3b29cab31 240 {
Siriagus 17:d6a3b29cab31 241 Enemy *enemy = *it;
Siriagus 17:d6a3b29cab31 242 enemy->dead = true;
Siriagus 17:d6a3b29cab31 243 }
Siriagus 17:d6a3b29cab31 244
Siriagus 17:d6a3b29cab31 245 if (player.y >= HEIGHT && !enemies.size()) // when all enemies are removed
Siriagus 17:d6a3b29cab31 246 {
Siriagus 17:d6a3b29cab31 247 if (livesLeft)
Siriagus 17:d6a3b29cab31 248 {
Siriagus 17:d6a3b29cab31 249 respawnPlayer(); // Respawn player if it still have lives left
Siriagus 17:d6a3b29cab31 250 spawnEnemy(); // Spawn an enemy right away
Siriagus 17:d6a3b29cab31 251 }
Siriagus 17:d6a3b29cab31 252 else
Siriagus 17:d6a3b29cab31 253 {
Siriagus 17:d6a3b29cab31 254 if (Global::score > Global::highscores[2].score) // If new high score
Siriagus 17:d6a3b29cab31 255 requestStateChange(SUBMIT_HIGHSCORE);
Siriagus 17:d6a3b29cab31 256 else
Siriagus 17:d6a3b29cab31 257 requestStateChange(GAME_OVER);
Siriagus 17:d6a3b29cab31 258 }
Siriagus 17:d6a3b29cab31 259 }
Siriagus 8:9ac6a428fa26 260 }
Siriagus 7:678873947b29 261 }
Siriagus 7:678873947b29 262
Siriagus 7:678873947b29 263 void Game::render()
Siriagus 7:678873947b29 264 {
Siriagus 17:d6a3b29cab31 265
Siriagus 17:d6a3b29cab31 266 if (!player.dead)
Siriagus 17:d6a3b29cab31 267 {
Siriagus 17:d6a3b29cab31 268 // Draw map
Siriagus 17:d6a3b29cab31 269 drawImage(map);
Siriagus 17:d6a3b29cab31 270 }
Siriagus 17:d6a3b29cab31 271 else
Siriagus 17:d6a3b29cab31 272 {
Siriagus 17:d6a3b29cab31 273 // Print lives left
Siriagus 17:d6a3b29cab31 274 std::stringstream ss;
Siriagus 17:d6a3b29cab31 275 ss << "Lives left: " << livesLeft;
Siriagus 17:d6a3b29cab31 276 lcd->printString(ss.str().c_str(), 4, 2);
Siriagus 17:d6a3b29cab31 277 }
Siriagus 11:adb68da98262 278
Siriagus 12:8178fad5e660 279 // Draw player
Siriagus 17:d6a3b29cab31 280 drawImage(Image::Player, player.x, player.y, false, !player.facingLeft, player.dead);
Siriagus 17:d6a3b29cab31 281
Siriagus 13:7ab71c7c311b 282
Siriagus 13:7ab71c7c311b 283 // Draw enemies
Siriagus 16:caf613d5b85e 284 for (std::vector<Enemy*>::iterator it = enemies.begin(); it != enemies.end(); ++it)
Siriagus 16:caf613d5b85e 285 {
Siriagus 16:caf613d5b85e 286 Enemy *enemy = *it;
Siriagus 17:d6a3b29cab31 287
Siriagus 17:d6a3b29cab31 288 switch (enemy->type)
Siriagus 17:d6a3b29cab31 289 {
Siriagus 17:d6a3b29cab31 290 case Enemy::SIMPLE:
Siriagus 17:d6a3b29cab31 291 drawImage(Image::EnemySimple, enemy->x, enemy->y, false, !enemy->facingLeft, enemy->dead);
Siriagus 17:d6a3b29cab31 292 break;
Siriagus 17:d6a3b29cab31 293
Siriagus 17:d6a3b29cab31 294 case Enemy::JUMPER:
Siriagus 17:d6a3b29cab31 295 drawImage(Image::EnemyJumper, enemy->x, enemy->y, false, !enemy->facingLeft, enemy->dead);
Siriagus 17:d6a3b29cab31 296 break;
Siriagus 17:d6a3b29cab31 297
Siriagus 17:d6a3b29cab31 298 case Enemy::RUNNER:
Siriagus 17:d6a3b29cab31 299 drawImage(Image::EnemyRunner, enemy->x, enemy->y, false, !enemy->facingLeft, enemy->dead);
Siriagus 17:d6a3b29cab31 300 break;
Siriagus 17:d6a3b29cab31 301
Siriagus 17:d6a3b29cab31 302 default:
Siriagus 17:d6a3b29cab31 303 ; // should not happen, don't render
Siriagus 17:d6a3b29cab31 304 }
Siriagus 17:d6a3b29cab31 305
Siriagus 17:d6a3b29cab31 306
Siriagus 16:caf613d5b85e 307 }
Siriagus 16:caf613d5b85e 308
Siriagus 9:da608ae65df9 309 // Render bullets
Siriagus 8:9ac6a428fa26 310 for (std::vector<Point*>::iterator it = bullets.begin(); it != bullets.end(); ++it)
Siriagus 8:9ac6a428fa26 311 {
Siriagus 8:9ac6a428fa26 312 int x, y;
Siriagus 8:9ac6a428fa26 313 x = (*it)->x;
Siriagus 8:9ac6a428fa26 314 y = (*it)->y;
Siriagus 8:9ac6a428fa26 315
Siriagus 8:9ac6a428fa26 316 if (x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT) // Boundary check
Siriagus 8:9ac6a428fa26 317 lcd->setPixel(x,y);
Siriagus 8:9ac6a428fa26 318 }
Siriagus 15:d5eb13c4c1c6 319
Siriagus 15:d5eb13c4c1c6 320 // Draw pause
Siriagus 15:d5eb13c4c1c6 321 if (paused)
Siriagus 15:d5eb13c4c1c6 322 {
Siriagus 15:d5eb13c4c1c6 323 lcd->drawRect(24, 13, 40, 13, 0); // outline
Siriagus 15:d5eb13c4c1c6 324 lcd->drawRect(25, 14, 38, 11, 2); // white fill
Siriagus 15:d5eb13c4c1c6 325 lcd->printString("Paused", 27, 2); // text
Siriagus 15:d5eb13c4c1c6 326 }
Siriagus 17:d6a3b29cab31 327
Siriagus 17:d6a3b29cab31 328 // GUI
Siriagus 17:d6a3b29cab31 329 renderScore();
Siriagus 13:7ab71c7c311b 330 }
Siriagus 13:7ab71c7c311b 331
Siriagus 13:7ab71c7c311b 332 // Collision test between entites and map
Siriagus 13:7ab71c7c311b 333 void Game::moveWithCollisionTest(Entity* entity, const int map[HEIGHT][WIDTH])
Siriagus 13:7ab71c7c311b 334 {
Siriagus 13:7ab71c7c311b 335 int x = entity->x;
Siriagus 13:7ab71c7c311b 336 int y = entity->y;
Siriagus 13:7ab71c7c311b 337 int steps = abs(entity->vx); // how many units (pixels) the entity should move in said direction
Siriagus 13:7ab71c7c311b 338 bool collision; // true if colliding
Siriagus 13:7ab71c7c311b 339
Siriagus 13:7ab71c7c311b 340 // Check x-axis
Siriagus 13:7ab71c7c311b 341 if (entity->vx > 0) // moving right
Siriagus 13:7ab71c7c311b 342 {
Siriagus 13:7ab71c7c311b 343 int entityRight = x + entity->width - 1; // Need to check right border of entity, since it is moving right
Siriagus 13:7ab71c7c311b 344
Siriagus 13:7ab71c7c311b 345 while(steps--) // While it still have more movement left
Siriagus 13:7ab71c7c311b 346 {
Siriagus 13:7ab71c7c311b 347 collision = false;
Siriagus 16:caf613d5b85e 348
Siriagus 16:caf613d5b85e 349 // Wrapping
Siriagus 16:caf613d5b85e 350 if (entityRight+1 >= WIDTH)
Siriagus 16:caf613d5b85e 351 entityRight = -1;// wants entityRight = -1, so next check is entityRight 0*/
Siriagus 16:caf613d5b85e 352
Siriagus 13:7ab71c7c311b 353 for (int i = 0; i < entity->height; ++i) // Loop through all vertical points on the right hand side of the entity (y+i)
Siriagus 13:7ab71c7c311b 354 {
Siriagus 13:7ab71c7c311b 355 if (map[y+i][entityRight+1]) // If moving to the right leads to collision for given y+i
Siriagus 13:7ab71c7c311b 356 {
Siriagus 15:d5eb13c4c1c6 357 // Slope + allows player to climb to top of platform by going right if it hits close to top of wall.
Siriagus 15:d5eb13c4c1c6 358 if (!map[y+i-1][entityRight+1] && entity->onGround)
Siriagus 15:d5eb13c4c1c6 359 {
Siriagus 15:d5eb13c4c1c6 360 entity->vy = -1;
Siriagus 15:d5eb13c4c1c6 361 }
Siriagus 15:d5eb13c4c1c6 362 else
Siriagus 15:d5eb13c4c1c6 363 {
Siriagus 15:d5eb13c4c1c6 364 collision = true; // Then collision is true
Siriagus 15:d5eb13c4c1c6 365 break; // Skip the for loop, no need for further testing
Siriagus 15:d5eb13c4c1c6 366 }
Siriagus 15:d5eb13c4c1c6 367
Siriagus 13:7ab71c7c311b 368 }
Siriagus 13:7ab71c7c311b 369 }
Siriagus 13:7ab71c7c311b 370
Siriagus 13:7ab71c7c311b 371 if (collision) // If collision
Siriagus 13:7ab71c7c311b 372 break; // skip the while loop, entity can not move further, even though its velocity is higher
Siriagus 13:7ab71c7c311b 373 else
Siriagus 13:7ab71c7c311b 374 ++entityRight; // Move entity one px to the right
Siriagus 13:7ab71c7c311b 375 }
Siriagus 13:7ab71c7c311b 376
Siriagus 16:caf613d5b85e 377 // If wrap didn't work, make sure entity is on the correct side of the map
Siriagus 16:caf613d5b85e 378 if (entityRight < 0)
Siriagus 16:caf613d5b85e 379 entityRight = WIDTH-1;
Siriagus 16:caf613d5b85e 380
Siriagus 13:7ab71c7c311b 381 entity->x = entityRight - (entity->width - 1); // Update entity's position. Need to set upper-left pixel.
Siriagus 13:7ab71c7c311b 382 }
Siriagus 13:7ab71c7c311b 383 else // moving left
Siriagus 13:7ab71c7c311b 384 {
Siriagus 13:7ab71c7c311b 385 while(steps--) // While still movement left
Siriagus 13:7ab71c7c311b 386 {
Siriagus 13:7ab71c7c311b 387 collision = false;
Siriagus 13:7ab71c7c311b 388
Siriagus 16:caf613d5b85e 389 // Wrap around map
Siriagus 16:caf613d5b85e 390 if (x-1 < 0)
Siriagus 16:caf613d5b85e 391 x = WIDTH; // causes x-1 in the next check to be WIDTH - 1
Siriagus 13:7ab71c7c311b 392
Siriagus 16:caf613d5b85e 393 // Check for all y-positions
Siriagus 16:caf613d5b85e 394 for (int i = 0; i < entity->height; ++i)
Siriagus 13:7ab71c7c311b 395 {
Siriagus 16:caf613d5b85e 396
Siriagus 13:7ab71c7c311b 397 if (map[y+i][x-1]) // If solid block
Siriagus 13:7ab71c7c311b 398 {
Siriagus 15:d5eb13c4c1c6 399 if (!map[y+i-1][x-1] && entity->onGround) // If slope or close to top of wall (=> can climb by going left).
Siriagus 15:d5eb13c4c1c6 400 {
Siriagus 15:d5eb13c4c1c6 401 entity->vy = -1;
Siriagus 15:d5eb13c4c1c6 402 }
Siriagus 15:d5eb13c4c1c6 403 else
Siriagus 15:d5eb13c4c1c6 404 {
Siriagus 15:d5eb13c4c1c6 405 collision = true;
Siriagus 15:d5eb13c4c1c6 406 break; // Collision detected, no further testing required
Siriagus 15:d5eb13c4c1c6 407 }
Siriagus 13:7ab71c7c311b 408 }
Siriagus 13:7ab71c7c311b 409 }
Siriagus 13:7ab71c7c311b 410
Siriagus 13:7ab71c7c311b 411 if (collision)
Siriagus 13:7ab71c7c311b 412 break;
Siriagus 13:7ab71c7c311b 413 else
Siriagus 13:7ab71c7c311b 414 --x; // Move to the left if no collision is detected
Siriagus 13:7ab71c7c311b 415 }
Siriagus 13:7ab71c7c311b 416
Siriagus 16:caf613d5b85e 417 x %= WIDTH; // In case wrapping caused entity to crash with wall on other side, x should be 0 instead of WIDTH (invalid).
Siriagus 16:caf613d5b85e 418
Siriagus 16:caf613d5b85e 419 entity->x = x; // update position
Siriagus 13:7ab71c7c311b 420 }
Siriagus 13:7ab71c7c311b 421
Siriagus 13:7ab71c7c311b 422 // Check collision with map in y-direction - works the same way as the x-axis, except for other axis
Siriagus 13:7ab71c7c311b 423 x = entity->x;
Siriagus 13:7ab71c7c311b 424 y = entity->y;
Siriagus 13:7ab71c7c311b 425 steps = abs(entity->vy);
Siriagus 13:7ab71c7c311b 426
Siriagus 13:7ab71c7c311b 427 if (entity->vy > 0) // downwards
Siriagus 13:7ab71c7c311b 428 {
Siriagus 13:7ab71c7c311b 429 int entityBottom = y + entity->height - 1; // Need to check if bottom part collides
Siriagus 13:7ab71c7c311b 430 while(steps--) // Still movement left
Siriagus 13:7ab71c7c311b 431 {
Siriagus 13:7ab71c7c311b 432 collision = false;
Siriagus 16:caf613d5b85e 433
Siriagus 13:7ab71c7c311b 434 for (int i = 0; i < entity->width; ++i) // Loop through all x-position on lower part of entity
Siriagus 16:caf613d5b85e 435 {
Siriagus 16:caf613d5b85e 436 if (map[(entityBottom+1) % HEIGHT][x+i]) // If moving the entity one step down for a given (x+i)-position gives a collision
Siriagus 13:7ab71c7c311b 437 {
Siriagus 13:7ab71c7c311b 438 collision = true;
Siriagus 13:7ab71c7c311b 439 break; // No further testing required
Siriagus 13:7ab71c7c311b 440 }
Siriagus 13:7ab71c7c311b 441 }
Siriagus 13:7ab71c7c311b 442
Siriagus 13:7ab71c7c311b 443 if (collision) // If collision
Siriagus 13:7ab71c7c311b 444 {
Siriagus 13:7ab71c7c311b 445 entity->vy = 0; // Set vertical velocity to 0 (playe
Siriagus 13:7ab71c7c311b 446 entity->onGround = true; // entity has hit ground
Siriagus 13:7ab71c7c311b 447 break; // Skip the while loop as the entity can not move further downwards
Siriagus 13:7ab71c7c311b 448 }
Siriagus 13:7ab71c7c311b 449 else // Can safely move entity without collision
Siriagus 15:d5eb13c4c1c6 450 {
Siriagus 13:7ab71c7c311b 451 ++entityBottom; // Move entity one step down
Siriagus 15:d5eb13c4c1c6 452 entity->onGround = false;
Siriagus 15:d5eb13c4c1c6 453 }
Siriagus 13:7ab71c7c311b 454 }
Siriagus 13:7ab71c7c311b 455
Siriagus 16:caf613d5b85e 456 // Wrapping
Siriagus 16:caf613d5b85e 457 y = (entityBottom - (entity->height - 1));
Siriagus 16:caf613d5b85e 458 if (y >= HEIGHT) // if completely outside map
Siriagus 16:caf613d5b85e 459 y = -entity->height; // wrap to top of map
Siriagus 16:caf613d5b85e 460
Siriagus 16:caf613d5b85e 461 entity->y = y; // (entityBottom - (entity->height - 1)); // Update position when done moving, remember that entity.y refers to upper part of the entity
Siriagus 13:7ab71c7c311b 462 }
Siriagus 13:7ab71c7c311b 463 else // moving up, check collision from top
Siriagus 13:7ab71c7c311b 464 {
Siriagus 13:7ab71c7c311b 465 while(steps--) // Still movement left
Siriagus 13:7ab71c7c311b 466 {
Siriagus 13:7ab71c7c311b 467 collision = false;
Siriagus 16:caf613d5b85e 468
Siriagus 13:7ab71c7c311b 469 for (int i = 0; i < entity->width; ++i) // Check for all x-positions
Siriagus 13:7ab71c7c311b 470 {
Siriagus 16:caf613d5b85e 471 int y1 = ((y-1) + HEIGHT) % HEIGHT; // In case negative, because of wrapping
Siriagus 16:caf613d5b85e 472
Siriagus 16:caf613d5b85e 473 if (map[y1][x+i]) // If moving upwards gives collision for a given x+i
Siriagus 13:7ab71c7c311b 474 {
Siriagus 13:7ab71c7c311b 475 collision = true; // Then we have a collision
Siriagus 13:7ab71c7c311b 476 break; // No further testing needed, skip for loop
Siriagus 13:7ab71c7c311b 477 }
Siriagus 13:7ab71c7c311b 478 }
Siriagus 13:7ab71c7c311b 479
Siriagus 13:7ab71c7c311b 480 if (collision) // If collision was detected
Siriagus 13:7ab71c7c311b 481 {
Siriagus 13:7ab71c7c311b 482 entity->vy = 0; // Set vertical velocity to zero
Siriagus 13:7ab71c7c311b 483 break; // Skip while loop as entity can not move further up
Siriagus 13:7ab71c7c311b 484 }
Siriagus 13:7ab71c7c311b 485 else // If safe to move for all x-values
Siriagus 13:7ab71c7c311b 486 --y; // Move entity one step up
Siriagus 13:7ab71c7c311b 487 }
Siriagus 13:7ab71c7c311b 488
Siriagus 16:caf613d5b85e 489 // Wrapping
Siriagus 16:caf613d5b85e 490 if (y + (entity->height - 1) < 0) // completely outside map (bottom of entity over top of map)
Siriagus 16:caf613d5b85e 491 y = HEIGHT-1 - entity->height - 1; // Sets the altitude.
Siriagus 16:caf613d5b85e 492
Siriagus 13:7ab71c7c311b 493 entity->y = y; // Update vertical position of entity
Siriagus 13:7ab71c7c311b 494 }
Siriagus 15:d5eb13c4c1c6 495 }
Siriagus 15:d5eb13c4c1c6 496
Siriagus 15:d5eb13c4c1c6 497 bool Game::hitTestRect(Rectangle r1, Rectangle r2)
Siriagus 15:d5eb13c4c1c6 498 {
Siriagus 15:d5eb13c4c1c6 499 return ((r1.x + r1.width > r2.x) // r1's right edge to the right of r2's left edge
Siriagus 15:d5eb13c4c1c6 500 && (r1.x < r2.x + r2.width) // r1's left edge to the left of r2's right edge
Siriagus 15:d5eb13c4c1c6 501 && (r1.y + r2.height > r2.y) // r1's bottom lower than r2's top
Siriagus 15:d5eb13c4c1c6 502 && (r1.y < r2.y + r2.height)); // r1's top higher than r2's bottom
Siriagus 15:d5eb13c4c1c6 503
Siriagus 15:d5eb13c4c1c6 504 // Note: Right border: r1.x + r1.width - 1, but we don't need to subtract 1 as we use > instead of >=
Siriagus 15:d5eb13c4c1c6 505 }
Siriagus 15:d5eb13c4c1c6 506
Siriagus 15:d5eb13c4c1c6 507 bool Game::bulletHitMap(Rectangle &bulletColRect, const int map[HEIGHT][WIDTH])
Siriagus 15:d5eb13c4c1c6 508 {
Siriagus 15:d5eb13c4c1c6 509 for (int j = 0; j < bulletColRect.width; ++j)
Siriagus 15:d5eb13c4c1c6 510 {
Siriagus 15:d5eb13c4c1c6 511 if (map[bulletColRect.y][bulletColRect.x + j])
Siriagus 15:d5eb13c4c1c6 512 return true;
Siriagus 15:d5eb13c4c1c6 513 }
Siriagus 15:d5eb13c4c1c6 514
Siriagus 15:d5eb13c4c1c6 515 return false;
Siriagus 16:caf613d5b85e 516 }
Siriagus 16:caf613d5b85e 517
Siriagus 16:caf613d5b85e 518 void Game::moveEnemies()
Siriagus 16:caf613d5b85e 519 {
Siriagus 17:d6a3b29cab31 520 for (std::vector<Enemy*>::iterator it = enemies.begin(); it != enemies.end(); )
Siriagus 16:caf613d5b85e 521 {
Siriagus 16:caf613d5b85e 522 Enemy *enemy = *it;
Siriagus 16:caf613d5b85e 523
Siriagus 16:caf613d5b85e 524 // Gravity
Siriagus 16:caf613d5b85e 525 enemy->vy += 1;
Siriagus 16:caf613d5b85e 526
Siriagus 16:caf613d5b85e 527 if (!enemy->dead)
Siriagus 16:caf613d5b85e 528 {
Siriagus 17:d6a3b29cab31 529 // Random movement for enemies
Siriagus 17:d6a3b29cab31 530 if (enemy->onGround && (rand() % 100) < enemy->jumpRate)
Siriagus 17:d6a3b29cab31 531 {
Siriagus 17:d6a3b29cab31 532 // jump
Siriagus 17:d6a3b29cab31 533 enemy->vy = -3;
Siriagus 17:d6a3b29cab31 534 enemy->onGround = false;
Siriagus 17:d6a3b29cab31 535 }
Siriagus 17:d6a3b29cab31 536 else if ((rand() % 100) > 98) // 2% chance
Siriagus 17:d6a3b29cab31 537 {
Siriagus 17:d6a3b29cab31 538 // switch direction
Siriagus 17:d6a3b29cab31 539 enemy->vx *= -1;
Siriagus 17:d6a3b29cab31 540 enemy->facingLeft = (enemy->vx < 0);
Siriagus 17:d6a3b29cab31 541 }
Siriagus 17:d6a3b29cab31 542
Siriagus 16:caf613d5b85e 543 moveWithCollisionTest(enemy, map);
Siriagus 16:caf613d5b85e 544
Siriagus 16:caf613d5b85e 545 // Enemy AI
Siriagus 17:d6a3b29cab31 546 if (enemy->y >= 0)
Siriagus 16:caf613d5b85e 547 {
Siriagus 17:d6a3b29cab31 548 int nextRight = enemy->getRight() + 1; // Next position of right edge if enemy moves to the right
Siriagus 17:d6a3b29cab31 549 nextRight %= WIDTH; // wrapping
Siriagus 17:d6a3b29cab31 550 for (int i = 0; i < enemy->height; ++i) // Check for all heighs
Siriagus 16:caf613d5b85e 551 {
Siriagus 17:d6a3b29cab31 552 // Check if crashing if moving right or left. Bounds should already be limited by moveWithCollisionTest!
Siriagus 17:d6a3b29cab31 553 if (map[enemy->y + i][nextRight] || map[enemy->y + i][enemy->x - 1])
Siriagus 17:d6a3b29cab31 554 {
Siriagus 17:d6a3b29cab31 555 enemy->vx *= -1; // move in opposite direction
Siriagus 17:d6a3b29cab31 556 enemy->facingLeft = !enemy->facingLeft; // toggle direction
Siriagus 17:d6a3b29cab31 557 break; // no further testing required
Siriagus 17:d6a3b29cab31 558 }
Siriagus 16:caf613d5b85e 559 }
Siriagus 16:caf613d5b85e 560 }
Siriagus 17:d6a3b29cab31 561
Siriagus 17:d6a3b29cab31 562 ++it; // go to next enemy
Siriagus 16:caf613d5b85e 563 }
Siriagus 17:d6a3b29cab31 564 else // if enemy is dead
Siriagus 16:caf613d5b85e 565 {
Siriagus 16:caf613d5b85e 566 enemy->y += enemy->vy;
Siriagus 16:caf613d5b85e 567 enemy->x += enemy->vx;
Siriagus 17:d6a3b29cab31 568
Siriagus 17:d6a3b29cab31 569 if (enemy->y >= HEIGHT) // if outside map (and dead)
Siriagus 17:d6a3b29cab31 570 {
Siriagus 17:d6a3b29cab31 571 delete enemy;
Siriagus 17:d6a3b29cab31 572 it = enemies.erase(it); // remove and go to next enemy
Siriagus 17:d6a3b29cab31 573 }
Siriagus 17:d6a3b29cab31 574 else
Siriagus 17:d6a3b29cab31 575 ++it; // go to next enemy
Siriagus 16:caf613d5b85e 576 }
Siriagus 16:caf613d5b85e 577 }
Siriagus 17:d6a3b29cab31 578 }
Siriagus 17:d6a3b29cab31 579
Siriagus 17:d6a3b29cab31 580 void Game::renderScore()
Siriagus 17:d6a3b29cab31 581 {
Siriagus 17:d6a3b29cab31 582 int s = (Global::score < 100000) ? Global::score : 99999; // Max possible score is 99999.
Siriagus 17:d6a3b29cab31 583
Siriagus 17:d6a3b29cab31 584 // Read digits
Siriagus 17:d6a3b29cab31 585 int digits[5]; // max five
Siriagus 17:d6a3b29cab31 586 // Count the number of digits in the score
Siriagus 17:d6a3b29cab31 587 int numDigits = 0;
Siriagus 17:d6a3b29cab31 588 do
Siriagus 17:d6a3b29cab31 589 {
Siriagus 17:d6a3b29cab31 590 digits[numDigits] = s % 10;
Siriagus 17:d6a3b29cab31 591 s /= 10;
Siriagus 17:d6a3b29cab31 592 ++numDigits;
Siriagus 17:d6a3b29cab31 593 } while (s != 0 && numDigits < 5);
Siriagus 17:d6a3b29cab31 594
Siriagus 17:d6a3b29cab31 595
Siriagus 17:d6a3b29cab31 596 // Draw score
Siriagus 17:d6a3b29cab31 597 int xStart = 79;
Siriagus 17:d6a3b29cab31 598 int xStep = 4; // width + 1
Siriagus 17:d6a3b29cab31 599 int y = 2;
Siriagus 17:d6a3b29cab31 600 int x;
Siriagus 17:d6a3b29cab31 601
Siriagus 17:d6a3b29cab31 602 for (int i = 0; i < numDigits; ++i)
Siriagus 17:d6a3b29cab31 603 {
Siriagus 17:d6a3b29cab31 604 x = xStart - i * xStep;
Siriagus 17:d6a3b29cab31 605
Siriagus 17:d6a3b29cab31 606 switch (digits[i])
Siriagus 17:d6a3b29cab31 607 {
Siriagus 17:d6a3b29cab31 608 case 1:
Siriagus 17:d6a3b29cab31 609 drawImage(Number::One, x, y);
Siriagus 17:d6a3b29cab31 610 break;
Siriagus 17:d6a3b29cab31 611
Siriagus 17:d6a3b29cab31 612 case 2:
Siriagus 17:d6a3b29cab31 613 drawImage(Number::Two, x, y);
Siriagus 17:d6a3b29cab31 614 break;
Siriagus 17:d6a3b29cab31 615
Siriagus 17:d6a3b29cab31 616 case 3:
Siriagus 17:d6a3b29cab31 617 drawImage(Number::Three, x, y);
Siriagus 17:d6a3b29cab31 618 break;
Siriagus 17:d6a3b29cab31 619
Siriagus 17:d6a3b29cab31 620 case 4:
Siriagus 17:d6a3b29cab31 621 drawImage(Number::Four, x, y);
Siriagus 17:d6a3b29cab31 622 break;
Siriagus 17:d6a3b29cab31 623
Siriagus 17:d6a3b29cab31 624 case 5:
Siriagus 17:d6a3b29cab31 625 drawImage(Number::Five, x, y);
Siriagus 17:d6a3b29cab31 626 break;
Siriagus 17:d6a3b29cab31 627
Siriagus 17:d6a3b29cab31 628 case 6:
Siriagus 17:d6a3b29cab31 629 drawImage(Number::Six, x, y);
Siriagus 17:d6a3b29cab31 630 break;
Siriagus 17:d6a3b29cab31 631
Siriagus 17:d6a3b29cab31 632 case 7:
Siriagus 17:d6a3b29cab31 633 drawImage(Number::Seven, x, y);
Siriagus 17:d6a3b29cab31 634 break;
Siriagus 17:d6a3b29cab31 635
Siriagus 17:d6a3b29cab31 636 case 8:
Siriagus 17:d6a3b29cab31 637 drawImage(Number::Eight, x, y);
Siriagus 17:d6a3b29cab31 638 break;
Siriagus 17:d6a3b29cab31 639
Siriagus 17:d6a3b29cab31 640 case 9:
Siriagus 17:d6a3b29cab31 641 drawImage(Number::Nine, x, y);
Siriagus 17:d6a3b29cab31 642 break;
Siriagus 17:d6a3b29cab31 643
Siriagus 17:d6a3b29cab31 644 case 0:
Siriagus 17:d6a3b29cab31 645 default:
Siriagus 17:d6a3b29cab31 646 drawImage(Number::Zero, x, y);
Siriagus 17:d6a3b29cab31 647 break;
Siriagus 17:d6a3b29cab31 648 }
Siriagus 17:d6a3b29cab31 649
Siriagus 17:d6a3b29cab31 650 }
Siriagus 17:d6a3b29cab31 651 }
Siriagus 17:d6a3b29cab31 652
Siriagus 17:d6a3b29cab31 653 void Game::respawnPlayer()
Siriagus 17:d6a3b29cab31 654 {
Siriagus 17:d6a3b29cab31 655 player.x = 74;
Siriagus 17:d6a3b29cab31 656 player.y = 31;
Siriagus 17:d6a3b29cab31 657 player.vx = player.vy = 0;
Siriagus 17:d6a3b29cab31 658 player.facingLeft = true;
Siriagus 17:d6a3b29cab31 659 player.dead = false;
Siriagus 7:678873947b29 660 }