A complex 2D-dungeon game on LPC1768 in SWJTU-Leeds Joint School XJEL2645 project. Referenced from the framework contributed by https://os.mbed.com/users/Siriagus/code/SimplePlatformGame/

Dependencies:   mbed N5110 ShiftReg PinDetect

Committer:
Siriagus
Date:
Sun May 10 13:14:33 2015 +0000
Revision:
16:caf613d5b85e
Parent:
15:d5eb13c4c1c6
Child:
17:d6a3b29cab31
Added wrapping (when entity goes outside the map, it enters on the other side).

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Siriagus 7:678873947b29 1 #include "Game.h"
Siriagus 7:678873947b29 2
Siriagus 8:9ac6a428fa26 3 Serial pc(USBTX, USBRX); // TO DELETE - DEBUGGING ONLY
Siriagus 8:9ac6a428fa26 4
Siriagus 8:9ac6a428fa26 5 void Game::init()
Siriagus 16:caf613d5b85e 6 {
Siriagus 15:d5eb13c4c1c6 7 paused = false;
Siriagus 15:d5eb13c4c1c6 8
Siriagus 12:8178fad5e660 9 // Set initial values for the player
Siriagus 13:7ab71c7c311b 10 player.x = 40; // start x
Siriagus 13:7ab71c7c311b 11 player.y = 5; // start y
Siriagus 13:7ab71c7c311b 12 player.width = player.height = 5; // important that this is correct, see size of Image::Player in Resources.h
Siriagus 12:8178fad5e660 13 player.onGround = false;
Siriagus 16:caf613d5b85e 14 }
Siriagus 16:caf613d5b85e 15
Siriagus 16:caf613d5b85e 16 void Game::spawnEnemy()
Siriagus 16:caf613d5b85e 17 {
Siriagus 16:caf613d5b85e 18 Enemy *enemy = new Enemy(75, 3, 5, 5, Enemy::SIMPLE);
Siriagus 16:caf613d5b85e 19 enemy->vx = -1;
Siriagus 15:d5eb13c4c1c6 20 enemy->facingLeft = true;
Siriagus 16:caf613d5b85e 21 enemies.push_back(enemy);
Siriagus 8:9ac6a428fa26 22 }
Siriagus 8:9ac6a428fa26 23
Siriagus 8:9ac6a428fa26 24 // Functions
Siriagus 7:678873947b29 25 void Game::update(float dt)
Siriagus 16:caf613d5b85e 26 {
Siriagus 15:d5eb13c4c1c6 27 // Pause button input
Siriagus 15:d5eb13c4c1c6 28 if (input->read(Input::ButtonC))
Siriagus 15:d5eb13c4c1c6 29 {
Siriagus 15:d5eb13c4c1c6 30 if (releasedBtnC)
Siriagus 15:d5eb13c4c1c6 31 {
Siriagus 15:d5eb13c4c1c6 32 paused = !paused;
Siriagus 15:d5eb13c4c1c6 33 releasedBtnC = false;
Siriagus 15:d5eb13c4c1c6 34 }
Siriagus 15:d5eb13c4c1c6 35 }
Siriagus 15:d5eb13c4c1c6 36 else
Siriagus 15:d5eb13c4c1c6 37 releasedBtnC = true;
Siriagus 15:d5eb13c4c1c6 38
Siriagus 15:d5eb13c4c1c6 39 // Skip the rest if paused
Siriagus 15:d5eb13c4c1c6 40 if (paused) return;
Siriagus 15:d5eb13c4c1c6 41
Siriagus 15:d5eb13c4c1c6 42
Siriagus 16:caf613d5b85e 43 if ((rand() % 100) > 93)
Siriagus 16:caf613d5b85e 44 spawnEnemy();
Siriagus 16:caf613d5b85e 45
Siriagus 8:9ac6a428fa26 46 // Handle input, should be its own function
Siriagus 8:9ac6a428fa26 47 switch(input->joystick->getDirection())
Siriagus 8:9ac6a428fa26 48 {
Siriagus 8:9ac6a428fa26 49 case LEFT:
Siriagus 8:9ac6a428fa26 50 case UP_LEFT:
Siriagus 8:9ac6a428fa26 51 case DOWN_LEFT:
Siriagus 8:9ac6a428fa26 52 player.vx = -2;
Siriagus 11:adb68da98262 53 player.facingLeft = true;
Siriagus 8:9ac6a428fa26 54 break;
Siriagus 8:9ac6a428fa26 55
Siriagus 8:9ac6a428fa26 56 case RIGHT:
Siriagus 8:9ac6a428fa26 57 case UP_RIGHT:
Siriagus 8:9ac6a428fa26 58 case DOWN_RIGHT:
Siriagus 8:9ac6a428fa26 59 player.vx = 2;
Siriagus 11:adb68da98262 60 player.facingLeft = false;
Siriagus 8:9ac6a428fa26 61 break;
Siriagus 8:9ac6a428fa26 62
Siriagus 8:9ac6a428fa26 63 case CENTER:
Siriagus 8:9ac6a428fa26 64 player.vx = 0;
Siriagus 8:9ac6a428fa26 65 break;
Siriagus 8:9ac6a428fa26 66 }
Siriagus 7:678873947b29 67
Siriagus 16:caf613d5b85e 68
Siriagus 16:caf613d5b85e 69 // MOVE: Random enemies
Siriagus 13:7ab71c7c311b 70
Siriagus 13:7ab71c7c311b 71 // Gravity
Siriagus 11:adb68da98262 72 player.vy += 1;
Siriagus 8:9ac6a428fa26 73
Siriagus 11:adb68da98262 74 // Check if player is trying to jump. Player can only jump if it's on the ground
Siriagus 12:8178fad5e660 75 if (input->read(Input::ButtonA) && player.onGround)
Siriagus 8:9ac6a428fa26 76 {
Siriagus 8:9ac6a428fa26 77 player.vy = -4;
Siriagus 12:8178fad5e660 78 player.onGround = false;
Siriagus 8:9ac6a428fa26 79 }
Siriagus 8:9ac6a428fa26 80
Siriagus 11:adb68da98262 81 // Terminal velocity 3 px/update
Siriagus 14:b4fed570abaf 82 if (player.vy > TERMINAL_VELOCITY) player.vy = TERMINAL_VELOCITY;
Siriagus 8:9ac6a428fa26 83
Siriagus 13:7ab71c7c311b 84 moveWithCollisionTest(&player, map);
Siriagus 16:caf613d5b85e 85 moveEnemies();
Siriagus 11:adb68da98262 86
Siriagus 16:caf613d5b85e 87
Siriagus 16:caf613d5b85e 88 // else if (enemy->y >= HEIGHT) ; // TODO : delete enemy
Siriagus 8:9ac6a428fa26 89
Siriagus 11:adb68da98262 90 // Check if bullet should be fired
Siriagus 9:da608ae65df9 91 if (input->read(Input::ButtonB) && releasedBtnB)
Siriagus 8:9ac6a428fa26 92 {
Siriagus 11:adb68da98262 93 // Create a new bullet and give it initial values
Siriagus 8:9ac6a428fa26 94 Point* bullet = new Point;
Siriagus 15:d5eb13c4c1c6 95 bullet->x = (int)(player.x + (player.width / 2)); //(player.facingLeft) ? (player.x-1) : (player.x + player.width);
Siriagus 8:9ac6a428fa26 96 bullet->y = player.y + 2;
Siriagus 11:adb68da98262 97 bullet->vx = (player.facingLeft) ? -4 : 4;
Siriagus 9:da608ae65df9 98 bullet->vy = 0;
Siriagus 8:9ac6a428fa26 99
Siriagus 8:9ac6a428fa26 100 bullets.push_back(bullet);
Siriagus 9:da608ae65df9 101 releasedBtnB = false;
Siriagus 8:9ac6a428fa26 102 }
Siriagus 9:da608ae65df9 103 else if (!input->read(Input::ButtonB))
Siriagus 9:da608ae65df9 104 releasedBtnB = true;
Siriagus 8:9ac6a428fa26 105
Siriagus 15:d5eb13c4c1c6 106 // Loop through bullets and move them + collision test
Siriagus 9:da608ae65df9 107 for (std::vector<Point*>::iterator it = bullets.begin(); it != bullets.end();)
Siriagus 8:9ac6a428fa26 108 {
Siriagus 15:d5eb13c4c1c6 109 Point* bullet = *it;
Siriagus 15:d5eb13c4c1c6 110
Siriagus 15:d5eb13c4c1c6 111 int x0; // left border of collision rect
Siriagus 15:d5eb13c4c1c6 112 int x1; // right border of collision rect
Siriagus 15:d5eb13c4c1c6 113
Siriagus 15:d5eb13c4c1c6 114 int oldX = bullet->x;
Siriagus 15:d5eb13c4c1c6 115 int newX = bullet->x + bullet->vx;
Siriagus 15:d5eb13c4c1c6 116
Siriagus 15:d5eb13c4c1c6 117 x0 = min(oldX, newX);
Siriagus 15:d5eb13c4c1c6 118 x1 = max(oldX, newX);
Siriagus 15:d5eb13c4c1c6 119
Siriagus 15:d5eb13c4c1c6 120 // Collision rect for bullet in this time step
Siriagus 15:d5eb13c4c1c6 121 Rectangle bulletColRect(x0, bullet->y, (x1-x0)+1, 1);
Siriagus 9:da608ae65df9 122
Siriagus 15:d5eb13c4c1c6 123 bool col = false;
Siriagus 15:d5eb13c4c1c6 124 // Delete if outside screen
Siriagus 15:d5eb13c4c1c6 125 if (newX < 0 || newX > WIDTH || bulletHitMap(bulletColRect, map)) // if outside screen
Siriagus 15:d5eb13c4c1c6 126 {
Siriagus 15:d5eb13c4c1c6 127 col = true;
Siriagus 15:d5eb13c4c1c6 128 }
Siriagus 15:d5eb13c4c1c6 129 else
Siriagus 9:da608ae65df9 130 {
Siriagus 15:d5eb13c4c1c6 131 // loop through all enemies
Siriagus 15:d5eb13c4c1c6 132 //bullet // point
Siriagus 15:d5eb13c4c1c6 133 //enemy // entity
Siriagus 16:caf613d5b85e 134 for (std::vector<Enemy*>::iterator it = enemies.begin(); it != enemies.end(); ++it)
Siriagus 15:d5eb13c4c1c6 135 {
Siriagus 16:caf613d5b85e 136 Enemy *enemy = *it;
Siriagus 15:d5eb13c4c1c6 137
Siriagus 16:caf613d5b85e 138 if (!enemy->dead && bullet->x >= enemy->x && bullet->x <= enemy->getRight() && bullet->y >= enemy->y && bullet->y <= enemy->getBottom())
Siriagus 16:caf613d5b85e 139 {
Siriagus 16:caf613d5b85e 140 col = true;
Siriagus 16:caf613d5b85e 141 // break; // todo: make for loop - iterate through all enemies
Siriagus 16:caf613d5b85e 142 enemy->vx = bullet->vx / 2; // sends the dead enemy in the same direction as the incoming bullet
Siriagus 16:caf613d5b85e 143 enemy->vy = -3; // sends the dead enemy upwards in the air, because of impact
Siriagus 16:caf613d5b85e 144
Siriagus 16:caf613d5b85e 145 enemy->dead = true;
Siriagus 16:caf613d5b85e 146 // remove enemy - todo: make vector
Siriagus 16:caf613d5b85e 147 }
Siriagus 15:d5eb13c4c1c6 148 }
Siriagus 15:d5eb13c4c1c6 149 }
Siriagus 15:d5eb13c4c1c6 150
Siriagus 15:d5eb13c4c1c6 151 if (!col)
Siriagus 15:d5eb13c4c1c6 152 {
Siriagus 15:d5eb13c4c1c6 153 ++it; // go to next element
Siriagus 15:d5eb13c4c1c6 154 bullet->x += bullet->vx; // update position
Siriagus 15:d5eb13c4c1c6 155 }
Siriagus 15:d5eb13c4c1c6 156 else
Siriagus 15:d5eb13c4c1c6 157 {
Siriagus 15:d5eb13c4c1c6 158 delete bullet;
Siriagus 9:da608ae65df9 159 it = bullets.erase(it); // go to next element
Siriagus 9:da608ae65df9 160 }
Siriagus 8:9ac6a428fa26 161
Siriagus 8:9ac6a428fa26 162 // TODO: Check for collisions
Siriagus 8:9ac6a428fa26 163 // TODO: Go both ways
Siriagus 8:9ac6a428fa26 164 }
Siriagus 7:678873947b29 165 }
Siriagus 7:678873947b29 166
Siriagus 7:678873947b29 167 void Game::render()
Siriagus 7:678873947b29 168 {
Siriagus 11:adb68da98262 169 // Draw map
Siriagus 11:adb68da98262 170 drawImage(map);
Siriagus 11:adb68da98262 171
Siriagus 12:8178fad5e660 172 // Draw player
Siriagus 13:7ab71c7c311b 173 drawImage(Image::Player, player.x, player.y, false, !player.facingLeft);
Siriagus 13:7ab71c7c311b 174
Siriagus 13:7ab71c7c311b 175 // Draw enemies
Siriagus 16:caf613d5b85e 176 for (std::vector<Enemy*>::iterator it = enemies.begin(); it != enemies.end(); ++it)
Siriagus 16:caf613d5b85e 177 {
Siriagus 16:caf613d5b85e 178 Enemy *enemy = *it;
Siriagus 16:caf613d5b85e 179 drawImage(Image::EnemySimple, enemy->x, enemy->y, false, !enemy->facingLeft, enemy->dead);
Siriagus 16:caf613d5b85e 180 }
Siriagus 16:caf613d5b85e 181
Siriagus 9:da608ae65df9 182 // Render bullets
Siriagus 8:9ac6a428fa26 183 for (std::vector<Point*>::iterator it = bullets.begin(); it != bullets.end(); ++it)
Siriagus 8:9ac6a428fa26 184 {
Siriagus 8:9ac6a428fa26 185 int x, y;
Siriagus 8:9ac6a428fa26 186 x = (*it)->x;
Siriagus 8:9ac6a428fa26 187 y = (*it)->y;
Siriagus 8:9ac6a428fa26 188
Siriagus 8:9ac6a428fa26 189 if (x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT) // Boundary check
Siriagus 8:9ac6a428fa26 190 lcd->setPixel(x,y);
Siriagus 8:9ac6a428fa26 191 }
Siriagus 15:d5eb13c4c1c6 192
Siriagus 15:d5eb13c4c1c6 193 // Draw pause
Siriagus 15:d5eb13c4c1c6 194 if (paused)
Siriagus 15:d5eb13c4c1c6 195 {
Siriagus 15:d5eb13c4c1c6 196 lcd->drawRect(24, 13, 40, 13, 0); // outline
Siriagus 15:d5eb13c4c1c6 197 lcd->drawRect(25, 14, 38, 11, 2); // white fill
Siriagus 15:d5eb13c4c1c6 198 lcd->printString("Paused", 27, 2); // text
Siriagus 15:d5eb13c4c1c6 199 }
Siriagus 13:7ab71c7c311b 200 }
Siriagus 13:7ab71c7c311b 201
Siriagus 13:7ab71c7c311b 202 // Collision test between entites and map
Siriagus 13:7ab71c7c311b 203 void Game::moveWithCollisionTest(Entity* entity, const int map[HEIGHT][WIDTH])
Siriagus 13:7ab71c7c311b 204 {
Siriagus 13:7ab71c7c311b 205 int x = entity->x;
Siriagus 13:7ab71c7c311b 206 int y = entity->y;
Siriagus 13:7ab71c7c311b 207 int steps = abs(entity->vx); // how many units (pixels) the entity should move in said direction
Siriagus 13:7ab71c7c311b 208 bool collision; // true if colliding
Siriagus 13:7ab71c7c311b 209
Siriagus 13:7ab71c7c311b 210 // Check x-axis
Siriagus 13:7ab71c7c311b 211 if (entity->vx > 0) // moving right
Siriagus 13:7ab71c7c311b 212 {
Siriagus 13:7ab71c7c311b 213 int entityRight = x + entity->width - 1; // Need to check right border of entity, since it is moving right
Siriagus 13:7ab71c7c311b 214
Siriagus 13:7ab71c7c311b 215 while(steps--) // While it still have more movement left
Siriagus 13:7ab71c7c311b 216 {
Siriagus 13:7ab71c7c311b 217 collision = false;
Siriagus 16:caf613d5b85e 218
Siriagus 16:caf613d5b85e 219 // Wrapping
Siriagus 16:caf613d5b85e 220 if (entityRight+1 >= WIDTH)
Siriagus 16:caf613d5b85e 221 entityRight = -1;// wants entityRight = -1, so next check is entityRight 0*/
Siriagus 16:caf613d5b85e 222
Siriagus 13:7ab71c7c311b 223 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 224 {
Siriagus 13:7ab71c7c311b 225 if (map[y+i][entityRight+1]) // If moving to the right leads to collision for given y+i
Siriagus 13:7ab71c7c311b 226 {
Siriagus 15:d5eb13c4c1c6 227 // Slope + allows player to climb to top of platform by going right if it hits close to top of wall.
Siriagus 15:d5eb13c4c1c6 228 if (!map[y+i-1][entityRight+1] && entity->onGround)
Siriagus 15:d5eb13c4c1c6 229 {
Siriagus 15:d5eb13c4c1c6 230 entity->vy = -1;
Siriagus 15:d5eb13c4c1c6 231 }
Siriagus 15:d5eb13c4c1c6 232 else
Siriagus 15:d5eb13c4c1c6 233 {
Siriagus 15:d5eb13c4c1c6 234 collision = true; // Then collision is true
Siriagus 15:d5eb13c4c1c6 235 break; // Skip the for loop, no need for further testing
Siriagus 15:d5eb13c4c1c6 236 }
Siriagus 15:d5eb13c4c1c6 237
Siriagus 13:7ab71c7c311b 238 }
Siriagus 13:7ab71c7c311b 239 }
Siriagus 13:7ab71c7c311b 240
Siriagus 13:7ab71c7c311b 241 if (collision) // If collision
Siriagus 13:7ab71c7c311b 242 break; // skip the while loop, entity can not move further, even though its velocity is higher
Siriagus 13:7ab71c7c311b 243 else
Siriagus 13:7ab71c7c311b 244 ++entityRight; // Move entity one px to the right
Siriagus 13:7ab71c7c311b 245 }
Siriagus 13:7ab71c7c311b 246
Siriagus 16:caf613d5b85e 247 // If wrap didn't work, make sure entity is on the correct side of the map
Siriagus 16:caf613d5b85e 248 if (entityRight < 0)
Siriagus 16:caf613d5b85e 249 entityRight = WIDTH-1;
Siriagus 16:caf613d5b85e 250
Siriagus 13:7ab71c7c311b 251 entity->x = entityRight - (entity->width - 1); // Update entity's position. Need to set upper-left pixel.
Siriagus 13:7ab71c7c311b 252 }
Siriagus 13:7ab71c7c311b 253 else // moving left
Siriagus 13:7ab71c7c311b 254 {
Siriagus 13:7ab71c7c311b 255 while(steps--) // While still movement left
Siriagus 13:7ab71c7c311b 256 {
Siriagus 13:7ab71c7c311b 257 collision = false;
Siriagus 13:7ab71c7c311b 258
Siriagus 16:caf613d5b85e 259 // Wrap around map
Siriagus 16:caf613d5b85e 260 if (x-1 < 0)
Siriagus 16:caf613d5b85e 261 x = WIDTH; // causes x-1 in the next check to be WIDTH - 1
Siriagus 13:7ab71c7c311b 262
Siriagus 16:caf613d5b85e 263 // Check for all y-positions
Siriagus 16:caf613d5b85e 264 for (int i = 0; i < entity->height; ++i)
Siriagus 13:7ab71c7c311b 265 {
Siriagus 16:caf613d5b85e 266
Siriagus 13:7ab71c7c311b 267 if (map[y+i][x-1]) // If solid block
Siriagus 13:7ab71c7c311b 268 {
Siriagus 15:d5eb13c4c1c6 269 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 270 {
Siriagus 15:d5eb13c4c1c6 271 entity->vy = -1;
Siriagus 15:d5eb13c4c1c6 272 }
Siriagus 15:d5eb13c4c1c6 273 else
Siriagus 15:d5eb13c4c1c6 274 {
Siriagus 15:d5eb13c4c1c6 275 collision = true;
Siriagus 15:d5eb13c4c1c6 276 break; // Collision detected, no further testing required
Siriagus 15:d5eb13c4c1c6 277 }
Siriagus 13:7ab71c7c311b 278 }
Siriagus 13:7ab71c7c311b 279 }
Siriagus 13:7ab71c7c311b 280
Siriagus 13:7ab71c7c311b 281 if (collision)
Siriagus 13:7ab71c7c311b 282 break;
Siriagus 13:7ab71c7c311b 283 else
Siriagus 13:7ab71c7c311b 284 --x; // Move to the left if no collision is detected
Siriagus 13:7ab71c7c311b 285 }
Siriagus 13:7ab71c7c311b 286
Siriagus 16:caf613d5b85e 287 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 288
Siriagus 16:caf613d5b85e 289 entity->x = x; // update position
Siriagus 13:7ab71c7c311b 290 }
Siriagus 13:7ab71c7c311b 291
Siriagus 13:7ab71c7c311b 292 // Check collision with map in y-direction - works the same way as the x-axis, except for other axis
Siriagus 13:7ab71c7c311b 293 x = entity->x;
Siriagus 13:7ab71c7c311b 294 y = entity->y;
Siriagus 13:7ab71c7c311b 295 steps = abs(entity->vy);
Siriagus 13:7ab71c7c311b 296
Siriagus 13:7ab71c7c311b 297 if (entity->vy > 0) // downwards
Siriagus 13:7ab71c7c311b 298 {
Siriagus 13:7ab71c7c311b 299 int entityBottom = y + entity->height - 1; // Need to check if bottom part collides
Siriagus 13:7ab71c7c311b 300 while(steps--) // Still movement left
Siriagus 13:7ab71c7c311b 301 {
Siriagus 13:7ab71c7c311b 302 collision = false;
Siriagus 16:caf613d5b85e 303
Siriagus 13:7ab71c7c311b 304 for (int i = 0; i < entity->width; ++i) // Loop through all x-position on lower part of entity
Siriagus 16:caf613d5b85e 305 {
Siriagus 16:caf613d5b85e 306 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 307 {
Siriagus 13:7ab71c7c311b 308 collision = true;
Siriagus 13:7ab71c7c311b 309 break; // No further testing required
Siriagus 13:7ab71c7c311b 310 }
Siriagus 13:7ab71c7c311b 311 }
Siriagus 13:7ab71c7c311b 312
Siriagus 13:7ab71c7c311b 313 if (collision) // If collision
Siriagus 13:7ab71c7c311b 314 {
Siriagus 13:7ab71c7c311b 315 entity->vy = 0; // Set vertical velocity to 0 (playe
Siriagus 13:7ab71c7c311b 316 entity->onGround = true; // entity has hit ground
Siriagus 13:7ab71c7c311b 317 break; // Skip the while loop as the entity can not move further downwards
Siriagus 13:7ab71c7c311b 318 }
Siriagus 13:7ab71c7c311b 319 else // Can safely move entity without collision
Siriagus 15:d5eb13c4c1c6 320 {
Siriagus 13:7ab71c7c311b 321 ++entityBottom; // Move entity one step down
Siriagus 15:d5eb13c4c1c6 322 entity->onGround = false;
Siriagus 15:d5eb13c4c1c6 323 }
Siriagus 13:7ab71c7c311b 324 }
Siriagus 13:7ab71c7c311b 325
Siriagus 16:caf613d5b85e 326 // Wrapping
Siriagus 16:caf613d5b85e 327 y = (entityBottom - (entity->height - 1));
Siriagus 16:caf613d5b85e 328 if (y >= HEIGHT) // if completely outside map
Siriagus 16:caf613d5b85e 329 y = -entity->height; // wrap to top of map
Siriagus 16:caf613d5b85e 330
Siriagus 16:caf613d5b85e 331 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 332 }
Siriagus 13:7ab71c7c311b 333 else // moving up, check collision from top
Siriagus 13:7ab71c7c311b 334 {
Siriagus 13:7ab71c7c311b 335 while(steps--) // Still movement left
Siriagus 13:7ab71c7c311b 336 {
Siriagus 13:7ab71c7c311b 337 collision = false;
Siriagus 16:caf613d5b85e 338
Siriagus 13:7ab71c7c311b 339 for (int i = 0; i < entity->width; ++i) // Check for all x-positions
Siriagus 13:7ab71c7c311b 340 {
Siriagus 16:caf613d5b85e 341 int y1 = ((y-1) + HEIGHT) % HEIGHT; // In case negative, because of wrapping
Siriagus 16:caf613d5b85e 342
Siriagus 16:caf613d5b85e 343 if (map[y1][x+i]) // If moving upwards gives collision for a given x+i
Siriagus 13:7ab71c7c311b 344 {
Siriagus 13:7ab71c7c311b 345 collision = true; // Then we have a collision
Siriagus 13:7ab71c7c311b 346 break; // No further testing needed, skip for loop
Siriagus 13:7ab71c7c311b 347 }
Siriagus 13:7ab71c7c311b 348 }
Siriagus 13:7ab71c7c311b 349
Siriagus 13:7ab71c7c311b 350 if (collision) // If collision was detected
Siriagus 13:7ab71c7c311b 351 {
Siriagus 13:7ab71c7c311b 352 entity->vy = 0; // Set vertical velocity to zero
Siriagus 13:7ab71c7c311b 353 break; // Skip while loop as entity can not move further up
Siriagus 13:7ab71c7c311b 354 }
Siriagus 13:7ab71c7c311b 355 else // If safe to move for all x-values
Siriagus 13:7ab71c7c311b 356 --y; // Move entity one step up
Siriagus 13:7ab71c7c311b 357 }
Siriagus 13:7ab71c7c311b 358
Siriagus 16:caf613d5b85e 359 // Wrapping
Siriagus 16:caf613d5b85e 360 if (y + (entity->height - 1) < 0) // completely outside map (bottom of entity over top of map)
Siriagus 16:caf613d5b85e 361 y = HEIGHT-1 - entity->height - 1; // Sets the altitude.
Siriagus 16:caf613d5b85e 362
Siriagus 13:7ab71c7c311b 363 entity->y = y; // Update vertical position of entity
Siriagus 13:7ab71c7c311b 364 }
Siriagus 15:d5eb13c4c1c6 365 }
Siriagus 15:d5eb13c4c1c6 366
Siriagus 15:d5eb13c4c1c6 367 bool Game::hitTestRect(Rectangle r1, Rectangle r2)
Siriagus 15:d5eb13c4c1c6 368 {
Siriagus 15:d5eb13c4c1c6 369 return ((r1.x + r1.width > r2.x) // r1's right edge to the right of r2's left edge
Siriagus 15:d5eb13c4c1c6 370 && (r1.x < r2.x + r2.width) // r1's left edge to the left of r2's right edge
Siriagus 15:d5eb13c4c1c6 371 && (r1.y + r2.height > r2.y) // r1's bottom lower than r2's top
Siriagus 15:d5eb13c4c1c6 372 && (r1.y < r2.y + r2.height)); // r1's top higher than r2's bottom
Siriagus 15:d5eb13c4c1c6 373
Siriagus 15:d5eb13c4c1c6 374 // Note: Right border: r1.x + r1.width - 1, but we don't need to subtract 1 as we use > instead of >=
Siriagus 15:d5eb13c4c1c6 375 }
Siriagus 15:d5eb13c4c1c6 376
Siriagus 15:d5eb13c4c1c6 377 bool Game::bulletHitMap(Rectangle &bulletColRect, const int map[HEIGHT][WIDTH])
Siriagus 15:d5eb13c4c1c6 378 {
Siriagus 15:d5eb13c4c1c6 379 for (int j = 0; j < bulletColRect.width; ++j)
Siriagus 15:d5eb13c4c1c6 380 {
Siriagus 15:d5eb13c4c1c6 381 if (map[bulletColRect.y][bulletColRect.x + j])
Siriagus 15:d5eb13c4c1c6 382 return true;
Siriagus 15:d5eb13c4c1c6 383 }
Siriagus 15:d5eb13c4c1c6 384
Siriagus 15:d5eb13c4c1c6 385 return false;
Siriagus 16:caf613d5b85e 386 }
Siriagus 16:caf613d5b85e 387
Siriagus 16:caf613d5b85e 388 void Game::moveEnemies()
Siriagus 16:caf613d5b85e 389 {
Siriagus 16:caf613d5b85e 390 for (std::vector<Enemy*>::iterator it = enemies.begin(); it != enemies.end(); ++it)
Siriagus 16:caf613d5b85e 391 {
Siriagus 16:caf613d5b85e 392 Enemy *enemy = *it;
Siriagus 16:caf613d5b85e 393
Siriagus 16:caf613d5b85e 394 // Random movement for enemies
Siriagus 16:caf613d5b85e 395 if (enemy->onGround && (rand() % 100) > 97) // 3 % chance
Siriagus 16:caf613d5b85e 396 {
Siriagus 16:caf613d5b85e 397 // jump
Siriagus 16:caf613d5b85e 398 enemy->vy = -3;
Siriagus 16:caf613d5b85e 399 enemy->onGround = false;
Siriagus 16:caf613d5b85e 400 }
Siriagus 16:caf613d5b85e 401 else if ((rand() % 100) > 98) // 2% chance
Siriagus 16:caf613d5b85e 402 {
Siriagus 16:caf613d5b85e 403 // switch direction
Siriagus 16:caf613d5b85e 404 enemy->vx *= -1;
Siriagus 16:caf613d5b85e 405 enemy->facingLeft = (enemy->vx < 0);
Siriagus 16:caf613d5b85e 406 }
Siriagus 16:caf613d5b85e 407
Siriagus 16:caf613d5b85e 408 // Gravity
Siriagus 16:caf613d5b85e 409 enemy->vy += 1;
Siriagus 16:caf613d5b85e 410
Siriagus 16:caf613d5b85e 411 if (!enemy->dead)
Siriagus 16:caf613d5b85e 412 {
Siriagus 16:caf613d5b85e 413 moveWithCollisionTest(enemy, map);
Siriagus 16:caf613d5b85e 414
Siriagus 16:caf613d5b85e 415 // Enemy AI
Siriagus 16:caf613d5b85e 416 int nextRight = enemy->getRight() + 1; // Next position of right edge if enemy moves to the right
Siriagus 16:caf613d5b85e 417 nextRight %= WIDTH; // wrapping
Siriagus 16:caf613d5b85e 418 for (int i = 0; i < enemy->height; ++i) // Check for all heighs
Siriagus 16:caf613d5b85e 419 {
Siriagus 16:caf613d5b85e 420 // Check if crashing if moving right or left. Bounds should already be limited by moveWithCollisionTest!
Siriagus 16:caf613d5b85e 421 if (map[enemy->y + i][nextRight] || map[enemy->y + i][enemy->x - 1])
Siriagus 16:caf613d5b85e 422 {
Siriagus 16:caf613d5b85e 423 enemy->vx *= -1; // move in opposite direction
Siriagus 16:caf613d5b85e 424 enemy->facingLeft = !enemy->facingLeft; // toggle direction
Siriagus 16:caf613d5b85e 425 break; // no further testing required
Siriagus 16:caf613d5b85e 426 }
Siriagus 16:caf613d5b85e 427 }
Siriagus 16:caf613d5b85e 428 }
Siriagus 16:caf613d5b85e 429 else
Siriagus 16:caf613d5b85e 430 {
Siriagus 16:caf613d5b85e 431 enemy->y += enemy->vy;
Siriagus 16:caf613d5b85e 432 enemy->x += enemy->vx;
Siriagus 16:caf613d5b85e 433 }
Siriagus 16:caf613d5b85e 434 }
Siriagus 7:678873947b29 435 }