Files
volcano_2022/source/player.cpp

396 lines
8.3 KiB
C++

#include "player.h"
// Constructor
Player::Player(SDL_Renderer *renderer, Asset *asset, Input *input, Map *map)
{
this->asset = asset;
this->renderer = renderer;
this->input = input;
this->map = map;
sound_jump = JA_LoadSound(asset->get("sound_player_jump.wav").c_str());
sound_death = JA_LoadSound(asset->get("sound_player_death.wav").c_str());
sound_coin = JA_LoadSound(asset->get("sound_player_coin.wav").c_str());
texture = new LTexture();
loadTextureFromFile(texture, asset->get("player.png"), renderer);
sprite = new AnimatedSprite(texture, renderer, asset->get("player.ani"));
w = 16;
h = 24;
x = 3 * 16;
y = 168;
vx = 0;
vy = 0;
lastPosition = {(int)x, (int)y};
const SDL_Rect rect = {(int)x, (int)y, w, h};
sprite->setRect(rect);
sprite->setCurrentAnimation("stand");
sprite->setFlip(SDL_FLIP_NONE);
jumpStrenght = 2.0f;
gravity = 0.3f;
accelX = 0.12f;
maxVX = 1.5f;
maxVY = 4.0f;
state = standing;
jumpPressed = false;
invulnerable = false;
enabled = true;
cooldown = 0;
lives = 10;
coins = 0;
key.insert(key.end(), {0, 0, 0, 0, 0, 0});
const SDL_Point p = {0, 0};
collider.insert(collider.end(), {p, p, p, p, p, p, p, p, p, p, p, p});
underFeet.insert(underFeet.end(), {p, p, p});
}
// Destructor
Player::~Player()
{
JA_DeleteSound(sound_jump);
JA_DeleteSound(sound_death);
JA_DeleteSound(sound_coin);
texture->unload();
delete texture;
delete sprite;
}
// Actualiza todas las variables
void Player::update()
{
checkInput();
move();
animate();
checkActors();
}
// Dibuja el objeto
void Player::render()
{
sprite->render();
}
// Comprueba las entradas y modifica variables
void Player::checkInput()
{
if (input->checkInput(INPUT_LEFT, REPEAT_TRUE))
{
vx = std::max(vx -= accelX, -maxVX);
sprite->setFlip(SDL_FLIP_HORIZONTAL);
}
else if (input->checkInput(INPUT_RIGHT, REPEAT_TRUE))
{
vx = std::min(vx += accelX, maxVX);
sprite->setFlip(SDL_FLIP_NONE);
}
else
{
if (vx > 0.0f)
{
vx = std::max(vx -= accelX, 0.0f);
}
else
{
vx = std::min(vx += accelX, 0.0f);
}
}
if (input->checkInput(INPUT_UP, REPEAT_TRUE))
{
if (state == standing)
{
if (!jumpPressed)
{
jumpStrenght = 2.0f;
vy -= jumpStrenght;
state = jumping;
jumpPressed = true;
}
}
else if (state == jumping)
{
if (jumpPressed)
{
jumpStrenght = std::max(jumpStrenght -= 0.4f, 0.0f);
vy -= jumpStrenght;
}
}
jumpPressed = true;
}
else
{
jumpPressed = false;
if (state == jumping)
{
state = falling;
}
}
}
// Aplica la gravedad
void Player::addGravity()
{
// *** Falta ver pq la gravedad empuja al muñeco hacia abajo en los tiles atravesables
if (state != standing)
{
vy = std::min(vy += gravity, maxVY);
}
}
// Actualiza los puntos de colisión
void Player::updateColliders()
{
const SDL_Point p = {(int)x, (int)y};
// Lado izquierdo
collider[0] = p;
collider[1] = {p.x, p.y + 7};
collider[2] = {p.x, p.y + 12};
collider[3] = {p.x, p.y + 18};
collider[4] = {p.x, p.y + 23};
// Lado derecho
collider[5] = {p.x + 15, p.y};
collider[6] = {p.x + 15, p.y + 7};
collider[7] = {p.x + 15, p.y + 12};
collider[8] = {p.x + 15, p.y + 18};
collider[9] = {p.x + 15, p.y + 23};
// Centro
collider[10] = {p.x + 7, p.y};
collider[11] = {p.x + 7, p.y + 23};
}
// Actualiza los puntos de los pies
void Player::updateFeet()
{
const SDL_Point p = {(int)x, (int)y};
underFeet[0] = {p.x, p.y + h};
underFeet[1] = {p.x + 7, p.y + h};
underFeet[2] = {p.x + 15, p.y + h};
}
// Compruena las colisiones con el mapa
bool Player::checkMapCollisions()
{
bool collision = false;
updateColliders();
for (auto c : collider)
{
collision |= (map->getTile(c) == wall);
}
return collision;
}
// Mueve al jugador en función de la velocidad/desplazamiento
void Player::move()
{
const int tileSize = map->getTileSize();
lastPosition = {(int)x, (int)y};
addGravity();
// Mueve en el eje X y comprueba colisiones con muros
x += vx;
if (checkMapCollisions())
{
// Recoloca
if (vx > 0)
{
x -= ((int)x + w) % tileSize;
}
else
{
x += tileSize - ((int)x % tileSize);
}
vx = 0.0f;
}
// Mueve en el eje Y y comprueba colisiones con muros
y += vy;
if (checkMapCollisions())
{
// Recoloca
if (vy > 0.0f)
{
y -= ((int)y + h) % tileSize;
state = standing;
}
else
{
y += tileSize - ((int)y % tileSize);
state = falling;
}
vy = 0.0f;
}
// Si no hay colisiones con los muros en el eje Y, comprueba no haya atravesado
// el suelo de un tile atravesble
else
{
const int a = (lastPosition.y + h) / tileSize;
const int b = ((int)y + h) / tileSize;
const bool tile_change = a != b;
const bool going_down = vy >= 0.0f;
const bool tile_aligned = ((int)y + h) % tileSize == 0;
if (((going_down) && (tile_aligned)) || ((going_down) && (tile_change)))
{
// Tiene uno de los pies sobre una superficie
if (isOnFloor())
{
state = standing;
vy = 0.0f;
y -= ((int)y + h) % tileSize;
}
// Tiene ambos pies sobre el vacío
else
{
state = falling;
}
}
}
// Actualiza la posición del sprite
sprite->setPosX(x);
sprite->setPosY(y);
}
// Anima al jugador
void Player::animate()
{
if (state != standing)
{
sprite->setCurrentAnimation("jump");
}
else
{
if (abs(vx) < 0.50f)
{
sprite->setCurrentAnimation("stand");
}
else
{
sprite->setCurrentAnimation("walk");
}
}
sprite->animate();
}
// Comprueba si el jugador tiene suelo debajo de los pies
bool Player::isOnFloor()
{
bool onFloor = false;
updateFeet();
for (auto f : underFeet)
{
onFloor |= ((map->getTile(f) == wall) || (map->getTile(f) == passable));
}
return onFloor;
}
// Comprueba si el jugador tiene una plataforma movil bajo sus pies
bool Player::isOnMovingPlatform()
{
bool onMovingPlatform = false;
updateFeet();
for (auto f : underFeet)
{
onMovingPlatform |= (map->getActorName(map->actorCollision(f)) == a_moving_platform);
}
return onMovingPlatform;
}
// Comprueba si está situado en alguno de los cuatro bordes de la habitación
bool Player::isOnScreenBorder()
{
bool success = false;
border = b_none;
if (x < map->getPlayArea(b_left))
{
border = b_left;
success = true;
}
else if (x > map->getPlayArea(b_right) - w)
{
border = b_right;
success = true;
}
else if (y < map->getPlayArea(b_top))
{
border = b_top;
success = true;
}
else if (y > map->getPlayArea(b_bottom) - h)
{
border = b_bottom;
success = true;
}
return success;
}
// Devuelve el valor de la variable
e_border Player::getBorder()
{
return border;
}
// Cambia al jugador de un borde al opuesto. Util para el cambio de pantalla
void Player::switchBorders()
{
switch (border)
{
case b_top:
y = map->getPlayArea(b_bottom) - h;
break;
case b_bottom:
y = map->getPlayArea(b_top);
break;
case b_right:
x = map->getPlayArea(b_left);
break;
case b_left:
x = map->getPlayArea(b_right) - w;
break;
default:
break;
}
border = b_none;
}
// Pasa la referencia del mapa
void Player::setMap(Map *map)
{
this->map = map;
}
// Comprueba las interacciones con los actores
int Player::checkActors()
{
SDL_Rect rect = sprite->getRect();
return map->actorCollision(rect);
}