treballant en Player
This commit is contained in:
@@ -49,24 +49,14 @@ void Player::handleInput() {
|
||||
} else if (Input::get()->checkAction(InputAction::RIGHT)) {
|
||||
wannaGo = Direction::RIGHT;
|
||||
} else {
|
||||
wannaGo = Direction::STAY;
|
||||
wannaGo = Direction::NONE;
|
||||
}
|
||||
|
||||
wannaJump = Input::get()->checkAction(InputAction::JUMP);
|
||||
}
|
||||
|
||||
// ANTIGUO move() - Comentado durante migración a paradigma de estados
|
||||
/*
|
||||
// La lógica de movimiento está distribuida en move
|
||||
void Player::move(float delta_time) {
|
||||
handleHorizontalMovement(delta_time);
|
||||
handleVerticalMovement(delta_time);
|
||||
updateColliderGeometry();
|
||||
}
|
||||
*/
|
||||
|
||||
// NUEVO: La lógica de movimiento está distribuida en move*() y se llama desde update*()
|
||||
void Player::move(float delta_time) {
|
||||
// Este método ahora es un dispatcher que llama al método de movimiento correspondiente
|
||||
switch (state_) {
|
||||
case State::ON_GROUND:
|
||||
moveOnGround(delta_time);
|
||||
@@ -81,45 +71,11 @@ void Player::move(float delta_time) {
|
||||
moveFalling(delta_time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::handleHorizontalMovement(float delta_time) {
|
||||
// TODO: Verificar si esto debe aplicar solo a ON_GROUND o también ON_SLOPE
|
||||
if (state_ == State::ON_GROUND || state_ == State::ON_SLOPE) {
|
||||
// Determinama cuál debe ser la velocidad a partir de automovement o de wannaGo
|
||||
updateVelocity();
|
||||
}
|
||||
|
||||
// Aplica el movimiento y el flip basado en la velocidad resultante
|
||||
if (vx_ < 0.0F) {
|
||||
moveHorizontal(delta_time, Direction::LEFT);
|
||||
sprite_->setFlip(SDL_FLIP_HORIZONTAL);
|
||||
} else if (vx_ > 0.0F) {
|
||||
moveHorizontal(delta_time, Direction::RIGHT);
|
||||
sprite_->setFlip(SDL_FLIP_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::handleVerticalMovement(float delta_time) {
|
||||
// No hay movimiento vertical en estados terrestres
|
||||
if (state_ == State::ON_GROUND || state_ == State::ON_SLOPE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state_ == State::JUMPING) {
|
||||
applyGravity(delta_time);
|
||||
}
|
||||
|
||||
// Movimiento vertical
|
||||
if (vy_ < 0.0F) {
|
||||
moveVerticalUp(delta_time);
|
||||
} else if (vy_ > 0.0F) {
|
||||
moveVerticalDown(delta_time);
|
||||
}
|
||||
syncSpriteAndCollider(); // Actualiza la posición del sprite y las colisiones
|
||||
}
|
||||
|
||||
void Player::handleConveyorBelts() {
|
||||
if (!auto_movement_ and isOnConveyorBelt() and wannaGo == Direction::STAY) {
|
||||
if (!auto_movement_ and isOnConveyorBelt() and wannaGo == Direction::NONE) {
|
||||
auto_movement_ = true;
|
||||
}
|
||||
|
||||
@@ -129,7 +85,6 @@ void Player::handleConveyorBelts() {
|
||||
}
|
||||
|
||||
void Player::handleShouldFall() {
|
||||
// TODO: También verificar ON_SLOPE
|
||||
if (!isOnFloor() and (state_ == State::ON_GROUND || state_ == State::ON_SLOPE)) {
|
||||
transitionToState(State::FALLING);
|
||||
}
|
||||
@@ -189,126 +144,237 @@ void Player::updateState(float delta_time) {
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// NUEVO PARADIGMA: Métodos de actualización por estado
|
||||
// ============================================================================
|
||||
|
||||
// ANTIGUO updateState() - Comentado durante migración
|
||||
/*
|
||||
void Player::updateState(float delta_time) {
|
||||
switch (state_) {
|
||||
case State::STANDING:
|
||||
handleConveyorBelts();
|
||||
handleShouldFall();
|
||||
if (wannaJump) {
|
||||
transitionToState(State::JUMPING);
|
||||
}
|
||||
break;
|
||||
case State::JUMPING:
|
||||
auto_movement_ = false;
|
||||
playJumpSound(delta_time);
|
||||
handleJumpEnd();
|
||||
break;
|
||||
case State::FALLING:
|
||||
auto_movement_ = false;
|
||||
playFallSound(delta_time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Actualización lógica del estado ON_GROUND
|
||||
void Player::updateOnGround(float delta_time) {
|
||||
(void)delta_time; // No usado en este método, pero se mantiene por consistencia
|
||||
|
||||
// Gestiona las cintas transportadoras
|
||||
handleConveyorBelts();
|
||||
|
||||
// Verifica si debe caer (no tiene suelo)
|
||||
handleShouldFall();
|
||||
(void)delta_time; // No usado en este método, pero se mantiene por consistencia
|
||||
handleConveyorBelts(); // Gestiona las cintas transportadoras
|
||||
handleShouldFall(); // Verifica si debe caer (no tiene suelo)
|
||||
|
||||
// Verifica si el jugador quiere saltar
|
||||
if (wannaJump) {
|
||||
transitionToState(State::JUMPING);
|
||||
}
|
||||
if (wannaJump) { transitionToState(State::JUMPING); }
|
||||
}
|
||||
|
||||
// Actualización lógica del estado ON_SLOPE
|
||||
void Player::updateOnSlope(float delta_time) {
|
||||
(void)delta_time; // No usado en este método, pero se mantiene por consistencia
|
||||
|
||||
// Verifica si debe caer (no tiene suelo)
|
||||
handleShouldFall();
|
||||
(void)delta_time; // No usado en este método, pero se mantiene por consistencia
|
||||
handleShouldFall(); // Verifica si debe caer (no tiene suelo)
|
||||
|
||||
// Verifica si el jugador quiere saltar
|
||||
if (wannaJump) {
|
||||
transitionToState(State::JUMPING);
|
||||
}
|
||||
if (wannaJump) { transitionToState(State::JUMPING); }
|
||||
}
|
||||
|
||||
// Actualización lógica del estado JUMPING
|
||||
void Player::updateJumping(float delta_time) {
|
||||
// Desactiva el movimiento automático durante el salto
|
||||
auto_movement_ = false;
|
||||
|
||||
// Reproduce los sonidos de salto
|
||||
playJumpSound(delta_time);
|
||||
|
||||
// Verifica si el salto ha terminado (alcanzó la altura inicial)
|
||||
handleJumpEnd();
|
||||
auto_movement_ = false; // Desactiva el movimiento automático durante el salto
|
||||
playJumpSound(delta_time); // Reproduce los sonidos de salto
|
||||
handleJumpEnd(); // Verifica si el salto ha terminado (alcanzó la altura inicial)
|
||||
}
|
||||
|
||||
// Actualización lógica del estado FALLING
|
||||
void Player::updateFalling(float delta_time) {
|
||||
// Desactiva el movimiento automático durante la caída
|
||||
auto_movement_ = false;
|
||||
|
||||
// Reproduce los sonidos de caída
|
||||
playFallSound(delta_time);
|
||||
auto_movement_ = false; // Desactiva el movimiento automático durante la caída
|
||||
playFallSound(delta_time); // Reproduce los sonidos de caída
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// NUEVO PARADIGMA: Métodos de movimiento por estado
|
||||
// ============================================================================
|
||||
|
||||
// Movimiento físico del estado ON_GROUND
|
||||
void Player::moveOnGround(float delta_time) {
|
||||
// Movimiento horizontal en suelo plano (migrado de handleHorizontalMovement)
|
||||
handleHorizontalMovement(delta_time);
|
||||
// Determinama cuál debe ser la velocidad a partir de automovement o de wannaGo
|
||||
updateVelocity();
|
||||
|
||||
// Actualiza geometría de colisión
|
||||
updateColliderGeometry();
|
||||
if (vx_ == 0.0F) { return; }
|
||||
|
||||
const float DISPLACEMENT = vx_ * delta_time;
|
||||
if (vx_ < 0.0F) {
|
||||
const SDL_FRect PROJECTION = getProjection(Direction::LEFT, DISPLACEMENT);
|
||||
const int POS = room_->checkRightSurfaces(PROJECTION);
|
||||
if (POS == Collision::NONE) {
|
||||
x_ += DISPLACEMENT;
|
||||
} else {
|
||||
x_ = POS + 1;
|
||||
}
|
||||
} else if (vx_ > 0.0F) {
|
||||
const SDL_FRect PROJECTION = getProjection(Direction::RIGHT, DISPLACEMENT);
|
||||
const int POS = room_->checkLeftSurfaces(PROJECTION);
|
||||
if (POS == Collision::NONE) {
|
||||
x_ += DISPLACEMENT;
|
||||
} else {
|
||||
x_ = POS - WIDTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Movimiento físico del estado ON_SLOPE
|
||||
void Player::moveOnSlope(float delta_time) {
|
||||
// Movimiento horizontal en rampa (migrado de handleHorizontalMovement)
|
||||
// handleSlopeMovement() ya se llama desde dentro de moveHorizontal()
|
||||
handleHorizontalMovement(delta_time);
|
||||
// Determinama cuál debe ser la velocidad a partir de automovement o de wannaGo
|
||||
updateVelocity();
|
||||
|
||||
// Actualiza geometría de colisión
|
||||
updateColliderGeometry();
|
||||
if (vx_ == 0.0F) { return; }
|
||||
|
||||
// Movimiento horizontal
|
||||
const float DISPLACEMENT = vx_ * delta_time;
|
||||
if (vx_ < 0.0F) {
|
||||
const SDL_FRect PROJECTION = getProjection(Direction::LEFT, DISPLACEMENT);
|
||||
const int POS = room_->checkRightSurfaces(PROJECTION);
|
||||
if (POS == Collision::NONE) {
|
||||
x_ += DISPLACEMENT;
|
||||
} else {
|
||||
x_ = POS + 1;
|
||||
}
|
||||
} else if (vx_ > 0.0F) {
|
||||
const SDL_FRect PROJECTION = getProjection(Direction::RIGHT, DISPLACEMENT);
|
||||
const int POS = room_->checkLeftSurfaces(PROJECTION);
|
||||
if (POS == Collision::NONE) {
|
||||
x_ += DISPLACEMENT;
|
||||
} else {
|
||||
x_ = POS - WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
// Movimiento vertical
|
||||
// Regla: Si está bajando la rampa, se pega a la slope
|
||||
if (isOnDownSlope()) {
|
||||
y_ += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Regla: Si está STANDING y tropieza lateralmente con una Slope, se pega a la slope
|
||||
// Comprueba si hay rampa en contacto lateral (solo los dos pixels inferiores)
|
||||
const int SIDE_X = vx_ < 0.0F ? static_cast<int>(x_) : static_cast<int>(x_) + WIDTH - 1;
|
||||
const LineVertical SIDE = {
|
||||
.x = SIDE_X,
|
||||
.y1 = static_cast<int>(y_) + HEIGHT - 2,
|
||||
.y2 = static_cast<int>(y_) + HEIGHT - 1};
|
||||
|
||||
// Comprueba la rampa correspondiente según la dirección
|
||||
const int SLOPE_Y = vx_ < 0.0F ? room_->checkLeftSlopes(SIDE) : room_->checkRightSlopes(SIDE);
|
||||
|
||||
if (SLOPE_Y != Collision::NONE) {
|
||||
// Hay rampa: sube al jugador para pegarlo a la rampa
|
||||
|
||||
// --- INICIO DE LA CORRECCIÓN ---
|
||||
|
||||
// Esta es la nueva posición "ideal" a la que nos queremos teletransportar
|
||||
const float new_y = SLOPE_Y - HEIGHT;
|
||||
|
||||
// Solo aplicamos el "snap" si es para SUBIR (new_y < y_)
|
||||
if (new_y < y_) {
|
||||
// "y_ - 1.0F" es la posición máxima que podemos subir en 1 frame.
|
||||
// std::max coge la posición más alta (más baja en pantalla):
|
||||
// - O la posición ideal (new_y)
|
||||
// - O la posición actual - 1 píxel
|
||||
// Esto "suaviza" el salto de 2 píxeles (p.ej. 84 -> 82) en dos
|
||||
// fotogramas (84 -> 83, y luego 83 -> 82)
|
||||
y_ = std::max(new_y, y_ - 1.0F);
|
||||
}
|
||||
|
||||
// --- FIN DE LA CORRECCIÓN ---
|
||||
}
|
||||
}
|
||||
|
||||
// Movimiento físico del estado JUMPING
|
||||
void Player::moveJumping(float delta_time) {
|
||||
// Movimiento horizontal (migrado de handleHorizontalMovement)
|
||||
handleHorizontalMovement(delta_time);
|
||||
// Movimiento horizontal
|
||||
if (vx_ != 0.0F) {
|
||||
const float DISPLACEMENT_X = vx_ * delta_time;
|
||||
const Direction DIRECTION = vx_ > 0.0F ? Direction::RIGHT : Direction::LEFT;
|
||||
const SDL_FRect PROJECTION = getProjection(DIRECTION, DISPLACEMENT_X);
|
||||
|
||||
// Movimiento vertical (migrado de handleVerticalMovement)
|
||||
handleVerticalMovement(delta_time);
|
||||
// Comprueba la colisión con las superficies
|
||||
const int POS = DIRECTION == Direction::LEFT ? room_->checkRightSurfaces(PROJECTION) : room_->checkLeftSurfaces(PROJECTION);
|
||||
|
||||
// Actualiza geometría de colisión
|
||||
updateColliderGeometry();
|
||||
// Calcula la nueva posición
|
||||
if (POS == Collision::NONE) {
|
||||
// No hay colisión: mueve al jugador
|
||||
x_ += DISPLACEMENT_X;
|
||||
} else {
|
||||
// Hay colisión: reposiciona al jugador en el punto de colisión
|
||||
x_ = DIRECTION == Direction::LEFT ? POS + 1 : POS - WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
// Movimiento vertical
|
||||
applyGravity(delta_time);
|
||||
|
||||
const float DISPLACEMENT_Y = vy_ * delta_time;
|
||||
// Movimiento vertical hacia arriba
|
||||
if (vy_ < 0.0F) {
|
||||
const SDL_FRect PROJECTION = getProjection(Direction::UP, DISPLACEMENT_Y);
|
||||
|
||||
// Comprueba la colisión
|
||||
const int POS = room_->checkBottomSurfaces(PROJECTION);
|
||||
|
||||
// Calcula la nueva posición
|
||||
if (POS == Collision::NONE) {
|
||||
// Si no hay colisión
|
||||
y_ += DISPLACEMENT_Y;
|
||||
} else {
|
||||
// Si hay colisión lo mueve hasta donde no colisiona -> FALLING
|
||||
y_ = POS + 1;
|
||||
transitionToState(State::FALLING);
|
||||
}
|
||||
}
|
||||
// Movimiento vertical hacia abajo
|
||||
else if (vy_ > 0.0F) {
|
||||
// Crea el rectangulo de proyección en el eje Y para ver si colisiona
|
||||
const SDL_FRect PROJECTION = getProjection(Direction::DOWN, DISPLACEMENT_Y);
|
||||
|
||||
// Comprueba la colisión con las superficies y las cintas transportadoras
|
||||
const float POS = std::max(room_->checkTopSurfaces(PROJECTION), room_->checkAutoSurfaces(PROJECTION));
|
||||
if (POS != Collision::NONE) {
|
||||
// Si hay colisión lo mueve hasta donde no colisiona y pasa a estar sobre la superficie
|
||||
y_ = POS - HEIGHT;
|
||||
transitionToState(State::ON_GROUND); // Aterrizó en superficie plana o conveyor belt
|
||||
}
|
||||
// Comprueba la colisión con las rampas
|
||||
else {
|
||||
// JUMPING colisiona con rampas solo si vx_ == 0
|
||||
if (vx_ == 0.0F) {
|
||||
auto rect = toSDLRect(PROJECTION);
|
||||
const LineVertical LEFT_SIDE = {.x = rect.x, .y1 = rect.y, .y2 = rect.y + rect.h};
|
||||
const LineVertical RIGHT_SIDE = {.x = rect.x + rect.w - 1, .y1 = rect.y, .y2 = rect.y + rect.h};
|
||||
const float POINT = std::max(room_->checkRightSlopes(RIGHT_SIDE), room_->checkLeftSlopes(LEFT_SIDE));
|
||||
if (POINT != Collision::NONE) {
|
||||
y_ = POINT - HEIGHT;
|
||||
transitionToState(State::ON_SLOPE); // Aterrizó en rampa
|
||||
} else {
|
||||
// No hay colisón con una rampa
|
||||
y_ += DISPLACEMENT_Y;
|
||||
}
|
||||
} else {
|
||||
// Esta saltando con movimiento horizontal y no hay colisión con los muros
|
||||
// Calcula la nueva posición (atraviesa rampas)
|
||||
y_ += DISPLACEMENT_Y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Movimiento físico del estado FALLING
|
||||
void Player::moveFalling(float delta_time) {
|
||||
// Movimiento vertical (migrado de handleVerticalMovement)
|
||||
handleVerticalMovement(delta_time);
|
||||
// Crea el rectangulo de proyección en el eje Y para ver si colisiona
|
||||
const float DISPLACEMENT = vy_ * delta_time;
|
||||
const SDL_FRect PROJECTION = getProjection(Direction::DOWN, DISPLACEMENT);
|
||||
|
||||
// Actualiza geometría de colisión
|
||||
updateColliderGeometry();
|
||||
// Comprueba la colisión con las superficies y las cintas transportadoras
|
||||
const float POS = std::max(room_->checkTopSurfaces(PROJECTION), room_->checkAutoSurfaces(PROJECTION));
|
||||
if (POS != Collision::NONE) {
|
||||
// Si hay colisión lo mueve hasta donde no colisiona y pasa a estar sobre la superficie
|
||||
y_ = POS - HEIGHT;
|
||||
transitionToState(State::ON_GROUND); // Aterrizó en superficie plana o conveyor belt
|
||||
}
|
||||
// Comprueba la colisión con las rampas
|
||||
else {
|
||||
auto rect = toSDLRect(PROJECTION);
|
||||
const LineVertical LEFT_SIDE = {.x = rect.x, .y1 = rect.y, .y2 = rect.y + rect.h};
|
||||
const LineVertical RIGHT_SIDE = {.x = rect.x + rect.w - 1, .y1 = rect.y, .y2 = rect.y + rect.h};
|
||||
const float POINT = std::max(room_->checkRightSlopes(RIGHT_SIDE), room_->checkLeftSlopes(LEFT_SIDE));
|
||||
if (POINT != Collision::NONE) {
|
||||
y_ = POINT - HEIGHT;
|
||||
transitionToState(State::ON_SLOPE); // Aterrizó en rampa
|
||||
} else {
|
||||
y_ += DISPLACEMENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba si está situado en alguno de los cuatro bordes de la habitación
|
||||
@@ -394,169 +460,6 @@ void Player::applyGravity(float delta_time) {
|
||||
}
|
||||
}
|
||||
|
||||
// Maneja el movimiento sobre rampas
|
||||
void Player::handleSlopeMovement(Direction direction) {
|
||||
// No procesa rampas durante el salto (permite atravesarlas cuando salta con movimiento horizontal)
|
||||
// Pero SÍ procesa en STANDING y FALLING (para pegarse a las rampas)
|
||||
if (state_ == State::JUMPING) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Regla: Si está bajando la rampa, se pega a la slope
|
||||
if (isOnDownSlope()) {
|
||||
y_ += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Regla: Si está STANDING y tropieza lateralmente con una Slope, se pega a la slope
|
||||
// Comprueba si hay rampa en contacto lateral (solo los dos pixels inferiores)
|
||||
const int SIDE_X = direction == Direction::LEFT ? static_cast<int>(x_) : static_cast<int>(x_) + WIDTH - 1;
|
||||
const LineVertical SIDE = {
|
||||
.x = SIDE_X,
|
||||
.y1 = static_cast<int>(y_) + HEIGHT - 2,
|
||||
.y2 = static_cast<int>(y_) + HEIGHT - 1};
|
||||
|
||||
// Comprueba la rampa correspondiente según la dirección
|
||||
const int SLOPE_Y = direction == Direction::LEFT ? room_->checkLeftSlopes(SIDE) : room_->checkRightSlopes(SIDE);
|
||||
|
||||
if (SLOPE_Y != Collision::NONE) {
|
||||
// Hay rampa: sube al jugador para pegarlo a la rampa
|
||||
|
||||
// --- INICIO DE LA CORRECCIÓN ---
|
||||
|
||||
// Esta es la nueva posición "ideal" a la que nos queremos teletransportar
|
||||
const float new_y = SLOPE_Y - HEIGHT;
|
||||
|
||||
// Solo aplicamos el "snap" si es para SUBIR (new_y < y_)
|
||||
if (new_y < y_) {
|
||||
// "y_ - 1.0F" es la posición máxima que podemos subir en 1 frame.
|
||||
// std::max coge la posición más alta (más baja en pantalla):
|
||||
// - O la posición ideal (new_y)
|
||||
// - O la posición actual - 1 píxel
|
||||
// Esto "suaviza" el salto de 2 píxeles (p.ej. 84 -> 82) en dos
|
||||
// fotogramas (84 -> 83, y luego 83 -> 82)
|
||||
y_ = std::max(new_y, y_ - 1.0F);
|
||||
}
|
||||
|
||||
// --- FIN DE LA CORRECCIÓN ---
|
||||
}
|
||||
}
|
||||
|
||||
// Maneja el movimiento horizontal
|
||||
void Player::moveHorizontal(float delta_time, Direction direction) {
|
||||
const float DISPLACEMENT = vx_ * delta_time;
|
||||
|
||||
// Crea el rectangulo de proyección en el eje X para ver si colisiona
|
||||
SDL_FRect proj;
|
||||
switch (direction) {
|
||||
case Direction::LEFT:
|
||||
// Movimiento a la izquierda
|
||||
proj = {
|
||||
.x = x_ + DISPLACEMENT,
|
||||
.y = y_,
|
||||
.w = std::ceil(std::fabs(DISPLACEMENT)),
|
||||
.h = HEIGHT};
|
||||
break;
|
||||
|
||||
case Direction::RIGHT:
|
||||
// Movimiento a la derecha
|
||||
proj = {
|
||||
.x = x_ + WIDTH,
|
||||
.y = y_,
|
||||
.w = std::ceil(DISPLACEMENT),
|
||||
.h = HEIGHT};
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Comprueba la colisión con las superficies
|
||||
const int POS = direction == Direction::LEFT ? room_->checkRightSurfaces(proj) : room_->checkLeftSurfaces(proj);
|
||||
|
||||
// Calcula la nueva posición
|
||||
if (POS == Collision::NONE) {
|
||||
// No hay colisión: mueve al jugador
|
||||
x_ += DISPLACEMENT;
|
||||
} else {
|
||||
// Hay colisión: reposiciona al jugador en el punto de colisión
|
||||
x_ = direction == Direction::LEFT ? POS + 1 : POS - WIDTH;
|
||||
}
|
||||
|
||||
// Maneja el movimiento sobre rampas
|
||||
handleSlopeMovement(direction);
|
||||
}
|
||||
|
||||
// Maneja el movimiento vertical hacia arriba
|
||||
void Player::moveVerticalUp(float delta_time) {
|
||||
// Crea el rectangulo de proyección en el eje Y para ver si colisiona
|
||||
const float DISPLACEMENT = vy_ * delta_time;
|
||||
SDL_FRect proj = {
|
||||
.x = x_,
|
||||
.y = y_ + DISPLACEMENT,
|
||||
.w = WIDTH,
|
||||
.h = std::ceil(std::fabs(DISPLACEMENT)) // Para evitar que tenga una altura de 0 pixels
|
||||
};
|
||||
|
||||
// Comprueba la colisión
|
||||
const int POS = room_->checkBottomSurfaces(proj);
|
||||
|
||||
// Calcula la nueva posición
|
||||
if (POS == Collision::NONE) {
|
||||
// Si no hay colisión
|
||||
y_ += DISPLACEMENT;
|
||||
} else {
|
||||
// Si hay colisión lo mueve hasta donde no colisiona
|
||||
// Regla: Si está JUMPING y tropieza contra el techo -> FALLING
|
||||
y_ = POS + 1;
|
||||
transitionToState(State::FALLING);
|
||||
}
|
||||
}
|
||||
|
||||
// Maneja el movimiento vertical hacia abajo
|
||||
void Player::moveVerticalDown(float delta_time) {
|
||||
// Crea el rectangulo de proyección en el eje Y para ver si colisiona
|
||||
const float DISPLACEMENT = vy_ * delta_time;
|
||||
SDL_FRect proj = {
|
||||
.x = x_,
|
||||
.y = y_ + HEIGHT,
|
||||
.w = WIDTH,
|
||||
.h = std::ceil(DISPLACEMENT) // Para evitar que tenga una altura de 0 pixels
|
||||
};
|
||||
|
||||
// Comprueba la colisión con las superficies normales y las automáticas
|
||||
const float POS = std::max(room_->checkTopSurfaces(proj), room_->checkAutoSurfaces(proj));
|
||||
if (POS != Collision::NONE) {
|
||||
// Si hay colisión lo mueve hasta donde no colisiona y pasa a estar sobre la superficie
|
||||
y_ = POS - HEIGHT;
|
||||
transitionToState(State::ON_GROUND); // Aterrizó en superficie plana o conveyor belt
|
||||
} else {
|
||||
// Si no hay colisión con los muros, comprueba la colisión con las rampas
|
||||
// CORRECCIÓN: FALLING siempre se pega a rampas, JUMPING se pega solo si vx_ == 0
|
||||
if (state_ == State::FALLING || (state_ == State::JUMPING && vx_ == 0.0F)) {
|
||||
// No está saltando O salta recto: se pega a las rampas
|
||||
auto rect = toSDLRect(proj);
|
||||
const LineVertical LEFT_SIDE = {.x = rect.x, .y1 = rect.y, .y2 = rect.y + rect.h};
|
||||
const LineVertical RIGHT_SIDE = {.x = rect.x + rect.w - 1, .y1 = rect.y, .y2 = rect.y + rect.h};
|
||||
const float POINT = std::max(room_->checkRightSlopes(RIGHT_SIDE), room_->checkLeftSlopes(LEFT_SIDE));
|
||||
if (POINT != Collision::NONE) {
|
||||
// No está saltando y hay colisión con una rampa
|
||||
// Calcula la nueva posición
|
||||
y_ = POINT - HEIGHT;
|
||||
transitionToState(State::ON_SLOPE); // Aterrizó en rampa
|
||||
} else {
|
||||
// No está saltando y no hay colisón con una rampa
|
||||
// Calcula la nueva posición
|
||||
y_ += DISPLACEMENT;
|
||||
}
|
||||
} else {
|
||||
// Esta saltando con movimiento horizontal y no hay colisión con los muros
|
||||
// Calcula la nueva posición (atraviesa rampas)
|
||||
y_ += DISPLACEMENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Establece la animación del jugador
|
||||
void Player::animate(float delta_time) {
|
||||
if (vx_ != 0) {
|
||||
@@ -595,25 +498,38 @@ void Player::playFallSound(float delta_time) {
|
||||
|
||||
// Comprueba si el jugador tiene suelo debajo de los pies
|
||||
auto Player::isOnFloor() -> bool {
|
||||
bool on_floor = false;
|
||||
bool on_top_surface = false;
|
||||
bool on_conveyor_belt = false;
|
||||
updateFeet();
|
||||
|
||||
// Comprueba las superficies
|
||||
on_floor |= room_->checkTopSurfaces(under_left_foot_);
|
||||
on_floor |= room_->checkTopSurfaces(under_right_foot_);
|
||||
on_top_surface |= room_->checkTopSurfaces(under_left_foot_);
|
||||
on_top_surface |= room_->checkTopSurfaces(under_right_foot_);
|
||||
|
||||
// Comprueba las cintas transportadoras
|
||||
on_floor |= room_->checkConveyorBelts(under_left_foot_);
|
||||
on_floor |= room_->checkConveyorBelts(under_right_foot_);
|
||||
on_conveyor_belt |= room_->checkConveyorBelts(under_left_foot_);
|
||||
on_conveyor_belt |= room_->checkConveyorBelts(under_right_foot_);
|
||||
|
||||
// Comprueba las rampas
|
||||
auto on_slope_l = room_->checkLeftSlopes(under_left_foot_);
|
||||
auto on_slope_r = room_->checkRightSlopes(under_right_foot_);
|
||||
|
||||
return on_floor || on_slope_l || on_slope_r;
|
||||
return on_top_surface || on_conveyor_belt || on_slope_l || on_slope_r;
|
||||
}
|
||||
|
||||
// Comprueba si el jugador esta sobre una superficie automática
|
||||
// Comprueba si el jugador está sobre una superficie
|
||||
auto Player::isOnTopSurface() -> bool {
|
||||
bool on_top_surface = false;
|
||||
updateFeet();
|
||||
|
||||
// Comprueba las superficies
|
||||
on_top_surface |= room_->checkTopSurfaces(under_left_foot_);
|
||||
on_top_surface |= room_->checkTopSurfaces(under_right_foot_);
|
||||
|
||||
return on_top_surface;
|
||||
}
|
||||
|
||||
// Comprueba si el jugador esta sobre una cinta transportadora
|
||||
auto Player::isOnConveyorBelt() -> bool {
|
||||
bool on_conveyor_belt = false;
|
||||
updateFeet();
|
||||
@@ -644,6 +560,18 @@ auto Player::isOnDownSlope() -> bool {
|
||||
return on_slope;
|
||||
}
|
||||
|
||||
// Comprueba si el jugador está sobre una rampa
|
||||
auto Player::isOnSlope() -> bool {
|
||||
bool on_slope = false;
|
||||
updateFeet();
|
||||
|
||||
// Comprueba las rampas
|
||||
on_slope |= room_->checkLeftSlopes(under_left_foot_);
|
||||
on_slope |= room_->checkRightSlopes(under_right_foot_);
|
||||
|
||||
return on_slope;
|
||||
}
|
||||
|
||||
// Comprueba que el jugador no toque ningun tile de los que matan
|
||||
auto Player::handleKillingTiles() -> bool {
|
||||
// Comprueba si hay contacto con algún tile que mata
|
||||
@@ -806,8 +734,8 @@ void Player::initSprite(const std::string& animations_path) {
|
||||
sprite_->setCurrentAnimation("walk");
|
||||
}
|
||||
|
||||
// Actualiza collider_box y collision points
|
||||
void Player::updateColliderGeometry() {
|
||||
// Actualiza la posición del sprite y las colisiones
|
||||
void Player::syncSpriteAndCollider() {
|
||||
placeSprite(); // Coloca el sprite en la posición del jugador
|
||||
collider_box_ = getRect(); // Actualiza el rectangulo de colisión
|
||||
updateColliderPoints(); // Actualiza los puntos de colisión
|
||||
@@ -831,20 +759,66 @@ void Player::updateVelocity() {
|
||||
if (auto_movement_) {
|
||||
// La cinta transportadora tiene el control
|
||||
vx_ = HORIZONTAL_VELOCITY * room_->getConveyorBeltDirection();
|
||||
sprite_->setFlip(vx_ < 0.0F ? Flip::LEFT : Flip::RIGHT);
|
||||
} else {
|
||||
// El jugador tiene el control
|
||||
switch (wannaGo) {
|
||||
case Direction::LEFT:
|
||||
vx_ = -HORIZONTAL_VELOCITY;
|
||||
sprite_->setFlip(Flip::LEFT);
|
||||
break;
|
||||
case Direction::RIGHT:
|
||||
vx_ = HORIZONTAL_VELOCITY;
|
||||
sprite_->setFlip(Flip::RIGHT);
|
||||
break;
|
||||
case Direction::STAY:
|
||||
case Direction::NONE:
|
||||
vx_ = 0.0F;
|
||||
break;
|
||||
default:
|
||||
vx_ = 0.0F;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Devuelve el rectangulo de proyeccion
|
||||
auto Player::getProjection(Direction direction, float displacement) -> SDL_FRect {
|
||||
switch (direction) {
|
||||
case Direction::LEFT:
|
||||
return {
|
||||
.x = x_ + displacement,
|
||||
.y = y_,
|
||||
.w = std::ceil(std::fabs(displacement)), // Para evitar que tenga una anchura de 0 pixels
|
||||
.h = HEIGHT};
|
||||
|
||||
case Direction::RIGHT:
|
||||
return {
|
||||
.x = x_ + WIDTH,
|
||||
.y = y_,
|
||||
.w = std::ceil(displacement), // Para evitar que tenga una anchura de 0 pixels
|
||||
.h = HEIGHT};
|
||||
|
||||
case Direction::UP:
|
||||
return {
|
||||
.x = x_,
|
||||
.y = y_ + displacement,
|
||||
.w = WIDTH,
|
||||
.h = std::ceil(std::fabs(displacement)) // Para evitar que tenga una altura de 0 pixels
|
||||
};
|
||||
|
||||
case Direction::DOWN:
|
||||
return {
|
||||
.x = x_,
|
||||
.y = y_ + HEIGHT,
|
||||
.w = WIDTH,
|
||||
.h = std::ceil(displacement) // Para evitar que tenga una altura de 0 pixels
|
||||
};
|
||||
|
||||
default:
|
||||
return {
|
||||
.x = 0.0F,
|
||||
.y = 0.0F,
|
||||
.w = 0.0F,
|
||||
.h = 0.0F};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user