forked from jaildesigner-jailgames/jaildoctors_dilemma
431 lines
10 KiB
C++
431 lines
10 KiB
C++
#include "player.h"
|
|
#include <fstream>
|
|
#include <sstream>
|
|
|
|
// 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;
|
|
|
|
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);
|
|
sprite->setVelY(ini.vy);
|
|
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()
|
|
{
|
|
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
|
|
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 (sprite->getPosX() < PLAY_AREA_LEFT)
|
|
{
|
|
border = BORDER_LEFT;
|
|
onBorder = true;
|
|
}
|
|
else if (sprite->getPosX() > PLAY_AREA_RIGHT - sprite->getWidth())
|
|
{
|
|
border = BORDER_RIGHT;
|
|
onBorder = true;
|
|
}
|
|
else if (sprite->getPosY() < PLAY_AREA_TOP)
|
|
{
|
|
border = BORDER_TOP;
|
|
onBorder = true;
|
|
}
|
|
else if (sprite->getPosY() > PLAY_AREA_BOTTOM - sprite->getHeight())
|
|
{
|
|
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 - sprite->getHeight() - 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 - sprite->getWidth() - 1;
|
|
}
|
|
|
|
onBorder = false;
|
|
}
|
|
|
|
// Obtiene el valor del pixel inferior izquierdo del jugador
|
|
SDL_Point Player::getLeftFoot()
|
|
{
|
|
SDL_Point point = {(int)sprite->getPosX(), (int)sprite->getPosY() + sprite->getHeight()};
|
|
return point;
|
|
}
|
|
|
|
// Obtiene el valor del pixel inferior derecho del jugador
|
|
SDL_Point Player::getRightFoot()
|
|
{
|
|
SDL_Point point = {(int)sprite->getPosX() + sprite->getWidth() - 1, (int)sprite->getPosY() + sprite->getHeight()};
|
|
return point;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// Obtiene la velocidad en el eje Y del jugador
|
|
float Player::getVelY()
|
|
{
|
|
return sprite->getVelY();
|
|
}
|
|
|
|
// 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 sprite->getRect();
|
|
}
|
|
|
|
// Obtiene el rectangulo de colision del jugador
|
|
SDL_Rect &Player::getCollider()
|
|
{
|
|
return colliderBox;
|
|
}
|
|
|
|
// Guarda la posición actual en la variable lastPosition
|
|
void Player::setLastPosition()
|
|
{
|
|
lastPosition = getRect();
|
|
}
|
|
|
|
// Deshace el ultimo movimiento
|
|
void Player::undoLastMove()
|
|
{
|
|
x = lastPosition.x;
|
|
y = lastPosition.y;
|
|
}
|
|
|
|
// Recalcula la posición del jugador y su animación
|
|
void Player::move()
|
|
{
|
|
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");
|
|
}
|
|
else
|
|
{
|
|
sprite->setCurrentAnimation("stand");
|
|
}
|
|
sprite->animate();
|
|
|
|
// Actualiza la posición del sprite
|
|
sprite->setPosX(x);
|
|
sprite->setPosY(y);
|
|
}
|
|
|
|
// Comprueba si ha finalizado el salto
|
|
void Player::checkJump()
|
|
{
|
|
if (status == STATUS_JUMPING)
|
|
if (sprite->getVelY() > 0)
|
|
if (sprite->getPosY() > jump_ini)
|
|
{
|
|
setStatus(STATUS_FALLING);
|
|
}
|
|
}
|
|
|
|
// 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()
|
|
{
|
|
player_t params;
|
|
|
|
params.x = sprite->getPosX();
|
|
params.y = sprite->getPosY();
|
|
params.vx = sprite->getVelX();
|
|
params.vy = sprite->getVelY();
|
|
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};
|
|
} |