#include "player.h" #include #include // CAUTION!!!!! si no se gasta al final, quitar la referencia a la habitación // Constructor Player::Player(player_t ini, std::string tileset, std::string animation, SDL_Renderer *renderer, Asset *asset, Input *input, Room *room) { // Obten punteros a objetos this->asset = asset; this->renderer = renderer; this->input = input; this->room = room; // Crea objetos texture = new LTexture(renderer, asset->get(tileset)); sprite = new AnimatedSprite(texture, renderer, animation); // Inicializa variables color = stringToColor("white"); onBorder = false; border = BORDER_TOP; invincible = false; 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->setWidth(8); sprite->setHeight(16); sprite->setFlip(ini.flip); lastPosition = getRect(); colliderBox = getRect(); const SDL_Point p = {0, 0}; colliderPoints.insert(colliderPoints.end(), {p, p, p, p, p, p, p, p}); } // Destructor Player::~Player() { delete texture; delete sprite; } // Pinta el jugador en pantalla void Player::render() { sprite->getTexture()->setColor(color.r, color.g, color.b); sprite->render(); } // Actualiza las variables del objeto void Player::update() { checkInput(); // Comprueba las entradas y modifica variables move(); // Recalcula la posición del jugador animate(); // Establece la animación del jugador checkBorders(); // Comprueba si está situado en alguno de los cuatro bordes de la habitación checkJumpEnd(); // Comprueba si ha finalizado el salto al alcanzar la altura de inicio } // Comprueba las entradas y modifica variables void Player::checkInput() { // Solo comprueba las entradas de dirección cuando está de pie if ((input->checkInput(INPUT_LEFT, REPEAT_TRUE)) && (status == STATUS_STANDING)) { vx = -0.6f; sprite->setFlip(SDL_FLIP_HORIZONTAL); } else if ((input->checkInput(INPUT_RIGHT, REPEAT_TRUE)) && (status == STATUS_STANDING)) { vx = 0.6f; sprite->setFlip(SDL_FLIP_NONE); } else if (status == STATUS_STANDING) { vx = 0.0f; } if (input->checkInput(INPUT_UP, REPEAT_TRUE)) { setStatus(STATUS_JUMPING); } } // Indica si el jugador esta en uno de los cuatro bordes de la pantalla bool Player::getOnBorder() { return onBorder; } // Indica en cual de los cuatro bordes se encuentra int Player::getBorder() { return border; } // Comprueba si está situado en alguno de los cuatro bordes de la habitación void Player::checkBorders() { if (x < PLAY_AREA_LEFT) { border = BORDER_LEFT; onBorder = true; } else if (x > PLAY_AREA_RIGHT - w) { border = BORDER_RIGHT; onBorder = true; } else if (y < PLAY_AREA_TOP) { border = BORDER_TOP; onBorder = true; } else if (y > PLAY_AREA_BOTTOM - h) { border = BORDER_BOTTOM; onBorder = true; } else { onBorder = false; } } // Cambia al jugador de un borde al opuesto. Util para el cambio de pantalla void Player::switchBorders() { if (border == BORDER_TOP) { y = PLAY_AREA_BOTTOM - h - 1; jump_ini += 128; } else if (border == BORDER_BOTTOM) { y = PLAY_AREA_TOP + 1; } else if (border == BORDER_RIGHT) { x = PLAY_AREA_LEFT + 1; } if (border == BORDER_LEFT) { x = PLAY_AREA_RIGHT - w - 1; } onBorder = false; } // Obtiene el valor del pixel inferior izquierdo del jugador SDL_Point Player::getLeftFoot() { return {(int)x, (int)y + h}; } // Obtiene el valor del pixel inferior derecho del jugador SDL_Point Player::getRightFoot() { return {(int)x + 7, (int)y + h}; } // Cambia el estado del jugador void Player::setStatus(int value) { // Si quiere cambiar a saltando, ha de ser desde quieto if ((value == STATUS_JUMPING) && (status == STATUS_STANDING)) { status = STATUS_JUMPING; vy = -MAX_VY; jump_ini = y; } // Modifica el estado a 'cayendo' if (value == STATUS_FALLING) { status = STATUS_FALLING; vy = MAX_VY; vx = 0.0f; } // Modifica el estado a 'de pie' if (value == STATUS_STANDING) { status = STATUS_STANDING; vy = 0.0f; } } // Obtiene el estado del jugador int Player::getStatus() { return status; } // Aplica gravedad al jugador void Player::applyGravity() { if (status == STATUS_JUMPING) { vy += GRAVITY; if (vy > MAX_VY) { vy = MAX_VY; } } } // Obtiene el rectangulo que delimita al jugador SDL_Rect Player::getRect() { return {(int)x, (int)y, w, h}; } // Obtiene el rectangulo de colision del jugador SDL_Rect &Player::getCollider() { colliderBox = getRect(); return colliderBox; } // Recalcula la posición del jugador y su animación void Player::move() { const int tileSize = room->getTileSize(); lastPosition = {(int)x, (int)y}; applyGravity(); // 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.0f) { x = (int)x - ((int)x + w) % tileSize; } else { x = (int)x + tileSize - ((int)x % tileSize); } //vx = 0.0f; } y += vy; if (checkWalls()) { // Recoloca if (vy > 0.0f) { // Bajando // y -= ((int)y + h) % tileSize; y -= 8; setStatus(STATUS_STANDING); } else { // Subiendo y += tileSize - ((int)y % tileSize); setStatus(STATUS_FALLING); } } else // Si no colisiona con los muros, comprueba los tiles atravesables { checkOnFloor(); } // Actualiza la posición del sprite sprite->setPosX(x); sprite->setPosY(y); } // Establece la animación del jugador void Player::animate() { // Establece la animación if (vx != 0) { sprite->setCurrentAnimation("walk"); } else { sprite->setCurrentAnimation("stand"); } sprite->animate(); } // Comprueba si ha finalizado el salto al alcanzar la altura de inicio void Player::checkJumpEnd() { if (status == STATUS_JUMPING) if (vy > 0) if (y >= jump_ini) { setStatus(STATUS_FALLING); } } // Comprueba si el jugador esta sobre el suelo void Player::checkOnFloor() { const int tileSize = room->getTileSize(); const int a = (lastPosition.y + h) / tileSize; const int b = getLeftFoot().y / tileSize; const bool tile_change = a != b; const bool going_down = vy >= 0.0f; const bool is_tile_aligned = getLeftFoot().y % tileSize == 0; if (((going_down) && (is_tile_aligned)) || ((going_down) && (tile_change))) { bool onFloor = false; onFloor |= (room->getTile(getLeftFoot()) == TILE_SOLID); onFloor |= (room->getTile(getRightFoot()) == TILE_SOLID); onFloor |= (room->getTile(getLeftFoot()) == TILE_TRAVESSABLE); onFloor |= (room->getTile(getRightFoot()) == TILE_TRAVESSABLE); // Tiene uno de los pies sobre una superficie if (onFloor) { setStatus(STATUS_STANDING); // Si ha habido un cambio de tile recoloca al jugador if (tile_change) { y = ((int)y - ((int)y % tileSize)); } } // 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() { player_t params; params.x = x; params.y = y; params.vx = vx; params.vy = vy; params.jump_ini = jump_ini; params.status = status; params.flip = sprite->getFlip(); return params; } // Recarga la textura 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}; } // Obtiene el valor de la variable bool Player::getInvincible() { return invincible; } // Establece el valor de la variable void Player::setInvincible(bool value) { invincible = value; }