#include "Level.h" #include #include #include "Monster.h" #include "Pickup.h" #include "Hazard.h" #include "Platform.h" Level::Level() { startX = -1; startY = -1; } void Level::changeLevel(int levelNo) { // Load background image if (!(background = loadImage("space.png"))) std::cout << "Level::changeLevel: Error loading background image.\n"; // Make player into a Marcus player.setImage("marcussheet.png"); player.setClip(ORIENT_FRONT, MARCUS_WIDTH * 0, 0, MARCUS_WIDTH, MARCUS_HEIGHT); player.setClip(ORIENT_BACK, MARCUS_WIDTH * 1, 0, MARCUS_WIDTH, MARCUS_HEIGHT); player.setClip(ORIENT_RIGHT, MARCUS_WIDTH * 2, 0, MARCUS_WIDTH, MARCUS_HEIGHT); player.setClip(ORIENT_LEFT, MARCUS_WIDTH * 3, 0, MARCUS_WIDTH, MARCUS_HEIGHT); player.setClip(ORIENT_CROUCH, MARCUS_WIDTH * 4, 0, MARCUS_WIDTH, CROUCH_HEIGHT); // Read the map file (all level/player init should be done here, not above) loadMap(levelNo); // Cope for no defined start position if (startX < 0) { startX = 0; startY = 0; } player.setX(startX); player.setY(startY); cameraX = 0; // Give him some weapons player.obtainWeapon(0); player.obtainWeapon(1); } void Level::move() { // Construct a rectangle for player, for collision detection SDL_Rect rect; rect.w = player.getClip()->w; rect.h = player.getClip()->h; // Only record y-coord for now rect.y = player.getY(); // Apply gravity player.incYVel(GRAVITY); // Player x-axis movement rect.x = player.getX() + player.getXVel(); // Check for crouching, 2 is setting crouch on if (player.getCrouch() == 2) rect.h = CROUCH_HEIGHT; // 1 is trying to uncrouch, don't let them if something is in the way if (player.getCrouch() == 1) { rect.h = MARCUS_HEIGHT; rect.y = player.getY() - MARCUS_HEIGHT + CROUCH_HEIGHT; // If there's no collision, set crouch to 0 (normal, uncrouched) if (checkCollision(rect) != 1) { player.setCrouch(0); // If the check failed then just keep checking collisions in crouched position } else { rect.h = CROUCH_HEIGHT; rect.y = player.getY(); } } // If there's a collision in the x-axis ... while (checkCollision(rect) == 1) { // ... fit snugly to edge if (player.getXVel() > 0) { rect.x--; } else { rect.x++; } } if (rect.x >= 0) player.setX(rect.x); // Player y-axis movement rect.y = player.getY() + player.getYVel(); // If there's a collision in the y-axis ... if (checkCollision(rect) == 1) { while (checkCollision(rect) == 1) { // ... fit snugly to edge if (player.getYVel() > 0) rect.y--; else rect.y++; } player.setYVel(0); } player.setY(rect.y); // Kill the player if they fall off the screen or touch a hazard if (player.getY() > SCREEN_HEIGHT || checkCollision(rect) == 2) { player.kill(); player.setX(startX); player.setY(startY); cameraX = 0; } player.orient(); // Move the visible weapon with the player player.weapon->setX(player.getX() + WEAPON_OFFSET_X); player.weapon->setY(player.getY() + WEAPON_OFFSET_Y); // Move the projectiles for (int i = 0; i < 10; i++) { // Only calculate if they're active if (player.weapon->projectiles[i].isActive()) { // Move based on weapon speed player.weapon->projectiles[i].setX(player.weapon->projectiles[i].getX() + player.weapon->getSpeed()); if (player.weapon->projectiles[i].getX() + cameraX > SCREEN_WIDTH || player.weapon->projectiles[i].getY() > SCREEN_HEIGHT || player.weapon->projectiles[i].getX() < 0 || player.weapon->projectiles[i].getY() < 0) { // If they go off screen, set to inactive player.weapon->projectiles[i].setActive(false); } // Set up a collision box for the projectiles SDL_Rect bullet; bullet.x = player.weapon->projectiles[i].getX(); bullet.y = player.weapon->projectiles[i].getY(); bullet.w = 20; bullet.h = 20; // Check collision with objects if (checkCollision(bullet)) { player.weapon->projectiles[i].setActive(false); } } } } void Level::draw(Screen *screen) { int x = cameraX * (SCREEN_WIDTH - background->w) / (SCREEN_WIDTH - MAP_X*50); int y = SCREEN_HEIGHT - background->h; // Blit background screen->blit(x, y, background); // If player is in the middle of the screen ... if (player.getX() + cameraX > SCREEN_WIDTH / 2 - player.getClip()->w / 2 + player.getXVel() && player.getX() + cameraX < SCREEN_WIDTH / 2 + player.getClip()->w / 2 + player.getXVel()) { // ... and is either moving left, or moving right but not past the end of the map ... if (player.getXVel() < 0 || (player.getXVel() > 0 && -cameraX + SCREEN_WIDTH < MAP_X * TILE_SIZE)) { // ... then scroll the level cameraX -= player.getXVel(); } } // Don't let the camera move to before the start of the level if (cameraX > 0) cameraX = 0; // Blit player screen->blit(player.getX() + cameraX, player.getY(), player.image, player.getClip()); // Draw each platform... for (int i = 0; i < numPlatforms; i++) { // ...if it is visible if (platform[i].getX() + TILE_SIZE + cameraX >= 0 && platform[i].getX() + cameraX <= SCREEN_WIDTH) { screen->blit(platform[i].getX() + cameraX, platform[i].getY(), platform[0].image, platform[i].getClip()); } } // Draw each hazard... for (int i = 0; i < numHazards; i++) { // ...if it is visible if (hazard[i].getX() + TILE_SIZE + cameraX >= 0 && hazard[i].getX() + cameraX <= SCREEN_WIDTH) { screen->blit(hazard[i].getX() + cameraX, hazard[i].getY(), hazard[0].image, hazard[i].getClip()); } } // Draw the player's weapon screen->blit(player.weapon->getX() + cameraX, player.weapon->getY(), player.weapon->image, player.weapon->getClip()); // Draw each projectile, if it's active for (int i = 0; i < 10; i++) { if (player.weapon->projectiles[i].isActive()) { screen->blit(player.weapon->projectiles[i].getX() + cameraX, player.weapon->projectiles[i].getY(), player.weapon->projectiles[i].image, player.weapon->projectiles[i].getClip()); } } } void Level::loadMap(int LevelNo) { numPlatforms = 0; numHazards = 0; // TODO: Let each Platform have a reference a single tiles image platform[0].setImage("tiles.png"); hazard[0].setImage("tiles.png"); // Open map file std::ifstream map("level01.map"); if (!map) std::cout << "map is NULL.\n"; // Read each tile... for (int i = 0; i < MAP_X * MAP_Y; i++) { int type = -1; map >> type; if (map.fail()) { std::cout << "map.fail().\n"; } // ...and register it as a platform if it's a platform if (type == 1 || type == 2) { // Set x/y-coordinates platform[numPlatforms].setX((i % MAP_X) * TILE_SIZE); platform[numPlatforms].setY((i / MAP_X) * TILE_SIZE); // Set the correct sprite sheet clip platform[numPlatforms].setClip(0, TILE_SIZE * (type - 1), 0, TILE_SIZE, TILE_SIZE); numPlatforms++; } else if (type == 3) { // Set x/y-coordinates hazard[numHazards].setX((i % MAP_X) * TILE_SIZE); hazard[numHazards].setY((i / MAP_X) * TILE_SIZE); // Set the correct sprite sheet clip hazard[numHazards].setClip(0, TILE_SIZE * (type - 1), 0, TILE_SIZE, TILE_SIZE); numHazards++; } else if (type == 'P') { // Set the player starting position startX = (i % MAP_X) * TILE_SIZE; startY = (i / MAP_X) * TILE_SIZE - player.getClip()->h; } } // Close map file map.close(); } /* Return values: 0: No collision 1: Platform 2: Hazard */ int Level::checkCollision(SDL_Rect r) { // TODO: Try to avoid separate loops for each type of MapObject // Loop through each platform for (int i = 0; i < numPlatforms; i++) { // Check for collisions in the x-axis ... if (r.x > platform[i].getX() - r.w && r.x < platform[i].getX() + TILE_SIZE) // ... if found, check for collisions in the y-axis if (r.y > platform[i].getY() - r.h && r.y < platform[i].getY() + TILE_SIZE) return 1; } // Loop through each hazard for (int i = 0; i < numHazards; i++) { // Check for collisions in the x-axis ... if (r.x > hazard[i].getX() - r.w && r.x < hazard[i].getX() + TILE_SIZE) // ... if found, check for collisions in the y-axis if (r.y > hazard[i].getY() - r.h && r.y < hazard[i].getY() + TILE_SIZE) return 2; } return 0; }