proves3
This commit is contained in:
@@ -446,31 +446,6 @@ auto Player::handleBorders() const -> Room::Border {
|
||||
return Room::Border::NONE;
|
||||
}
|
||||
|
||||
// Reposiciona al jugador al hacer commit definitivo a la room adyacente.
|
||||
// Se llama cuando el rectángulo completo del jugador ha salido de bounds.
|
||||
void Player::commitToRoom(Room::Border border) {
|
||||
switch (border) {
|
||||
case Room::Border::TOP:
|
||||
y_ += PlayArea::HEIGHT;
|
||||
last_grounded_position_ = static_cast<int>(y_);
|
||||
break;
|
||||
case Room::Border::BOTTOM:
|
||||
y_ -= PlayArea::HEIGHT;
|
||||
last_grounded_position_ = static_cast<int>(y_);
|
||||
break;
|
||||
case Room::Border::RIGHT:
|
||||
x_ -= PlayArea::WIDTH;
|
||||
break;
|
||||
case Room::Border::LEFT:
|
||||
x_ += PlayArea::WIDTH;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
border_ = Room::Border::NONE;
|
||||
syncSpriteAndCollider();
|
||||
}
|
||||
|
||||
void Player::setAdjacentRoom(std::shared_ptr<Room> room, Room::Border direction) {
|
||||
adjacent_room_ = std::move(room);
|
||||
adjacent_direction_ = direction;
|
||||
@@ -481,23 +456,6 @@ void Player::clearAdjacentRoom() {
|
||||
adjacent_direction_ = Room::Border::NONE;
|
||||
}
|
||||
|
||||
auto Player::isFullyOutOfBounds() const -> bool {
|
||||
switch (adjacent_direction_) {
|
||||
case Room::Border::TOP:
|
||||
return (y_ + HEIGHT) <= PlayArea::TOP;
|
||||
case Room::Border::BOTTOM:
|
||||
return y_ >= PlayArea::BOTTOM;
|
||||
case Room::Border::LEFT:
|
||||
return (x_ + WIDTH) <= PlayArea::LEFT;
|
||||
case Room::Border::RIGHT:
|
||||
return x_ >= PlayArea::RIGHT;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Devuelve el TileCollider correcto y los offsets de traducción de coordenadas
|
||||
// según en qué room está el centro del jugador.
|
||||
auto Player::getCollisionContext() const -> CollisionContext {
|
||||
if (!adjacent_room_) {
|
||||
return {room_->getTileCollider(), 0.0F, 0.0F};
|
||||
@@ -534,6 +492,29 @@ auto Player::getCollisionContext() const -> CollisionContext {
|
||||
return {room_->getTileCollider(), 0.0F, 0.0F};
|
||||
}
|
||||
|
||||
void Player::switchBorders() {
|
||||
switch (border_) {
|
||||
case Room::Border::TOP:
|
||||
y_ += PlayArea::HEIGHT;
|
||||
last_grounded_position_ = static_cast<int>(y_);
|
||||
break;
|
||||
case Room::Border::BOTTOM:
|
||||
y_ -= PlayArea::HEIGHT;
|
||||
last_grounded_position_ = static_cast<int>(y_);
|
||||
break;
|
||||
case Room::Border::RIGHT:
|
||||
x_ -= PlayArea::WIDTH;
|
||||
break;
|
||||
case Room::Border::LEFT:
|
||||
x_ += PlayArea::WIDTH;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
border_ = Room::Border::NONE;
|
||||
syncSpriteAndCollider();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Geometría y renderizado
|
||||
// ============================================================================
|
||||
|
||||
@@ -63,7 +63,7 @@ class Player {
|
||||
void update(float delta_time);
|
||||
[[nodiscard]] auto isOnBorder() const -> bool { return border_ != Room::Border::NONE; }
|
||||
[[nodiscard]] auto getBorder() const -> Room::Border { return border_; }
|
||||
void commitToRoom(Room::Border border);
|
||||
void switchBorders();
|
||||
auto getRect() -> SDL_FRect { return {.x = x_, .y = y_, .w = WIDTH, .h = HEIGHT}; }
|
||||
auto getCollider() -> SDL_FRect& { return collider_box_; }
|
||||
auto getSpawnParams() -> SpawnData { return {.x = x_, .y = y_, .vx = vx_, .vy = vy_, .last_grounded_position = last_grounded_position_, .state = state_, .flip = sprite_->getFlip()}; }
|
||||
@@ -73,7 +73,6 @@ class Player {
|
||||
void setRoom(std::shared_ptr<Room> room) { room_ = std::move(room); }
|
||||
void setAdjacentRoom(std::shared_ptr<Room> room, Room::Border direction);
|
||||
void clearAdjacentRoom();
|
||||
[[nodiscard]] auto isFullyOutOfBounds() const -> bool;
|
||||
[[nodiscard]] auto isAlive() const -> bool { return is_alive_; }
|
||||
void setPaused(bool value) { is_paused_ = value; }
|
||||
void setIgnoreInput(bool value) { ignore_input_ = value; }
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "game/ui/console.hpp" // Para Console
|
||||
#include "game/ui/notifier.hpp" // Para Notifier, NotificationText, CHEEVO_NO...
|
||||
#include "utils/defines.hpp" // Para Tile::SIZE, PlayArea::HEIGHT, RoomBorder::BOTTOM
|
||||
#include "utils/easing_functions.hpp" // Para Easing::cubicInOut
|
||||
#include "utils/utils.hpp"
|
||||
|
||||
#ifdef _DEBUG
|
||||
@@ -308,8 +309,8 @@ void Game::updatePlaying(float delta_time) {
|
||||
|
||||
// Actualiza los objetos
|
||||
room_->update(delta_time);
|
||||
if (transitioning_ && transition_adjacent_room_) {
|
||||
transition_adjacent_room_->update(delta_time);
|
||||
if (transitioning_) {
|
||||
transition_old_room_->update(delta_time);
|
||||
}
|
||||
switch (mode_) {
|
||||
case Mode::GAME:
|
||||
@@ -329,9 +330,12 @@ void Game::updatePlaying(float delta_time) {
|
||||
checkPlayerAndEnemies();
|
||||
checkIfPlayerIsAlive();
|
||||
|
||||
// Actualizar cámara de transición
|
||||
// Avanzar transición
|
||||
if (transitioning_) {
|
||||
updateTransitionCamera(delta_time);
|
||||
transition_timer_ += delta_time;
|
||||
if (transition_timer_ >= TRANSITION_DURATION) {
|
||||
endTransition();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -467,11 +471,44 @@ void Game::renderPlaying() {
|
||||
|
||||
if (transitioning_) {
|
||||
// --- Transición animada entre pantallas ---
|
||||
int cam_x = static_cast<int>(camera_offset_x_);
|
||||
int cam_y = static_cast<int>(camera_offset_y_);
|
||||
const float T = std::min(transition_timer_ / TRANSITION_DURATION, 1.0F);
|
||||
const float P = Easing::cubicInOut(T);
|
||||
|
||||
// Renderizar habitación principal con offset de cámara
|
||||
Screen::get()->setRenderOffset(cam_x, cam_y);
|
||||
// Calcular offsets (derivar uno del otro para evitar gap de 1px por truncamiento)
|
||||
int old_ox = 0;
|
||||
int old_oy = 0;
|
||||
int new_ox = 0;
|
||||
int new_oy = 0;
|
||||
|
||||
switch (transition_direction_) {
|
||||
case Room::Border::RIGHT:
|
||||
new_ox = static_cast<int>((1.0F - P) * PlayArea::WIDTH);
|
||||
old_ox = new_ox - PlayArea::WIDTH;
|
||||
break;
|
||||
case Room::Border::LEFT:
|
||||
new_ox = -static_cast<int>((1.0F - P) * PlayArea::WIDTH);
|
||||
old_ox = new_ox + PlayArea::WIDTH;
|
||||
break;
|
||||
case Room::Border::BOTTOM:
|
||||
new_oy = static_cast<int>((1.0F - P) * PlayArea::HEIGHT);
|
||||
old_oy = new_oy - PlayArea::HEIGHT;
|
||||
break;
|
||||
case Room::Border::TOP:
|
||||
new_oy = -static_cast<int>((1.0F - P) * PlayArea::HEIGHT);
|
||||
old_oy = new_oy + PlayArea::HEIGHT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Renderizar habitación saliente con su offset
|
||||
Screen::get()->setRenderOffset(old_ox, old_oy);
|
||||
transition_old_room_->renderMap();
|
||||
transition_old_room_->renderEnemies();
|
||||
transition_old_room_->renderItems();
|
||||
|
||||
// Renderizar habitación entrante + jugador con su offset
|
||||
Screen::get()->setRenderOffset(new_ox, new_oy);
|
||||
room_->renderMap();
|
||||
room_->renderEnemies();
|
||||
room_->renderItems();
|
||||
@@ -479,23 +516,6 @@ void Game::renderPlaying() {
|
||||
player_->render();
|
||||
}
|
||||
|
||||
// Renderizar habitación adyacente: misma cámara pero desplazada una pantalla
|
||||
if (transition_adjacent_room_) {
|
||||
int adj_x = cam_x;
|
||||
int adj_y = cam_y;
|
||||
switch (transition_direction_) {
|
||||
case Room::Border::TOP: adj_y += -PlayArea::HEIGHT; break;
|
||||
case Room::Border::BOTTOM: adj_y += PlayArea::HEIGHT; break;
|
||||
case Room::Border::LEFT: adj_x += -PlayArea::WIDTH; break;
|
||||
case Room::Border::RIGHT: adj_x += PlayArea::WIDTH; break;
|
||||
default: break;
|
||||
}
|
||||
Screen::get()->setRenderOffset(adj_x, adj_y);
|
||||
transition_adjacent_room_->renderMap();
|
||||
transition_adjacent_room_->renderEnemies();
|
||||
transition_adjacent_room_->renderItems();
|
||||
}
|
||||
|
||||
// Scoreboard sin offset
|
||||
Screen::get()->setRenderOffset(0, 0);
|
||||
scoreboard_->render();
|
||||
@@ -773,54 +793,17 @@ auto Game::changeRoom(const std::string& room_path) -> bool {
|
||||
|
||||
// Comprueba si el jugador esta en el borde de la pantalla
|
||||
void Game::checkPlayerIsOnBorder() {
|
||||
if (!player_->isOnBorder()) {
|
||||
// Si hay transición activa y el jugador ha vuelto completamente dentro de bounds,
|
||||
// comprobar si la cámara también ha vuelto para cancelar la transición
|
||||
if (transitioning_ && std::abs(camera_offset_x_) < 1.0F && std::abs(camera_offset_y_) < 1.0F) {
|
||||
endTransition();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const auto BORDER = player_->getBorder();
|
||||
|
||||
// Si ya hay transición activa, comprobar si el jugador hace commit a la room adyacente
|
||||
// No permitir transiciones encadenadas
|
||||
if (transitioning_) {
|
||||
// ¿El jugador ha salido completamente por el lado de la transición?
|
||||
if (player_->isFullyOutOfBounds()) {
|
||||
// Commit: la room adyacente pasa a ser la room principal
|
||||
room_ = transition_adjacent_room_;
|
||||
player_->setRoom(room_);
|
||||
player_->commitToRoom(transition_direction_);
|
||||
current_room_ = transition_adjacent_room_path_;
|
||||
spawn_data_ = player_->getSpawnParams();
|
||||
setScoreBoardColor();
|
||||
|
||||
// Ajustar cámara: restar el desplazamiento de una pantalla completa
|
||||
switch (transition_direction_) {
|
||||
case Room::Border::TOP: camera_offset_y_ -= PlayArea::HEIGHT; break;
|
||||
case Room::Border::BOTTOM: camera_offset_y_ += PlayArea::HEIGHT; break;
|
||||
case Room::Border::LEFT: camera_offset_x_ -= PlayArea::WIDTH; break;
|
||||
case Room::Border::RIGHT: camera_offset_x_ += PlayArea::WIDTH; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
// Limpiar transición (pero la cámara sigue animándose hacia 0)
|
||||
player_->clearAdjacentRoom();
|
||||
transition_adjacent_room_.reset();
|
||||
transition_adjacent_room_path_.clear();
|
||||
transition_direction_ = Room::Border::NONE;
|
||||
|
||||
// La cámara aún no está en 0, así que mantenemos transitioning_ = true
|
||||
// Se resolverá cuando la cámara llegue a 0 y el jugador esté dentro de bounds
|
||||
if (std::abs(camera_offset_x_) < 1.0F && std::abs(camera_offset_y_) < 1.0F) {
|
||||
endTransition();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (transition_just_ended_) {
|
||||
transition_just_ended_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// No hay transición activa — iniciar una nueva
|
||||
if (player_->isOnBorder()) {
|
||||
const auto BORDER = player_->getBorder();
|
||||
const auto ROOM_NAME = room_->getRoom(BORDER);
|
||||
|
||||
// Si no hay habitación adyacente
|
||||
@@ -831,79 +814,50 @@ void Game::checkPlayerIsOnBorder() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Cargar room adyacente
|
||||
auto adjacent_room = std::make_shared<Room>(ROOM_NAME, scoreboard_data_);
|
||||
transition_adjacent_room_ = adjacent_room;
|
||||
transition_adjacent_room_path_ = ROOM_NAME;
|
||||
// Guardar la habitación saliente
|
||||
transition_old_room_ = room_;
|
||||
transition_direction_ = BORDER;
|
||||
|
||||
// Pasar la room adyacente al player para colisiones
|
||||
player_->setAdjacentRoom(adjacent_room, BORDER);
|
||||
|
||||
// Iniciar transición (NO cambiar room_, NO reposicionar jugador)
|
||||
transitioning_ = true;
|
||||
|
||||
if (room_tracker_->addRoom(ROOM_NAME)) {
|
||||
scoreboard_data_->rooms++;
|
||||
Options::stats.rooms = scoreboard_data_->rooms;
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza la cámara durante la transición: sigue al jugador con inercia
|
||||
void Game::updateTransitionCamera(float delta_time) {
|
||||
// El target es una pantalla completa en la dirección de la transición,
|
||||
// excepto si el jugador ha vuelto dentro de bounds (target = 0)
|
||||
float target_x = 0.0F;
|
||||
float target_y = 0.0F;
|
||||
|
||||
const auto RECT = player_->getRect();
|
||||
const float CENTER_X = RECT.x + (RECT.w / 2.0F);
|
||||
const float CENTER_Y = RECT.y + (RECT.h / 2.0F);
|
||||
const bool PLAYER_OUT_OF_BOUNDS =
|
||||
CENTER_X < PlayArea::LEFT || CENTER_X > PlayArea::RIGHT ||
|
||||
CENTER_Y < PlayArea::TOP || CENTER_Y > PlayArea::BOTTOM;
|
||||
|
||||
if (PLAYER_OUT_OF_BOUNDS) {
|
||||
// El jugador está fuera: la cámara se dirige a mostrar la room adyacente
|
||||
switch (transition_direction_) {
|
||||
case Room::Border::TOP: target_y = static_cast<float>(PlayArea::HEIGHT); break;
|
||||
case Room::Border::BOTTOM: target_y = -static_cast<float>(PlayArea::HEIGHT); break;
|
||||
case Room::Border::LEFT: target_x = static_cast<float>(PlayArea::WIDTH); break;
|
||||
case Room::Border::RIGHT: target_x = -static_cast<float>(PlayArea::WIDTH); break;
|
||||
// Crear nueva habitación y reposicionar jugador
|
||||
if (changeRoom(ROOM_NAME)) {
|
||||
// Pasar la room saliente como adyacente al player (para colisiones offscreen)
|
||||
// La dirección es la opuesta: si salimos por TOP, la vieja queda en BOTTOM
|
||||
Room::Border opposite = Room::Border::NONE;
|
||||
switch (BORDER) {
|
||||
case Room::Border::TOP: opposite = Room::Border::BOTTOM; break;
|
||||
case Room::Border::BOTTOM: opposite = Room::Border::TOP; break;
|
||||
case Room::Border::LEFT: opposite = Room::Border::RIGHT; break;
|
||||
case Room::Border::RIGHT: opposite = Room::Border::LEFT; break;
|
||||
default: break;
|
||||
}
|
||||
player_->setAdjacentRoom(transition_old_room_, opposite);
|
||||
|
||||
player_->switchBorders();
|
||||
spawn_data_ = player_->getSpawnParams();
|
||||
|
||||
// Iniciar transición animada
|
||||
transitioning_ = true;
|
||||
transition_timer_ = 0.0F;
|
||||
} else {
|
||||
// changeRoom falló, limpiar
|
||||
transition_old_room_.reset();
|
||||
transition_direction_ = Room::Border::NONE;
|
||||
|
||||
if (BORDER == Room::Border::BOTTOM) {
|
||||
killPlayer();
|
||||
}
|
||||
}
|
||||
// Si el jugador está dentro de bounds, target = 0 → la cámara vuelve
|
||||
|
||||
// Interpolar la cámara hacia el objetivo con velocidad constante
|
||||
constexpr float CAMERA_SPEED = 500.0F;
|
||||
auto lerp_towards = [delta_time](float current, float target) -> float {
|
||||
const float DIFF = target - current;
|
||||
if (std::abs(DIFF) < 1.0F) { return target; }
|
||||
const float STEP = CAMERA_SPEED * delta_time;
|
||||
if (std::abs(DIFF) <= STEP) { return target; }
|
||||
return current + (DIFF > 0.0F ? STEP : -STEP);
|
||||
};
|
||||
|
||||
camera_offset_x_ = lerp_towards(camera_offset_x_, target_x);
|
||||
camera_offset_y_ = lerp_towards(camera_offset_y_, target_y);
|
||||
|
||||
// Si no hay room adyacente pendiente, la cámara vuelve a 0, y al llegar terminamos
|
||||
if (!transition_adjacent_room_ &&
|
||||
std::abs(camera_offset_x_) < 1.0F && std::abs(camera_offset_y_) < 1.0F) {
|
||||
endTransition();
|
||||
}
|
||||
}
|
||||
|
||||
// Finaliza la transición entre pantallas
|
||||
void Game::endTransition() {
|
||||
transitioning_ = false;
|
||||
camera_offset_x_ = 0.0F;
|
||||
camera_offset_y_ = 0.0F;
|
||||
player_->clearAdjacentRoom();
|
||||
transition_adjacent_room_.reset();
|
||||
transition_adjacent_room_path_.clear();
|
||||
transition_just_ended_ = true;
|
||||
transition_timer_ = 0.0F;
|
||||
transition_old_room_.reset();
|
||||
transition_direction_ = Room::Border::NONE;
|
||||
player_->clearAdjacentRoom();
|
||||
Screen::get()->setRenderOffset(0, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ class Game {
|
||||
static constexpr float DEMO_ROOM_DURATION = 6.0F; // Duración de cada habitación en modo demo en segundos (400 frames)
|
||||
static constexpr float FADE_STEP_INTERVAL = 0.05F; // Intervalo entre pasos de fade en segundos
|
||||
static constexpr float POST_FADE_DELAY = 2.0F; // Duración de la pantalla negra después del fade
|
||||
static constexpr float TRANSITION_DURATION = 0.5F; // Duración de la transición entre pantallas en segundos
|
||||
|
||||
// --- Estructuras ---
|
||||
struct DemoData {
|
||||
@@ -77,7 +78,6 @@ class Game {
|
||||
void togglePause(); // Pone el juego en pausa
|
||||
void initPlayer(const Player::SpawnData& spawn_point, std::shared_ptr<Room> room); // Inicializa al jugador
|
||||
void endTransition(); // Finaliza la transición entre pantallas
|
||||
void updateTransitionCamera(float delta_time); // Actualiza la cámara durante la transición
|
||||
void keepMusicPlaying(); // Hace sonar la música
|
||||
void demoInit(); // DEMO MODE: Inicializa las variables para el modo demo
|
||||
void demoCheckRoomChange(float delta_time); // DEMO MODE: Comprueba si se ha de cambiar de habitación
|
||||
@@ -108,11 +108,10 @@ class Game {
|
||||
|
||||
// Transición animada entre pantallas
|
||||
bool transitioning_{false}; // Indica si hay una transición en curso
|
||||
std::shared_ptr<Room> transition_adjacent_room_; // Room adyacente durante la transición
|
||||
std::string transition_adjacent_room_path_; // Path de la room adyacente
|
||||
float transition_timer_{0.0F}; // Tiempo transcurrido en la transición
|
||||
std::shared_ptr<Room> transition_old_room_; // Habitación saliente (se mantiene viva durante la transición)
|
||||
Room::Border transition_direction_{Room::Border::NONE}; // Dirección de la transición
|
||||
float camera_offset_x_{0.0F}; // Offset actual de la cámara (pixeles)
|
||||
float camera_offset_y_{0.0F}; // Offset actual de la cámara (pixeles)
|
||||
bool transition_just_ended_{false}; // Cooldown de 1 frame tras finalizar transición
|
||||
|
||||
// Variables de demo mode
|
||||
DemoData demo_; // Variables para el modo demo
|
||||
|
||||
Reference in New Issue
Block a user