Colisiones casi acabadas

This commit is contained in:
2022-09-04 19:43:43 +02:00
parent 1351943c79
commit 796a31a099
3 changed files with 138 additions and 142 deletions

View File

@@ -6,7 +6,7 @@ Game::Game(SDL_Renderer *renderer, Screen *screen, Asset *asset, Input *input)
// Inicia variables // Inicia variables
clock = SDL_GetTicks(); clock = SDL_GetTicks();
currentRoom = "01.room"; currentRoom = "01.room";
spawnPoint = {2 * 8, 12 * 8, 0, 0, 0, STATUS_STANDING, SDL_FLIP_NONE}; spawnPoint = {2 * 8, 12 * 8, 0, 0, 0, s_standing, SDL_FLIP_NONE};
debug = true; debug = true;
// Copia los punteros // Copia los punteros
@@ -222,22 +222,13 @@ void Game::renderDebugInfo()
const int inc = debugText->getCharacterWidth() + 1; const int inc = debugText->getCharacterWidth() + 1;
int line = 131; int line = 131;
text = std::to_string(player->getRect().x) + "," + std::to_string(player->getRect().y); text = "X = " + std::to_string((int)player->x) + ", Y = " + std::to_string((int)player->y);
debugText->write(0, line += inc, text); debugText->write(0, line += inc, text);
text = "status: " + std::to_string(player->status); text = "VX = " + std::to_string(player->vx) + ", VY = " + std::to_string(player->vy);
debugText->write(0, line += inc, text); debugText->write(0, line += inc, text);
text = "foot: " + std::to_string((int)player->getLeftFoot().y); text = "STATE = " + std::to_string(player->state);
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);
debugText->write(0, line += inc, text); debugText->write(0, line += inc, text);
} }

View File

