diff --git a/source/director.cpp b/source/director.cpp index 899bede..516de18 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -17,7 +17,7 @@ Director::Director(std::string path) } else { - section.name = SECTION_PROG_LOGO; + section.name = SECTION_PROG_GAME; section.subsection = 0; } diff --git a/source/game.cpp b/source/game.cpp index 9975119..00776ac 100644 --- a/source/game.cpp +++ b/source/game.cpp @@ -7,7 +7,7 @@ Game::Game(SDL_Renderer *renderer, Screen *screen, Asset *asset, Input *input) clock = SDL_GetTicks(); currentRoom = "01.room"; spawnPoint = {2 * 8, 12 * 8, 0, 0, 0, STATUS_STANDING, SDL_FLIP_NONE}; - debug = false; + debug = true; // Copia los punteros this->renderer = renderer; @@ -161,10 +161,10 @@ void Game::update() room->update(); { player->update(); - checkPlayerAndWalls(); // Debe ir detras del player update, por si se ha metido en algun muro + // checkPlayerAndWalls(); // Debe ir detras del player update, por si se ha metido en algun muro } checkPlayerOnBorder(); - checkPlayerOnFloor(); + // checkPlayerOnFloor(); checkPlayerAndItems(); checkPlayerAndEnemies(); scoreboard->update(); @@ -200,6 +200,11 @@ void Game::renderDebugInfo() return; } + // Borra el marcador + const SDL_Rect rect = {0, 17 * BLOCK, PLAY_AREA_WIDTH, GAMECANVAS_HEIGHT - PLAY_AREA_HEIGHT}; + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_RenderFillRect(renderer, &rect); + // Pinta la rejilla SDL_SetRenderDrawColor(renderer, 255, 255, 255, 64); for (int i = 0; i < PLAY_AREA_BOTTOM; i += 8) @@ -216,16 +221,19 @@ void Game::renderDebugInfo() const int inc = debugText->getCharacterWidth() + 1; int line = 131; + text = std::to_string((int)player->x) + "," + std::to_string((int)player->y); + debugText->write(0, line += inc, text); + text = "status: " + std::to_string(player->status); debugText->write(0, line += inc, text); - text = "foot: " + std::to_string((int)player->getLeftFoot().y); - debugText->write(0, line += inc, text); + // text = "foot: " + std::to_string((int)player->getLeftFoot().y); + // debugText->write(0, line += inc, text); - const int a = (player->lastPosition.y + 16) / 8; - const int b = player->getLeftFoot().y / 8; - text = "tile: " + std::to_string(a) + " - " + std::to_string(b); - debugText->write(0, line += inc, text); + // const int a = (player->lastPosition.y + 16) / 8; + // const int b = player->getLeftFoot().y / 8; + // text = "tile: " + std::to_string(a) + " - " + std::to_string(b); + // debugText->write(0, line += inc, text); const bool collision = checkPlayerAndEnemies(); text = "collision: " + std::to_string(collision); @@ -261,6 +269,9 @@ bool Game::changeRoom(std::string file) // Crea un objeto habitación nuevo a partir del fichero room = new Room(asset->get(file), renderer, asset, itemTracker, &itemsPicked); + // Pasa la nueva habitación al jugador + player->setRoom(room); + success = true; } @@ -282,105 +293,6 @@ void Game::checkPlayerOnBorder() } } -// Comprueba si el jugador esta sobre el suelo -void Game::checkPlayerOnFloor() -{ - // Comprueba si tiene suelo bajo los pies solo cuando no hay velocidad de subida - // y solo cuando el pie este encima de un bloque, es decir, en multiplos de 8 - - // *** HAY UN POSIBLE PROBLEMA y es que caiga muy rapido y viaje a mas de un pixel de velocidad, - // con lo que se saltaria la comprobación - - // *** POSIBLE SOLUCION. Comprobar si el tile actual del pie es diferente al tile del pie previo. - // Esto indica que se ha saltado la comprobacion cada 8 pixeles. - // En este caso habría que recolocar al jugador en el sitio - - // *** PARECE RESUELTO - - const int a = (player->lastPosition.y + 16) / 8; - const int b = player->getLeftFoot().y / 8; - const bool tile_change = a != b; - - const bool is_not_going_up = player->getVelY() >= 0; - const bool is_tile_aligned = player->getLeftFoot().y % 8 == 0; - - if (((is_not_going_up) && (is_tile_aligned)) || ((is_not_going_up) && (tile_change))) - { - bool test = false; - test |= (room->getTile(player->getLeftFoot()) == TILE_SOLID); - test |= (room->getTile(player->getRightFoot()) == TILE_SOLID); - test |= (room->getTile(player->getLeftFoot()) == TILE_TRAVESSABLE); - test |= (room->getTile(player->getRightFoot()) == TILE_TRAVESSABLE); - - // Tiene uno de los pies sobre una superficie - if (test) - { - player->setStatus(STATUS_STANDING); - - // Si ha habido un cambio de tile, hay que recolocarlo - if (tile_change) - { - int offset = (int)player->sprite->getPosY() % 8; - player->sprite->setPosY((int)player->sprite->getPosY() - offset); - } - } - // Tiene ambos pies sobre el vacío - else if (player->getStatus() != STATUS_JUMPING) - { - player->setStatus(STATUS_FALLING); - } - } -} - -// Comprueba que el jugador no atraviese ninguna pared -void Game::checkPlayerAndWalls() -{ - // Obtiene los ocho puntos de colisión del jugador - const SDL_Rect rect = player->getRect(); - const SDL_Point p1 = {rect.x, rect.y}; - const SDL_Point p2 = {rect.x + 7, rect.y}; - const SDL_Point p3 = {rect.x + 7, rect.y + 7}; - const SDL_Point p4 = {rect.x, rect.y + 7}; - const SDL_Point p5 = {rect.x, rect.y + 8}; - const SDL_Point p6 = {rect.x + 7, rect.y + 8}; - const SDL_Point p7 = {rect.x + 7, rect.y + 15}; - const SDL_Point p8 = {rect.x, rect.y + 15}; - - // Comprueba si ha colisionado con un muro - bool wall = false; - wall |= (room->getTile(p1) == TILE_SOLID); - wall |= (room->getTile(p2) == TILE_SOLID); - wall |= (room->getTile(p3) == TILE_SOLID); - wall |= (room->getTile(p4) == TILE_SOLID); - wall |= (room->getTile(p5) == TILE_SOLID); - wall |= (room->getTile(p6) == TILE_SOLID); - wall |= (room->getTile(p7) == TILE_SOLID); - wall |= (room->getTile(p8) == TILE_SOLID); - - if (wall) - { - // Si hay colisión, deshace el movimiento y lo pone en modo caída - player->undoLastMove(); - player->setStatus(STATUS_FALLING); - } - - // Comprueba si ha colisionado con un tile de los que matan al jugador - bool death = false; - death |= (room->getTile(p1) == TILE_KILL); - death |= (room->getTile(p2) == TILE_KILL); - death |= (room->getTile(p3) == TILE_KILL); - death |= (room->getTile(p4) == TILE_KILL); - death |= (room->getTile(p5) == TILE_KILL); - death |= (room->getTile(p6) == TILE_KILL); - death |= (room->getTile(p7) == TILE_KILL); - death |= (room->getTile(p8) == TILE_KILL); - - if (death) - { - killPlayer(); - } -} - // Comprueba las colisiones del jugador con los enemigos bool Game::checkPlayerAndEnemies() { diff --git a/source/game.h b/source/game.h index e09e8e8..911d53c 100644 --- a/source/game.h +++ b/source/game.h @@ -64,12 +64,6 @@ private: // Comprueba si el jugador esta en el borde de la pantalla y actua void checkPlayerOnBorder(); - // Comprueba si el jugador esta sobre el suelo - void checkPlayerOnFloor(); - - // Comprueba que el jugador no atraviese ninguna pared - void checkPlayerAndWalls(); - // Comprueba las colisiones del jugador con los enemigos bool checkPlayerAndEnemies(); diff --git a/source/player.cpp b/source/player.cpp index aafda59..f84e50b 100644 --- a/source/player.cpp +++ b/source/player.cpp @@ -11,6 +11,7 @@ Player::Player(player_t ini, std::string tileset, std::string animation, SDL_Ren this->asset = asset; this->renderer = renderer; this->input = input; + this->room = room; // Crea objetos texture = new LTexture(renderer, asset->get(tileset)); @@ -24,6 +25,13 @@ Player::Player(player_t ini, std::string tileset, std::string animation, SDL_Ren jump_ini = ini.jump_ini; status = ini.status; + x = ini.x; + y = ini.y; + vx = ini.vx; + vy = ini.vy; + w = 8; + h = 16; + sprite->setPosX(ini.x); sprite->setPosY(ini.y); sprite->setVelX(ini.vx); @@ -34,7 +42,9 @@ Player::Player(player_t ini, std::string tileset, std::string animation, SDL_Ren sprite->setFlip(ini.flip); lastPosition = getRect(); - collider = getRect(); + colliderBox = getRect(); + const SDL_Point p = {0, 0}; + colliderPoints.insert(colliderPoints.end(), {p, p, p, p, p, p, p, p}); } // Destructor @@ -54,14 +64,14 @@ void Player::render() // Actualiza las variables del objeto void Player::update() { - - setLastPosition(); // Guarda la posición actual en la variable lastPosition - checkInput(); // Comprueba las entradas y modifica variables - move(); // Recalcula la posición del jugador y su animación - checkBorders(); // Comprueba si está situado en alguno de los cuatro bordes de la habitación - applyGravity(); // Aplica gravedad al jugador - checkJump(); // Comprueba si ha finalizado el salto - collider = getRect(); // Obtiene el rectangulo que delimita al jugador + setLastPosition(); // Guarda la posición actual en la variable lastPosition + checkInput(); // Comprueba las entradas y modifica variables + move(); // Recalcula la posición del jugador y su animación + checkBorders(); // Comprueba si está situado en alguno de los cuatro bordes de la habitación + applyGravity(); // Aplica gravedad al jugador + checkJump(); // Comprueba si ha finalizado el salto + checkOnFloor(); // Comprueba si el jugador esta sobre el suelo + colliderBox = getRect(); // Obtiene el rectangulo que delimita al jugador } // Comprueba las entradas y modifica variables @@ -70,17 +80,17 @@ void Player::checkInput() // Solo comprueba las entradas de dirección cuando está de pie if ((input->checkInput(INPUT_LEFT, REPEAT_TRUE)) && (status == STATUS_STANDING)) { - sprite->setVelX(-0.6f); + vx = -0.6f; sprite->setFlip(SDL_FLIP_HORIZONTAL); } else if ((input->checkInput(INPUT_RIGHT, REPEAT_TRUE)) && (status == STATUS_STANDING)) { - sprite->setVelX(0.6f); + vx = 0.6f; sprite->setFlip(SDL_FLIP_NONE); } else if (status == STATUS_STANDING) { - sprite->setVelX(0); + vx = 0.0f; } if (input->checkInput(INPUT_UP, REPEAT_TRUE)) @@ -135,20 +145,20 @@ void Player::switchBorders() { if (border == BORDER_TOP) { - sprite->setPosY(PLAY_AREA_BOTTOM - sprite->getHeight() - 1); + y = PLAY_AREA_BOTTOM - sprite->getHeight() - 1; jump_ini += 128; } else if (border == BORDER_BOTTOM) { - sprite->setPosY(PLAY_AREA_TOP + 1); + y = PLAY_AREA_TOP + 1; } else if (border == BORDER_RIGHT) { - sprite->setPosX(PLAY_AREA_LEFT + 1); + x = PLAY_AREA_LEFT + 1; } if (border == BORDER_LEFT) { - sprite->setPosX(PLAY_AREA_RIGHT - sprite->getWidth() - 1); + x = PLAY_AREA_RIGHT - sprite->getWidth() - 1; } onBorder = false; @@ -175,23 +185,23 @@ void Player::setStatus(int value) if ((value == STATUS_JUMPING) && (status == STATUS_STANDING)) { status = STATUS_JUMPING; - sprite->setVelY(-MAX_VY); - jump_ini = sprite->getPosY(); + vy = -MAX_VY; + jump_ini = y; } // Modifica el estado a 'cayendo' if (value == STATUS_FALLING) { status = STATUS_FALLING; - sprite->setVelY(MAX_VY); - sprite->setVelX(0); + vy = MAX_VY; + vx = 0.0f; } // Modifica el estado a 'de pie' if (value == STATUS_STANDING) { status = STATUS_STANDING; - sprite->setVelY(0.0f); + vy = 0.0f; } } @@ -212,10 +222,10 @@ void Player::applyGravity() { if (status == STATUS_JUMPING) { - sprite->setVelY(sprite->getVelY() + GRAVITY); - if (sprite->getVelY() > MAX_VY) + vy += GRAVITY; + if (vy > MAX_VY) { - sprite->setVelY(MAX_VY); + vy = MAX_VY; } } } @@ -229,7 +239,7 @@ SDL_Rect Player::getRect() // Obtiene el rectangulo de colision del jugador SDL_Rect &Player::getCollider() { - return collider; + return colliderBox; } // Guarda la posición actual en la variable lastPosition @@ -241,15 +251,51 @@ void Player::setLastPosition() // Deshace el ultimo movimiento void Player::undoLastMove() { - sprite->setPosX(lastPosition.x); - sprite->setPosY(lastPosition.y); + x = lastPosition.x; + y = lastPosition.y; } // Recalcula la posición del jugador y su animación void Player::move() { - sprite->update(); - if (sprite->getVelX() != 0) + const int tileSize = 8; + + // Calcula la nueva posición del jugador y compensa en caso de colisión + x += vx; + + // Comprueba colisiones con muros + if (checkWalls()) + { + // Recoloca + if (vx > 0) + { + x -= ((int)x + w) % tileSize; + } + else + { + x += tileSize - ((int)x % tileSize); + } + + // vx = 0.0f; + } + + y += vy; + if (checkWalls()) + { + // Recoloca + if (vy > 0.0f) + { + y -= ((int)y + h) % tileSize; + } + else + { + y += tileSize - ((int)y % tileSize); + } + setStatus(STATUS_FALLING); + } + + // Establece la animación + if (vx != 0) { sprite->setCurrentAnimation("walk"); } @@ -257,6 +303,11 @@ void Player::move() { sprite->setCurrentAnimation("stand"); } + sprite->animate(); + + // Actualiza la posición del sprite + sprite->setPosX(x); + sprite->setPosY(y); } // Comprueba si ha finalizado el salto @@ -270,6 +321,73 @@ void Player::checkJump() } } +// Comprueba si el jugador esta sobre el suelo +void Player::checkOnFloor() +{ + // Comprueba si tiene suelo bajo los pies solo cuando no hay velocidad de subida + // y solo cuando el pie este encima de un bloque, es decir, en multiplos de 8 + + // *** HAY UN POSIBLE PROBLEMA y es que caiga muy rapido y viaje a mas de un pixel de velocidad, + // con lo que se saltaria la comprobación + + // *** POSIBLE SOLUCION. Comprobar si el tile actual del pie es diferente al tile del pie previo. + // Esto indica que se ha saltado la comprobacion cada 8 pixeles. + // En este caso habría que recolocar al jugador en el sitio + + // *** PARECE RESUELTO + + const int a = (lastPosition.y + 16) / 8; + const int b = getLeftFoot().y / 8; + const bool tile_change = a != b; + + const bool is_not_going_up = getVelY() >= 0; + const bool is_tile_aligned = getLeftFoot().y % 8 == 0; + + if (((is_not_going_up) && (is_tile_aligned)) || ((is_not_going_up) && (tile_change))) + { + bool test = false; + test |= (room->getTile(getLeftFoot()) == TILE_SOLID); + test |= (room->getTile(getRightFoot()) == TILE_SOLID); + test |= (room->getTile(getLeftFoot()) == TILE_TRAVESSABLE); + test |= (room->getTile(getRightFoot()) == TILE_TRAVESSABLE); + + // Tiene uno de los pies sobre una superficie + if (test) + { + setStatus(STATUS_STANDING); + + // Si ha habido un cambio de tile, hay que recolocarlo + if (tile_change) + { + const int offset = (int)y % 8; + y = ((int)y - offset); + } + } + // Tiene ambos pies sobre el vacío + else if (getStatus() != STATUS_JUMPING) + { + setStatus(STATUS_FALLING); + } + } +} + +// Comprueba que el jugador no atraviese ninguna pared +bool Player::checkWalls() +{ + // Actualiza los puntos de colisión + updateColliderPoints(); + + // Comprueba si ha colisionado con un muro + bool wall = false; + + for (auto c : colliderPoints) + { + wall |= (room->getTile(c) == TILE_SOLID); + } + + return wall; +} + // Obtiene algunos parametros del jugador player_t Player::getSpawnParams() { @@ -290,4 +408,24 @@ player_t Player::getSpawnParams() void Player::reLoadTexture() { texture->reLoad(); +} + +// Establece el valor de la variable +void Player::setRoom(Room *room) +{ + this->room = room; +} + +// Actualiza los puntos de colisión +void Player::updateColliderPoints() +{ + const SDL_Rect rect = getRect(); + colliderPoints[0] = {rect.x, rect.y}; + colliderPoints[1] = {rect.x + 7, rect.y}; + colliderPoints[2] = {rect.x + 7, rect.y + 7}; + colliderPoints[3] = {rect.x, rect.y + 7}; + colliderPoints[4] = {rect.x, rect.y + 8}; + colliderPoints[5] = {rect.x + 7, rect.y + 8}; + colliderPoints[6] = {rect.x + 7, rect.y + 15}; + colliderPoints[7] = {rect.x, rect.y + 15}; } \ No newline at end of file diff --git a/source/player.h b/source/player.h index 93fc491..c235aa6 100644 --- a/source/player.h +++ b/source/player.h @@ -8,6 +8,7 @@ #include "input.h" #include "const.h" #include +#include #ifndef PLAYER_H #define PLAYER_H @@ -34,17 +35,23 @@ struct player_t // Clase Player class Player { -private: - LTexture *texture; // Textura con los graficos del enemigo - Input *input; // Objeto para gestionar la entrada - - SDL_Renderer *renderer; // El renderizador de la ventana - Asset *asset; // Objeto con la ruta a todos los ficheros de recursos - color_t color; // Color del jugador - SDL_Rect collider; // Caja de colisión - - bool onBorder; // Indica si el jugador esta en uno de los cuatro bordes de la pantalla - int border; // Indica en cual de los cuatro bordes se encuentra +public: + float x; // Posición del jugador en el eje X + float y; // Posición del jugador en el eje Y + float vx; // Velocidad/desplazamiento del jugador en el eje X + float vy; // Velocidad/desplazamiento del jugador en el eje Y + int w; // Ancho del jugador + int h; // ALto del jugador + LTexture *texture; // Textura con los graficos del enemigo + Input *input; // Objeto para gestionar la entrada + SDL_Renderer *renderer; // El renderizador de la ventana + Asset *asset; // Objeto con la ruta a todos los ficheros de recursos + Room *room; // Objeto encargado de gestionar cada habitación del juego + color_t color; // Color del jugador + SDL_Rect colliderBox; // Caja de colisión con los enemigos u objetos + std::vector colliderPoints; // Puntos de colisión con el mapa + bool onBorder; // Indica si el jugador esta en uno de los cuatro bordes de la pantalla + int border; // Indica en cual de los cuatro bordes se encuentra // Comprueba las entradas y modifica variables void checkInput(); @@ -67,6 +74,21 @@ private: // Comprueba si ha finalizado el salto void checkJump(); + // Comprueba si el jugador esta sobre el suelo + void checkOnFloor(); + + // Comprueba que el jugador no atraviese ninguna pared + bool checkWalls(); + + // Obtiene el valor del pixel inferior izquierdo del jugador + SDL_Point getLeftFoot(); + + // Obtiene el valor del pixel inferior derecho del jugador + SDL_Point getRightFoot(); + + // Actualiza los puntos de colisión + void updateColliderPoints(); + public: AnimatedSprite *sprite; // Sprite del enemigo SDL_Rect lastPosition; // Contiene la ultima posición del jugador, por si hay que deshacer algun movimiento @@ -94,12 +116,6 @@ public: // Cambia al jugador de un borde al opuesto. Util para el cambio de pantalla void switchBorders(); - // Obtiene el valor del pixel inferior izquierdo del jugador - SDL_Point getLeftFoot(); - - // Obtiene el valor del pixel inferior derecho del jugador - SDL_Point getRightFoot(); - // Cambia el estado del jugador void setStatus(int value); @@ -123,6 +139,9 @@ public: // Recarga la textura void reLoadTexture(); + + // Establece el valor de la variable + void setRoom(Room *room); }; #endif