#include "game/scenes/game.hpp" #include #include // Para std::sqrt, std::min #include #include // Para vector #include "core/audio/audio.hpp" // Para Audio #include "core/input/global_inputs.hpp" // Para check #include "core/input/input.hpp" // Para Input, InputAction, Input::DO_NOT_ALLOW_REPEAT #include "core/rendering/screen.hpp" // Para Screen #include "core/rendering/surface.hpp" // Para Surface #include "core/rendering/text.hpp" // Para Text, Text::CENTER_FLAG, Text::COLOR_FLAG #include "core/resources/resource_cache.hpp" // Para ResourceRoom, Resource #include "core/resources/resource_list.hpp" // Para Asset #include "core/system/global_events.hpp" // Para check #include "game/defaults.hpp" // Para Defaults::Music #include "game/gameplay/item_tracker.hpp" // Para ItemTracker #include "game/gameplay/room.hpp" // Para Room, RoomData #include "game/gameplay/room_tracker.hpp" // Para RoomTracker #include "game/gameplay/scoreboard.hpp" // Para Scoreboard::Data, Scoreboard #include "game/options.hpp" // Para Options, options, Cheat, SectionState #include "game/scene_manager.hpp" // Para SceneManager #include "game/ui/notifier.hpp" // Para Notifier, NotificationText, CHEEVO_NO... #include "utils/color.hpp" // Para Color #include "utils/defines.hpp" // Para Tile::SIZE, PlayArea::HEIGHT, RoomBorder::BOTTOM #include "utils/utils.hpp" // Para stringToColor #ifdef _DEBUG #include "core/system/debug.hpp" // Para Debug #endif // Constructor Game::Game(Mode mode) : scoreboard_data_(std::make_shared(0, 9, 0, true, 0, SDL_GetTicks())), scoreboard_(std::make_shared(scoreboard_data_)), room_tracker_(std::make_shared()), mode_(mode), #ifdef _DEBUG current_room_("04.yaml"), spawn_data_(Player::SpawnData(25 * Tile::SIZE, PlayArea::BOTTOM - Player::HEIGHT - Tile::SIZE, 0, 0, 0, Player::State::ON_GROUND, Flip::LEFT)) #else current_room_("04.yaml"), spawn_data_(Player::SpawnData(25 * Tile::SIZE, 21 * Tile::SIZE, 0, 0, 0, Player::State::ON_GROUND, Flip::LEFT)) #endif { // Crea objetos e inicializa variables ItemTracker::init(); demoInit(); room_ = std::make_shared(current_room_, scoreboard_data_); initPlayer(spawn_data_, room_); total_items_ = getTotalItems(); createRoomNameTexture(); game_backbuffer_surface_ = std::make_shared(Options::game.width, Options::game.height); changeRoom(current_room_); SceneManager::current = SceneManager::Scene::GAME; SceneManager::options = SceneManager::Options::NONE; } Game::~Game() { ItemTracker::destroy(); } // Comprueba los eventos de la cola void Game::handleEvents() { SDL_Event event; while (SDL_PollEvent(&event)) { GlobalEvents::handle(event); #ifdef _DEBUG handleDebugEvents(event); #endif } } // Comprueba el teclado void Game::handleInput() { Input::get()->update(); // Inputs globales siempre funcionan if (Input::get()->checkAction(InputAction::TOGGLE_MUSIC, Input::DO_NOT_ALLOW_REPEAT)) { scoreboard_data_->music = !scoreboard_data_->music; scoreboard_data_->music ? Audio::get()->resumeMusic() : Audio::get()->pauseMusic(); Notifier::get()->show({"MUSIC " + std::string(scoreboard_data_->music ? "ENABLED" : "DISABLED")}); } // Durante fade/postfade, solo procesar inputs globales if (state_ != State::PLAYING) { GlobalInputs::handle(); return; } // Input de pausa solo en estado PLAYING if (Input::get()->checkAction(InputAction::PAUSE, Input::DO_NOT_ALLOW_REPEAT)) { togglePause(); Notifier::get()->show({std::string(paused_ ? "GAME PAUSED" : "GAME RUNNING")}); } GlobalInputs::handle(); } // Bucle para el juego void Game::run() { keepMusicPlaying(); if (!scoreboard_data_->music && mode_ == Mode::GAME) { Audio::get()->pauseMusic(); } while (SceneManager::current == SceneManager::Scene::GAME) { update(); render(); } if (mode_ == Mode::GAME) { Audio::get()->stopMusic(); } } // Actualiza el juego, las variables, comprueba la entrada, etc. void Game::update() { const float DELTA_TIME = delta_timer_.tick(); handleEvents(); // Comprueba los eventos handleInput(); // Comprueba las entradas #ifdef _DEBUG Debug::get()->clear(); #endif // Dispatch por estado switch (state_) { case State::PLAYING: updatePlaying(DELTA_TIME); break; case State::BLACK_SCREEN: updateBlackScreen(DELTA_TIME); break; case State::GAME_OVER: updateGameOver(DELTA_TIME); break; case State::FADE_TO_ENDING: updateFadeToEnding(DELTA_TIME); break; case State::POST_FADE_ENDING: updatePostFadeEnding(DELTA_TIME); break; } Audio::update(); // Actualiza el objeto Audio Screen::get()->update(DELTA_TIME); // Actualiza el objeto Screen #ifdef _DEBUG updateDebugInfo(); #endif } // Actualiza el juego en estado PLAYING void Game::updatePlaying(float delta_time) { // Actualiza los objetos room_->update(delta_time); switch (mode_) { case Mode::GAME: #ifdef _DEBUG // Maneja el arrastre del jugador con el ratón (debug) handleDebugMouseDrag(delta_time); // Si estamos arrastrando, no ejecutar la física normal del jugador if (!debug_dragging_player_) { player_->update(delta_time); } #else player_->update(delta_time); #endif handlePlayerIsOnBorder(); handlePlayerAndItemsCollisions(); handlePlayerAndEnemiesCollisions(); handleIfPlayerIsAlive(); isGameCompleted(); restAtJail(delta_time); break; case Mode::DEMO: demoCheckRoomChange(delta_time); break; } scoreboard_->update(delta_time); keepMusicPlaying(); } // Actualiza el juego en estado BLACK_SCREEN void Game::updateBlackScreen(float delta_time) { state_time_ += delta_time; // Si se acabaron las vidas Y pasó el threshold → GAME_OVER if (scoreboard_data_->lives < 0 && state_time_ > GAME_OVER_THRESHOLD) { transitionToState(State::GAME_OVER); return; } // Si pasó la duración completa → volver a PLAYING if (state_time_ > BLACK_SCREEN_DURATION) { // Despausar al salir player_->setPaused(false); room_->setPaused(false); Screen::get()->setBorderColor(room_->getBorderColor()); transitionToState(State::PLAYING); } } // Actualiza el juego en estado GAME_OVER void Game::updateGameOver(float delta_time) { // Pequeño delay antes de cambiar escena state_time_ += delta_time; if (state_time_ > 0.1F) { // 100ms de delay mínimo SceneManager::current = SceneManager::Scene::TITLE; } } // Actualiza el juego en estado FADE_TO_ENDING void Game::updateFadeToEnding(float delta_time) { // Actualiza room, enemies, items (todo sigue funcionando) room_->update(delta_time); // NO actualizar player (congelar movimiento) // player_->update(delta_time); -- COMENTADO INTENCIONALMENTE // Actualiza scoreboard scoreboard_->update(delta_time); keepMusicPlaying(); // Aplica el fade progresivo al BACKBUFFER (no al renderer de pantalla) fade_accumulator_ += delta_time; if (fade_accumulator_ >= FADE_STEP_INTERVAL) { fade_accumulator_ = 0.0F; if (game_backbuffer_surface_->fadeSubPalette()) { // Fade completado, transicionar a POST_FADE transitionToState(State::POST_FADE_ENDING); } } } // Actualiza el juego en estado POST_FADE_ENDING void Game::updatePostFadeEnding(float delta_time) { // Pantalla negra estática, acumular tiempo state_time_ += delta_time; // Después del delay, cambiar a la escena de ending if (state_time_ >= POST_FADE_DELAY) { SceneManager::current = SceneManager::Scene::TITLE; } } // Cambia al estado especificado y resetea los timers void Game::transitionToState(State new_state) { // Lógica de ENTRADA según el nuevo estado if (new_state == State::BLACK_SCREEN) { // Respawn room y player room_ = std::make_shared(current_room_, scoreboard_data_); initPlayer(spawn_data_, room_); // Pausar ambos room_->setPaused(true); player_->setPaused(true); } state_ = new_state; state_time_ = 0.0F; fade_accumulator_ = 0.0F; } // Pinta los objetos en pantalla void Game::render() { // Dispatch por estado switch (state_) { case State::PLAYING: renderPlaying(); break; case State::BLACK_SCREEN: renderBlackScreen(); break; case State::GAME_OVER: renderGameOver(); break; case State::FADE_TO_ENDING: renderFadeToEnding(); break; case State::POST_FADE_ENDING: renderPostFadeEnding(); break; } } // Renderiza el juego en estado PLAYING (directo a pantalla) void Game::renderPlaying() { // Prepara para dibujar el frame Screen::get()->start(); // Dibuja los elementos del juego en orden room_->renderMap(); room_->renderEnemies(); room_->renderItems(); if (mode_ == Mode::GAME) { player_->render(); } renderRoomName(); #ifdef _DEBUG if (!Debug::get()->isEnabled()) { scoreboard_->render(); } // Debug info renderDebugInfo(); #else scoreboard_->render(); #endif // Actualiza la pantalla Screen::get()->render(); } // Renderiza el juego en estado BLACK_SCREEN (pantalla negra) void Game::renderBlackScreen() { Screen::get()->start(); auto const COLOR = Color::index(Color::Cpc::BLACK); Screen::get()->clearSurface(COLOR); Screen::get()->setBorderColor(COLOR); Screen::get()->render(); } // Renderiza el juego en estado GAME_OVER (pantalla negra) void Game::renderGameOver() { Screen::get()->start(); Screen::get()->clearSurface(Color::index(Color::Cpc::BLACK)); Screen::get()->render(); } // Renderiza el juego en estado FADE_TO_ENDING (via backbuffer) void Game::renderFadeToEnding() { // 1. Guardar renderer actual auto previous_renderer = Screen::get()->getRendererSurface(); // 2. Cambiar target a backbuffer Screen::get()->setRendererSurface(game_backbuffer_surface_); // 3. Renderizar todo a backbuffer game_backbuffer_surface_->clear(Color::index(Color::Cpc::BLACK)); room_->renderMap(); room_->renderEnemies(); room_->renderItems(); player_->render(); // Player congelado pero visible renderRoomName(); scoreboard_->render(); // 4. Restaurar renderer original Screen::get()->setRendererSurface(previous_renderer); // 5. Preparar pantalla y volcar backbuffer (fade YA aplicado en update) Screen::get()->start(); game_backbuffer_surface_->render(); Screen::get()->render(); } // Renderiza el juego en estado POST_FADE_ENDING (pantalla negra) void Game::renderPostFadeEnding() { Screen::get()->start(); Screen::get()->clearSurface(Color::index(Color::Cpc::BLACK)); Screen::get()->render(); } #ifdef _DEBUG // Pasa la información de debug void Game::updateDebugInfo() { // Debug::get()->add("X = " + std::to_string(static_cast(player_->x_)) + ", Y = " + std::to_string(static_cast(player_->y_))); // Debug::get()->add("VX = " + std::to_string(player_->vx_).substr(0, 4) + ", VY = " + std::to_string(player_->vy_).substr(0, 4)); // Debug::get()->add("STATE = " + std::to_string(static_cast(player_->state_))); } // Pone la información de debug en pantalla void Game::renderDebugInfo() { if (!Debug::get()->isEnabled()) { return; } auto surface = Screen::get()->getRendererSurface(); // Borra el área del scoreboard SDL_FRect rect = {ScoreboardArea::X, ScoreboardArea::Y, ScoreboardArea::WIDTH, ScoreboardArea::HEIGHT}; surface->fillRect(&rect, Color::index(Color::Cpc::BLACK)); // Pinta la rejilla /*for (int i = 0; i < PlayArea::BOTTOM; i += 8) { // Lineas horizontales surface->drawLine(0, i, PlayArea::RIGHT, i, static_cast(PaletteColor::BRIGHT_BLACK)); } for (int i = 0; i < PlayArea::RIGHT; i += 8) { // Lineas verticales surface->drawLine(i, 0, i, PlayArea::BOTTOM - 1, static_cast(PaletteColor::BRIGHT_BLACK)); }*/ // Pinta el texto de debug en el área del scoreboard Debug::get()->setPos({ScoreboardArea::X, ScoreboardArea::Y}); Debug::get()->render(); } // Comprueba los eventos void Game::handleDebugEvents(const SDL_Event& event) { if (event.type == SDL_EVENT_KEY_DOWN && static_cast(event.key.repeat) == 0) { switch (event.key.key) { case SDLK_F12: Debug::get()->toggleEnabled(); Notifier::get()->show({"DEBUG " + std::string(Debug::get()->isEnabled() ? "ENABLED" : "DISABLED")}); room_->redrawMap(); // Redibuja el tilemap para mostrar/ocultar líneas de colisión Options::cheats.invincible = static_cast(Debug::get()->isEnabled()); player_->setColor(); scoreboard_data_->music = !Debug::get()->isEnabled(); scoreboard_data_->music ? Audio::get()->resumeMusic() : Audio::get()->pauseMusic(); break; case SDLK_R: Resource::Cache::get()->reload(); break; case SDLK_W: changeRoom(room_->getRoom(Room::Border::TOP)); break; case SDLK_A: changeRoom(room_->getRoom(Room::Border::LEFT)); break; case SDLK_S: changeRoom(room_->getRoom(Room::Border::BOTTOM)); break; case SDLK_D: changeRoom(room_->getRoom(Room::Border::RIGHT)); break; case SDLK_1: Options::cheats.infinite_lives = Options::cheats.infinite_lives == Options::Cheat::State::ENABLED ? Options::Cheat::State::DISABLED : Options::Cheat::State::ENABLED; Notifier::get()->show({std::string("INFINITE LIVES ") + (Options::cheats.infinite_lives == Options::Cheat::State::ENABLED ? "ENABLED" : "DISABLED")}, Notifier::Style::DEFAULT, -1, true); player_->setColor(); break; case SDLK_2: Options::cheats.invincible = Options::cheats.invincible == Options::Cheat::State::ENABLED ? Options::Cheat::State::DISABLED : Options::Cheat::State::ENABLED; Notifier::get()->show({std::string("INVINCIBLE ") + (Options::cheats.invincible == Options::Cheat::State::ENABLED ? "ENABLED" : "DISABLED")}, Notifier::Style::DEFAULT, -1, true); player_->setColor(); break; case SDLK_0: Screen::get()->toggleDebugInfo(); break; default: break; } } } // Maneja el arrastre del jugador con el ratón (debug) void Game::handleDebugMouseDrag(float delta_time) { // Solo funciona si Debug está habilitado if (!Debug::get()->isEnabled()) { return; } // Obtener estado del ratón (coordenadas de ventana física) float mouse_x = 0.0F; float mouse_y = 0.0F; SDL_MouseButtonFlags buttons = SDL_GetMouseState(&mouse_x, &mouse_y); // Convertir coordenadas de ventana a coordenadas lógicas del renderer float render_x = 0.0F; float render_y = 0.0F; SDL_RenderCoordinatesFromWindow(Screen::get()->getRenderer(), mouse_x, mouse_y, &render_x, &render_y); // Restar el offset del borde para obtener coordenadas del área de juego SDL_FRect dst_rect = Screen::get()->getGameSurfaceDstRect(); float game_x = render_x - dst_rect.x; float game_y = render_y - dst_rect.y; // Verificar si los botones están presionados bool left_button_pressed = (buttons & SDL_BUTTON_LMASK) != 0; bool right_button_pressed = (buttons & SDL_BUTTON_RMASK) != 0; // Botón derecho: teleport instantáneo a la posición del cursor if (right_button_pressed && !debug_dragging_player_) { player_->setDebugPosition(game_x, game_y); player_->finalizeDebugTeleport(); } else if (left_button_pressed) { // Obtener posición actual del jugador SDL_FRect player_rect = player_->getRect(); float player_x = player_rect.x; float player_y = player_rect.y; // Calcular distancia al objetivo float dx = game_x - player_x; float dy = game_y - player_y; float distance = std::sqrt(dx * dx + dy * dy); // Constantes de velocidad con ease-in (aceleración progresiva) constexpr float DRAG_SPEED_MIN = 30.0F; // Velocidad inicial (pixels/segundo) constexpr float DRAG_SPEED_MAX = 600.0F; // Velocidad máxima (pixels/segundo) constexpr float DRAG_ACCELERATION = 600.0F; // Aceleración (pixels/segundo²) // Incrementar velocidad con el tiempo (ease-in) if (!debug_dragging_player_) { debug_drag_speed_ = DRAG_SPEED_MIN; // Iniciar con velocidad mínima } debug_drag_speed_ = std::min(DRAG_SPEED_MAX, debug_drag_speed_ + DRAG_ACCELERATION * delta_time); if (distance > 1.0F) { // Calcular el movimiento con la velocidad actual float move_factor = std::min(1.0F, debug_drag_speed_ * delta_time / distance); float new_x = player_x + dx * move_factor; float new_y = player_y + dy * move_factor; // Mover el jugador hacia la posición del cursor player_->setDebugPosition(new_x, new_y); } debug_dragging_player_ = true; Debug::get()->add(std::string("X : " + std::to_string(static_cast(player_rect.x)))); Debug::get()->add(std::string("Y : " + std::to_string(static_cast(player_rect.y)))); } else if (debug_dragging_player_) { // Botón soltado después de arrastrar: finalizar teleport player_->finalizeDebugTeleport(); debug_dragging_player_ = false; debug_drag_speed_ = 0.0F; // Reset para el próximo arrastre } } #endif // Escribe el nombre de la pantalla void Game::renderRoomName() { // Dibuja la textura con el nombre de la habitación room_name_surface_->render(nullptr, &room_name_rect_); } // Cambia de habitación auto Game::changeRoom(const std::string& room_path) -> bool { // En las habitaciones los limites tienen la cadena del fichero o un 0 en caso de no limitar con nada if (room_path == "0") { return false; } // Verifica que exista el fichero que se va a cargar if (!Resource::List::get()->get(room_path).empty()) { // Crea un objeto habitación nuevo a partir del fichero room_ = std::make_shared(room_path, scoreboard_data_); // Pone el nombre de la habitación en la textura fillRoomNameTexture(); // Pone el color del marcador en función del color del borde de la habitación setScoreBoardColor(); if (room_tracker_->addRoom(room_path)) { // Incrementa el contador de habitaciones visitadas scoreboard_data_->rooms++; } // Pasa la nueva habitación al jugador player_->setRoom(room_); // Cambia la habitación actual current_room_ = room_path; return true; } return false; } // Comprueba si el jugador esta en el borde de la pantalla void Game::handlePlayerIsOnBorder() { if (player_->isOnBorder()) { const auto BORDER = player_->getBorder(); const auto ROOM_NAME = room_->getRoom(BORDER); // Si puede cambiar de habitación, cambia if (changeRoom(ROOM_NAME)) { player_->switchBorders(); spawn_data_ = player_->getSpawnParams(); return; } // Si ha llegado al fondo y no hay habitación, muere if (BORDER == Room::Border::BOTTOM) { killPlayer(); return; } } } // Comprueba las colisiones del jugador con los enemigos auto Game::handlePlayerAndEnemiesCollisions() -> bool { const bool DEATH = room_->enemyCollision(player_->getCollider()); if (DEATH) { killPlayer(); } return DEATH; } // Comprueba las colisiones del jugador con los objetos void Game::handlePlayerAndItemsCollisions() { room_->itemCollision(player_->getCollider()); } // Comprueba si el jugador esta vivo void Game::handleIfPlayerIsAlive() { if (!player_->isAlive()) { killPlayer(); } } // Mata al jugador void Game::killPlayer() { if (Options::cheats.invincible == Options::Cheat::State::ENABLED) { return; } // Resta una vida al jugador if (Options::cheats.infinite_lives == Options::Cheat::State::DISABLED) { --scoreboard_data_->lives; } // Sonido Audio::get()->playSound(Defaults::Sound::HIT, Audio::Group::GAME); // Transicionar al estado BLACK_SCREEN (el respawn ocurre en transitionToState) transitionToState(State::BLACK_SCREEN); } // Pone el color del marcador en función del color del borde de la habitación void Game::setScoreBoardColor() { // Obtiene el color del borde const Uint8 BORDER_COLOR = room_->getBorderColor(); const bool IS_BLACK = BORDER_COLOR == Color::index(Color::Cpc::BLACK); // Si el color del borde es negro cambia el texto del marcador a blanco scoreboard_data_->color = IS_BLACK ? Color::index(Color::Cpc::WHITE) : BORDER_COLOR; } // Comprueba si ha finalizado el juego auto Game::isGameCompleted() -> bool { const bool IS_ON_THE_ROOM = room_->getName() == "THE JAIL"; // Estar en la habitación que toca const bool HAVE_THE_ITEMS = scoreboard_data_->items >= int(total_items_ * 0.9F); // Con mas del 90% de los items recogidos const bool IS_ON_THE_DOOR = player_->getRect().x <= 128; // Y en la ubicación que toca (En la puerta) if (HAVE_THE_ITEMS && IS_ON_THE_ROOM && IS_ON_THE_DOOR) { // Iniciar transición de fade en vez de cambio inmediato de escena transitionToState(State::FADE_TO_ENDING); Audio::get()->fadeOutMusic(Defaults::Music::FADE_DURATION_MS); // Fade out de música return true; } return false; } // Obtiene la cantidad total de items que hay en el mapeado del juego auto Game::getTotalItems() -> int { int items = 0; auto rooms = Resource::Cache::get()->getRooms(); for (const auto& room : rooms) { items += room.room->items.size(); } return items; } // Pone el juego en pausa void Game::togglePause() { paused_ = !paused_; player_->setPaused(paused_); room_->setPaused(paused_); scoreboard_->setPaused(paused_); } // Da vidas al jugador cuando está en la Jail void Game::restAtJail(float delta_time) { if (room_->getName() != "THE JAIL" || scoreboard_data_->lives == 9) { jail_restore_time_ = 0.0F; // Reset timer cuando no está en la Jail return; } if (!paused_) { jail_restore_time_ += delta_time; } // Incrementa el numero de vidas if (jail_restore_time_ >= JAIL_RESTORE_INTERVAL) { jail_restore_time_ -= JAIL_RESTORE_INTERVAL; // Mantiene el excedente para precisión scoreboard_data_->lives++; Audio::get()->playSound(Defaults::Sound::HIT, Audio::Group::GAME); } } // Crea la textura con el nombre de la habitación void Game::fillRoomNameTexture() { // Pone la textura como destino de renderizado auto previuos_renderer = Screen::get()->getRendererSurface(); Screen::get()->setRendererSurface(room_name_surface_); // Rellena la textura de color room_name_surface_->clear(stringToColor("white")); // Escribe el texto en la textura auto text = Resource::Cache::get()->getText("smb2"); text->writeDX(Text::CENTER_FLAG | Text::COLOR_FLAG, GameCanvas::CENTER_X, text->getCharacterSize() / 2, room_->getName(), 1, room_->getBGColor()); // Deja el renderizador por defecto Screen::get()->setRendererSurface(previuos_renderer); } // Inicializa al jugador void Game::initPlayer(const Player::SpawnData& spawn_point, std::shared_ptr room) { const Player::Data PLAYER{.spawn_data = spawn_point, .animations_path = "player.yaml", .room = std::move(room)}; player_ = std::make_shared(PLAYER); } // Crea la textura para poner el nombre de la habitación void Game::createRoomNameTexture() { auto text = Resource::Cache::get()->getText("smb2"); room_name_surface_ = std::make_shared(Options::game.width, text->getCharacterSize() * 2); // Establece el destino de la textura room_name_rect_ = {.x = 0.0F, .y = PlayArea::HEIGHT, .w = Options::game.width, .h = text->getCharacterSize() * 2.0F}; } // Hace sonar la música void Game::keepMusicPlaying() { const std::string MUSIC_PATH = mode_ == Mode::GAME ? Defaults::Music::GAME_TRACK : Defaults::Music::TITLE_TRACK; // Si la música no está sonando if (Audio::get()->getMusicState() == Audio::MusicState::STOPPED) { Audio::get()->playMusic(MUSIC_PATH); } } // DEMO MODE: Inicializa las variables para el modo demo void Game::demoInit() { if (mode_ == Mode::DEMO) { demo_ = DemoData(0.0F, 0, {"04.yaml", "54.yaml", "20.yaml", "09.yaml", "05.yaml", "11.yaml", "31.yaml", "44.yaml"}); current_room_ = demo_.rooms.front(); } } // DEMO MODE: Comprueba si se ha de cambiar de habitación void Game::demoCheckRoomChange(float delta_time) { if (mode_ == Mode::DEMO) { demo_.time_accumulator += delta_time; if (demo_.time_accumulator >= DEMO_ROOM_DURATION) { demo_.time_accumulator = 0.0F; demo_.room_index++; if (demo_.room_index == (int)demo_.rooms.size()) { SceneManager::current = SceneManager::Scene::LOGO; SceneManager::options = SceneManager::Options::NONE; } else { changeRoom(demo_.rooms[demo_.room_index]); } } } }