@@ -24,7 +24,7 @@ Player::Player(player_t ini, std::string tileset, std::string animation, SDL_Ren
invincible = false; invincible = false;
jump_ini = ini.jump_ini; jump_ini = ini.jump_ini;
status = ini.status; state = ini.state;
x = ini.x; x = ini.x;
y = ini.y; y = ini.y;
@@ -32,6 +32,7 @@ Player::Player(player_t ini, std::string tileset, std::string animation, SDL_Ren
vy = ini.vy; vy = ini.vy;
w = 8; w = 8;
h = 16; h = 16;
maxVY = 1.2f;
sprite->setPosX(ini.x); sprite->setPosX(ini.x);
sprite->setPosY(ini.y); sprite->setPosY(ini.y);
@@ -44,6 +45,7 @@ Player::Player(player_t ini, std::string tileset, std::string animation, SDL_Ren
colliderBox = getRect(); colliderBox = getRect();
const SDL_Point p = {0, 0}; const SDL_Point p = {0, 0};
colliderPoints.insert(colliderPoints.end(), {p, p, p, p, p, p, p, p}); colliderPoints.insert(colliderPoints.end(), {p, p, p, p, p, p, p, p});
underFeet.insert(underFeet.end(), {p, p});
} }
// Destructor // Destructor
@@ -74,24 +76,29 @@ void Player::update()
void Player::checkInput() void Player::checkInput()
{ {
// Solo comprueba las entradas de dirección cuando está de pie // Solo comprueba las entradas de dirección cuando está de pie
if ((input->checkInput(INPUT_LEFT, REPEAT_TRUE)) && (status == STATUS_STANDING)) if ((input->checkInput(INPUT_LEFT, REPEAT_TRUE)) && (state == s_standing))
{ {
vx = -0.6f; vx = -0.6f;
sprite->setFlip(SDL_FLIP_HORIZONTAL); sprite->setFlip(SDL_FLIP_HORIZONTAL);
} }
else if ((input->checkInput(INPUT_RIGHT, REPEAT_TRUE)) && (status == STATUS_STANDING)) else if ((input->checkInput(INPUT_RIGHT, REPEAT_TRUE)) && (state == s_standing))
{ {
vx = 0.6f; vx = 0.6f;
sprite->setFlip(SDL_FLIP_NONE); sprite->setFlip(SDL_FLIP_NONE);
} }
else if (status == STATUS_STANDING) else if (state == s_standing)
{ {
vx = 0.0f; vx = 0.0f;
} }
if (input->checkInput(INPUT_UP, REPEAT_TRUE)) if (input->checkInput(INPUT_UP, REPEAT_TRUE))
{ {
setStatus(STATUS_JUMPING); if (state == s_standing)
{
state = s_jumping;
vy = -maxVY;
jump_ini = y;
}
} }
} }
@@ -136,6 +143,21 @@ void Player::checkBorders()
} }
} }
// Comprueba el estado del jugador
void Player::checkState()
{
if (state == s_falling)
{
vx = 0.0f;
vy = maxVY;
}
else if (state == s_standing)
{
vy = 0.0f;
}
}
// Cambia al jugador de un borde al opuesto. Util para el cambio de pantalla // Cambia al jugador de un borde al opuesto. Util para el cambio de pantalla
void Player::switchBorders() void Player::switchBorders()
{ {
@@ -160,60 +182,18 @@ void Player::switchBorders()
onBorder = false; 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 // Aplica gravedad al jugador
void Player::applyGravity() void Player::applyGravity()
{ {
if (status == STATUS_JUMPING) const float gf = 0.035f;
// La gravedad solo se aplica cuando está saltando
if (state == s_jumping)
{ {
vy += GRAVITY; vy += gf;
if (vy > MAX_VY) if (vy > maxVY)
{ {
vy = MAX_VY; vy = maxVY;
} }
} }
} }
@@ -235,8 +215,9 @@ SDL_Rect &Player::getCollider()
void Player::move() void Player::move()
{ {
const int tileSize = room->getTileSize(); const int tileSize = room->getTileSize();
lastPosition = {(int)x, (int)y}; lastPosition = {(int)x, (int)y}; // Guarda la posicion actual antes de modificarla
applyGravity(); applyGravity(); // Aplica gravedad al jugador
checkState(); // Comprueba el estado del jugador
// Calcula la nueva posición del jugador y compensa en caso de colisión // Calcula la nueva posición del jugador y compensa en caso de colisión
x += vx; x += vx;
@@ -253,8 +234,6 @@ void Player::move()
{ {
x = (int)x + tileSize - ((int)x % tileSize); x = (int)x + tileSize - ((int)x % tileSize);
} }
//vx = 0.0f;
} }
y += vy; y += vy;
@@ -263,20 +242,68 @@ void Player::move()
// Recoloca // Recoloca
if (vy > 0.0f) if (vy > 0.0f)
{ // Bajando { // Bajando
// y -= ((int)y + h) % tileSize; y -= ((int)y + h) % tileSize;
y -= 8; state = s_standing;
setStatus(STATUS_STANDING);
} }
else else
{ // Subiendo { // Subiendo
y += tileSize - ((int)y % tileSize); y += tileSize - ((int)y % tileSize);
setStatus(STATUS_FALLING); state = s_falling;
} }
} }
else else
// Si no colisiona con los muros, comprueba los tiles atravesables // Si no colisiona con los muros, haz comprobaciones extra
{ {
checkOnFloor(); const int a = (lastPosition.y + h) / tileSize;
const int b = ((int)y + h) / tileSize;
const bool tile_change = a != b;
bool going_down = vy >= 0.0f;
bool tile_aligned = ((int)y + h) % tileSize == 0;
// Si está cayendo y hay cambio de tile o está justo sobre uno
if (going_down && (tile_aligned || tile_change))
{
// Comprueba si tiene uno de los pies sobre una superficie
if (isOnFloor())
{ // Y deja al jugador de pie
state = s_standing;
// Si ademas ha habido un cambio de tile recoloca al jugador
if (tile_change)
{
y = ((int)y - ((int)y % tileSize));
}
}
// Si tiene ambos pies sobre el vacío y no está saltando
else if (state != s_jumping)
{
state = s_falling;
}
}
going_down = vy >= 0.0f;
tile_aligned = ((int)y + h) % tileSize == 0;
// Si simplemente está cayendo (sin mirar si hay cambio de tile o si está justo sobre uno)
if (going_down)
{
if (state != s_jumping)
{
state = s_falling;
}
// Si está alineado con el tile mira el suelo (para que no lo mire si está
// dentro de un tile atravesable y lo deje a medias)
if (tile_aligned)
{
if (isOnFloor())
{
state = s_standing;
}
}
}
} }
// Actualiza la posición del sprite // Actualiza la posición del sprite
@@ -302,52 +329,27 @@ void Player::animate()
// Comprueba si ha finalizado el salto al alcanzar la altura de inicio // Comprueba si ha finalizado el salto al alcanzar la altura de inicio
void Player::checkJumpEnd() void Player::checkJumpEnd()
{ {
if (status == STATUS_JUMPING) if (state == s_jumping)
if (vy > 0) if (vy > 0)
if (y >= jump_ini) if (y >= jump_ini)
{ {
setStatus(STATUS_FALLING); state = s_falling;
} }
} }
// Comprueba si el jugador esta sobre el suelo // Comprueba si el jugador tiene suelo debajo de los pies
void Player::checkOnFloor() bool Player::isOnFloor()
{ {
const int tileSize = room->getTileSize(); bool onFloor = false;
const int a = (lastPosition.y + h) / tileSize; updateFeet();
const int b = getLeftFoot().y / tileSize;
const bool tile_change = a != b;
const bool going_down = vy >= 0.0f; for (auto f : underFeet)
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(f) == TILE_SOLID) || (room->getTile(f) == TILE_TRAVESSABLE));
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);
}
} }
return onFloor;
} }
// Comprueba que el jugador no atraviese ninguna pared // Comprueba que el jugador no atraviese ninguna pared
@@ -377,7 +379,7 @@ player_t Player::getSpawnParams()
params.vx = vx; params.vx = vx;
params.vy = vy; params.vy = vy;
params.jump_ini = jump_ini; params.jump_ini = jump_ini;
params.status = status; params.state = state;
params.flip = sprite->getFlip(); params.flip = sprite->getFlip();
return params; return params;
@@ -409,6 +411,15 @@ void Player::updateColliderPoints()
colliderPoints[7] = {rect.x, rect.y + 15}; colliderPoints[7] = {rect.x, rect.y + 15};
} }
// 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};
}
// Obtiene el valor de la variable // Obtiene el valor de la variable
bool Player::getInvincible() bool Player::getInvincible()
{ {

View File

@@ -13,13 +13,12 @@
#ifndef PLAYER_H #ifndef PLAYER_H
#define PLAYER_H #define PLAYER_H
//#define VX 0.6 enum state_e
#define STATUS_STANDING 0 {
#define STATUS_JUMPING 1 s_standing,
#define STATUS_FALLING 2 s_jumping,
s_falling
#define GRAVITY 0.035f };
#define MAX_VY 1.2f
struct player_t struct player_t
{ {
@@ -28,7 +27,7 @@ struct player_t
float vx; float vx;
float vy; float vy;
int jump_ini; int jump_ini;
int status; state_e state;
SDL_RendererFlip flip; SDL_RendererFlip flip;
}; };
@@ -42,17 +41,23 @@ public:
float vy; // Velocidad/desplazamiento del jugador en el eje Y float vy; // Velocidad/desplazamiento del jugador en el eje Y
int w; // Ancho del jugador int w; // Ancho del jugador
int h; // ALto 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 SDL_Renderer *renderer; // El renderizador de la ventana
Input *input; // Objeto para gestionar la entrada
Asset *asset; // Objeto con la ruta a todos los ficheros de recursos Asset *asset; // Objeto con la ruta a todos los ficheros de recursos
Room *room; // Objeto encargado de gestionar cada habitación del juego Room *room; // Objeto encargado de gestionar cada habitación del juego
LTexture *texture; // Textura con los graficos del enemigo
AnimatedSprite *sprite; // Sprite del enemigo
color_t color; // Color del jugador color_t color; // Color del jugador
SDL_Rect colliderBox; // Caja de colisión con los enemigos u objetos SDL_Rect colliderBox; // Caja de colisión con los enemigos u objetos
std::vector<SDL_Point> colliderPoints; // Puntos de colisión con el mapa std::vector<SDL_Point> colliderPoints; // Puntos de colisión con el mapa
std::vector<SDL_Point> underFeet; // Contiene los puntos que hay bajo cada pie del jugador
state_e state; // Estado en el que se encuentra el jugador. Util apara saber si está saltando o cayendo
bool onBorder; // Indica si el jugador esta en uno de los cuatro bordes de la pantalla 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 int border; // Indica en cual de los cuatro bordes se encuentra
bool invincible; // Si es invencible, no puede morir bool invincible; // Si es invencible, no puede morir
SDL_Rect lastPosition; // Contiene la ultima posición del jugador, por si hay que deshacer algun movimiento
int jump_ini; // Valor del eje Y en el que se inicia el salto
float maxVY; // Velocidad máxima que puede alcanzar al desplazarse en vertical
// Comprueba las entradas y modifica variables // Comprueba las entradas y modifica variables
void checkInput(); void checkInput();
@@ -60,6 +65,9 @@ public:
// Comprueba si se halla en alguno de los cuatro bordes // Comprueba si se halla en alguno de los cuatro bordes
void checkBorders(); void checkBorders();
// Comprueba el estado del jugador
void checkState();
// Asigna velocidad negativa en el eje Y al jugador // Asigna velocidad negativa en el eje Y al jugador
void jump(); void jump();
@@ -75,27 +83,19 @@ public:
// Comprueba si ha finalizado el salto al alcanzar la altura de inicio // Comprueba si ha finalizado el salto al alcanzar la altura de inicio
void checkJumpEnd(); void checkJumpEnd();
// Comprueba si el jugador esta sobre el suelo // Comprueba si el jugador tiene suelo debajo de los pies
void checkOnFloor(); bool isOnFloor();
// Comprueba que el jugador no atraviese ninguna pared // Comprueba que el jugador no atraviese ninguna pared
bool checkWalls(); 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 // Actualiza los puntos de colisión
void updateColliderPoints(); void updateColliderPoints();
public: // Actualiza los puntos de los pies
AnimatedSprite *sprite; // Sprite del enemigo void updateFeet();
SDL_Rect lastPosition; // Contiene la ultima posición del jugador, por si hay que deshacer algun movimiento
int jump_ini; // Valor del eje Y en el que se inicia el salto
int status; // Estado en el que se encuentra el jugador. Util apara saber si está saltando o cayendo
public:
// Constructor // Constructor
Player(player_t ini, std::string tileset, std::string animation, SDL_Renderer *renderer, Asset *asset, Input *input, Room *room); Player(player_t ini, std::string tileset, std::string animation, SDL_Renderer *renderer, Asset *asset, Input *input, Room *room);
@@ -117,12 +117,6 @@ public:
// Cambia al jugador de un borde al opuesto. Util para el cambio de pantalla // Cambia al jugador de un borde al opuesto. Util para el cambio de pantalla
void switchBorders(); void switchBorders();
// Cambia el estado del jugador
void setStatus(int value);
// Obtiene el estado del jugador
int getStatus();
// Obtiene el rectangulo que delimita al jugador // Obtiene el rectangulo que delimita al jugador
SDL_Rect getRect(); SDL_Rect getRect();