From 03a7bbc6d195d9f274161a60a4325f8d1975b103 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Fri, 25 Jul 2025 20:54:00 +0200 Subject: [PATCH] =?UTF-8?q?Player:=20afegides=20animacions=20per=20al=20es?= =?UTF-8?q?tat=20WAITING=20Player:=20si=20tires=20a=20jugar=20desde=20el?= =?UTF-8?q?=20estat=20WAITING=20passes=20al=20ENTERING=5FSCREEN=20i=20desp?= =?UTF-8?q?res=20sempre=20tens=20inmunitat,=20fins=20i=20tot=20la=20primer?= =?UTF-8?q?a=20volta=20(al=20comen=C3=A7ar=20el=20joc)=20falta:=20arreg?= =?UTF-8?q?=C3=B1ar=20el=20z-order=20per=20al=20estat=20WAITING?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/gfx/player/player.ani | 7 + data/gfx/player/player1.gif | Bin 12170 -> 14350 bytes data/gfx/player/player2.gif | Bin 11988 -> 14217 bytes source/animated_sprite.cpp | 15 +- source/animated_sprite.h | 4 + source/moving_sprite.cpp | 9 +- source/moving_sprite.h | 1 + source/player.cpp | 264 ++++++++++++++++++-------------- source/player.h | 298 ++++++++++++++++++------------------ source/scoreboard.cpp | 104 ++++++------- source/scoreboard.h | 81 +++++----- source/sections/credits.cpp | 8 +- source/sections/game.cpp | 96 ++++++------ source/sections/game.h | 18 +-- source/sections/title.cpp | 8 +- source/tabe.cpp | 56 +++---- source/tabe.h | 204 ++++++++++++------------ 17 files changed, 619 insertions(+), 554 deletions(-) diff --git a/data/gfx/player/player.ani b/data/gfx/player/player.ani index c276435..93ffb89 100644 --- a/data/gfx/player/player.ani +++ b/data/gfx/player/player.ani @@ -118,4 +118,11 @@ name=dead speed=5 loop=0 frames=47,48,49,50,51,52,53 +[/animation] + +[animation] +name=hello +speed=3 +loop=-1 +frames=54,55,56,57,58,59,60,61,62,63,64,64,64,64,64,64,64,64,64,64,64,64,64,65,66,67,68,69,70,71,72,73,73,72,71,70,70,71,72,73,73,72,71,70,70,71,72,73,73,72,71,70,70,71,72,73,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54 [/animation] \ No newline at end of file diff --git a/data/gfx/player/player1.gif b/data/gfx/player/player1.gif index 942481928026446aad965bc87cff9fd6cfe666b4..0c6ae164648bb01e0785b09800e0bd7587c2d68a 100644 GIT binary patch delta 2571 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 delta 374 zcmV-+0g3*OaEf0FM@dFFH(`JPzyXm82a+uD|M`wiaP_U&hd17M9qU@UP>dXvXtUb=X& zykxI8cYd90cIwOuV=a&%K>?F(r!#3AetdZW=ey-u9Udrfv=I+BZ?9TDZ!659&<*HOAg6ojszT8h>|KW z$s?6lLK&inT@+yAk~}(DKqC-3(WR4MUYUZJTv|TZg#l6wp~46wz-b~GQabVG6mrtJ z=bcDCmZun0SWzbtW3nTtp;sk**O)rHDTIS}(WcGRtqD`V#6T UYy$e}FOfK?Dlx2f>PQd(JJ)ii5&!@I diff --git a/data/gfx/player/player2.gif b/data/gfx/player/player2.gif index 31fd0de8af2fa07fe3821a2277127eb5488610c2..6413de799417b553f2d283b257f74294fe1c64af 100644 GIT binary patch delta 2667 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 P3$kID;f5B@5(EG{$PT#p diff --git a/source/animated_sprite.cpp b/source/animated_sprite.cpp index e906502..ad968da 100644 --- a/source/animated_sprite.cpp +++ b/source/animated_sprite.cpp @@ -66,7 +66,7 @@ auto AnimatedSprite::getIndex(const std::string& name) -> int { // Calcula el frame correspondiente a la animación void AnimatedSprite::animate() { - if (animations_[current_animation_].speed == 0) { + if (animations_[current_animation_].speed == 0 || animations_[current_animation_].paused) { return; } @@ -87,7 +87,7 @@ void AnimatedSprite::animate() { // En caso contrario else { // Escoge el frame correspondiente de la animación - setSpriteClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]); + updateSpriteClip(); // Incrementa el contador de la animacion animations_[current_animation_].counter++; @@ -110,10 +110,11 @@ void AnimatedSprite::setCurrentAnimation(const std::string& name, bool reset) { animations_[current_animation_].counter = 0; animations_[current_animation_].completed = false; } else { - animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size()); + animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size() - 1); animations_[current_animation_].counter = animations_[OLD_ANIMATION].counter; animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed; } + updateSpriteClip(); } } @@ -132,6 +133,7 @@ void AnimatedSprite::setCurrentAnimation(int index, bool reset) { animations_[current_animation_].counter = animations_[OLD_ANIMATION].counter; animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed; } + updateSpriteClip(); } } @@ -146,6 +148,8 @@ void AnimatedSprite::resetAnimation() { animations_[current_animation_].current_frame = 0; animations_[current_animation_].counter = 0; animations_[current_animation_].completed = false; + animations_[current_animation_].paused = false; + updateSpriteClip(); } // Carga la animación desde un vector de cadenas @@ -267,3 +271,8 @@ void AnimatedSprite::parseFramesParameter(const std::string& frames_str, Animati void AnimatedSprite::setAnimationSpeed(size_t value) { animations_[current_animation_].speed = value; } + +// Actualiza el spriteClip con el frame correspondiente +void AnimatedSprite::updateSpriteClip() { + setSpriteClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]); +} \ No newline at end of file diff --git a/source/animated_sprite.h b/source/animated_sprite.h index 1a4fa4c..83170d0 100644 --- a/source/animated_sprite.h +++ b/source/animated_sprite.h @@ -25,6 +25,7 @@ struct Animation { bool completed{false}; // Indica si la animación ha finalizado size_t current_frame{0}; // Frame actual en reproducción int counter{0}; // Contador para la animación + bool paused{false}; // La animación no avanza Animation() = default; }; @@ -60,6 +61,8 @@ class AnimatedSprite : public MovingSprite { void resetAnimation(); // Reinicia la animación actual void setAnimationSpeed(size_t value); // Establece la velocidad de la animación auto getAnimationSpeed() const -> size_t { return animations_[current_animation_].speed; } // Obtiene la velocidad de la animación actual + void animtionPause() { animations_[current_animation_].paused = true; } // Detiene la animación + void animationResume() { animations_[current_animation_].paused = false; } // Reanuda la animación // --- Consultas --- auto animationIsCompleted() -> bool; // Comprueba si la animación ha terminado @@ -81,4 +84,5 @@ class AnimatedSprite : public MovingSprite { auto processAnimationBlock(const AnimationsFileBuffer& source, size_t start_index, const AnimationConfig& config) -> size_t; // Procesa un bloque completo de animación static void processAnimationParameter(const std::string& line, Animation& animation, const AnimationConfig& config); // Procesa un parámetro individual de animación static void parseFramesParameter(const std::string& frames_str, Animation& animation, const AnimationConfig& config); // Parsea el parámetro de frames (lista separada por comas) + void updateSpriteClip(); // Actualiza el spriteClip con el frame correspondiente }; \ No newline at end of file diff --git a/source/moving_sprite.cpp b/source/moving_sprite.cpp index 206dc6e..96cd356 100644 --- a/source/moving_sprite.cpp +++ b/source/moving_sprite.cpp @@ -30,6 +30,13 @@ MovingSprite::MovingSprite(std::shared_ptr texture) // Reinicia todas las variables void MovingSprite::clear() { + stop(); + Sprite::clear(); +} + +// Elimina el movimiento del sprite +void MovingSprite::stop() +{ x_ = 0.0F; // Posición en el eje X y_ = 0.0F; // Posición en el eje Y @@ -45,8 +52,6 @@ void MovingSprite::clear() { vertical_zoom_ = 1.0F; // Zoom aplicado a la altura flip_ = SDL_FLIP_NONE; // Establece como se ha de voltear el sprite - - Sprite::clear(); } // Mueve el sprite diff --git a/source/moving_sprite.h b/source/moving_sprite.h index 26ea2c6..5a57842 100644 --- a/source/moving_sprite.h +++ b/source/moving_sprite.h @@ -33,6 +33,7 @@ class MovingSprite : public Sprite { // --- Métodos principales --- virtual void update(); // Actualiza las variables internas del objeto void clear() override; // Reinicia todas las variables a cero + void stop(); // Elimina el movimiento del sprite void render() override; // Muestra el sprite por pantalla // --- Getters de posición y movimiento --- diff --git a/source/player.cpp b/source/player.cpp index 0193fbe..c534875 100644 --- a/source/player.cpp +++ b/source/player.cpp @@ -42,9 +42,8 @@ Player::Player(int id, float x, int y, bool demo, SDL_FRect &play_area, std::vec void Player::init() { // Inicializa variables de estado pos_y_ = default_pos_y_; - walking_state_ = PlayerState::WALKING_STOP; - firing_state_ = PlayerState::FIRING_NONE; - playing_state_ = PlayerState::WAITING; + walking_state_ = State::WALKING_STOP; + firing_state_ = State::FIRING_NONE; power_up_ = false; power_up_counter_ = POWERUP_COUNTER; extra_hit_ = false; @@ -73,12 +72,12 @@ void Player::init() { // Actua en consecuencia de la entrada recibida void Player::setInput(InputAction input) { switch (playing_state_) { - case PlayerState::PLAYING: { + case State::PLAYING: { setInputPlaying(input); break; } - case PlayerState::ENTERING_NAME: - case PlayerState::ENTERING_NAME_GAME_COMPLETED: { + case State::ENTERING_NAME: + case State::ENTERING_NAME_GAME_COMPLETED: { setInputEnteringName(input); break; } @@ -92,29 +91,29 @@ void Player::setInputPlaying(InputAction input) { switch (input) { case InputAction::LEFT: { vel_x_ = -BASE_SPEED; - setWalkingState(PlayerState::WALKING_LEFT); + setWalkingState(State::WALKING_LEFT); break; } case InputAction::RIGHT: { vel_x_ = BASE_SPEED; - setWalkingState(PlayerState::WALKING_RIGHT); + setWalkingState(State::WALKING_RIGHT); break; } case InputAction::FIRE_CENTER: { - setFiringState(PlayerState::FIRING_UP); + setFiringState(State::FIRING_UP); break; } case InputAction::FIRE_LEFT: { - setFiringState(PlayerState::FIRING_LEFT); + setFiringState(State::FIRING_LEFT); break; } case InputAction::FIRE_RIGHT: { - setFiringState(PlayerState::FIRING_RIGHT); + setFiringState(State::FIRING_RIGHT); break; } default: { vel_x_ = 0; - setWalkingState(PlayerState::WALKING_STOP); + setWalkingState(State::WALKING_STOP); break; } } @@ -147,27 +146,30 @@ void Player::setInputEnteringName(InputAction input) { // Mueve el jugador a la posición y animación que le corresponde void Player::move() { switch (playing_state_) { - case PlayerState::PLAYING: + case State::PLAYING: handlePlayingMovement(); break; - case PlayerState::ROLLING: + case State::ROLLING: handleRollingMovement(); break; - case PlayerState::TITLE_ANIMATION: + case State::TITLE_ANIMATION: handleTitleAnimation(); break; - case PlayerState::CONTINUE_TIME_OUT: + case State::CONTINUE_TIME_OUT: handleContinueTimeOut(); break; - case PlayerState::LEAVING_SCREEN: + case State::LEAVING_SCREEN: handleLeavingScreen(); break; - case PlayerState::ENTERING_SCREEN: + case State::ENTERING_SCREEN: handleEnteringScreen(); break; - case PlayerState::CREDITS: + case State::CREDITS: handleCreditsMovement(); break; + case State::WAITING: + handleWaitingMovement(); + break; default: break; } @@ -215,9 +217,9 @@ void Player::handleRollingGroundCollision() { } void Player::handleRollingStop() { - const auto NEXT_PLAYER_STATUS = isEligibleForHighScore() ? PlayerState::ENTERING_NAME : PlayerState::CONTINUE; + const auto NEXT_PLAYER_STATUS = isEligibleForHighScore() ? State::ENTERING_NAME : State::CONTINUE; - const auto NEXT_STATE = demo_ ? PlayerState::LYING_ON_THE_FLOOR_FOREVER : NEXT_PLAYER_STATUS; + const auto NEXT_STATE = demo_ ? State::LYING_ON_THE_FLOOR_FOREVER : NEXT_PLAYER_STATUS; setPlayingState(NEXT_STATE); pos_x_ = player_sprite_->getPosX(); @@ -245,14 +247,15 @@ void Player::handleTitleAnimation() { shiftSprite(); if (pos_x_ == MIN_X || pos_x_ == MAX_X) { - setPlayingState(PlayerState::TITLE_HIDDEN); + setPlayingState(State::TITLE_HIDDEN); } } void Player::handleContinueTimeOut() { // Si el cadaver desaparece por el suelo, cambia de estado if (player_sprite_->getPosY() > play_area_.h) { - setPlayingState(PlayerState::WAITING); + player_sprite_->stop(); + setPlayingState(State::WAITING); } } @@ -267,7 +270,7 @@ void Player::handleLeavingScreen() { shiftSprite(); if (pos_x_ == MIN_X || pos_x_ == MAX_X) { - setPlayingState(PlayerState::GAME_OVER); + setPlayingState(State::GAME_OVER); } } @@ -288,8 +291,7 @@ void Player::handlePlayer1Entering() { pos_x_ += vel_x_; if (pos_x_ > default_pos_x_) { pos_x_ = default_pos_x_; - setPlayingState(PlayerState::PLAYING); - setInvulnerable(false); + setPlayingState(State::RESPAWNING); } } @@ -298,8 +300,7 @@ void Player::handlePlayer2Entering() { pos_x_ += vel_x_; if (pos_x_ < default_pos_x_) { pos_x_ = default_pos_x_; - setPlayingState(PlayerState::PLAYING); - setInvulnerable(false); + setPlayingState(State::RESPAWNING); } } @@ -330,11 +331,19 @@ void Player::handleCreditsLeftMovement() { } } +void Player::handleWaitingMovement() { + ++waiting_counter_; + if (waiting_counter_ == WAITING_COUNTER) { + waiting_counter_ = 0; + player_sprite_->resetAnimation(); + } +} + void Player::updateWalkingStateForCredits() { if (pos_x_ > param.game.game_area.center_x - WIDTH / 2) { - setWalkingState(PlayerState::WALKING_LEFT); + setWalkingState(State::WALKING_LEFT); } else { - setWalkingState(PlayerState::WALKING_RIGHT); + setWalkingState(State::WALKING_RIGHT); } } @@ -374,25 +383,25 @@ void Player::render() { // Establece la animación correspondiente al estado void Player::setAnimation() { switch (playing_state_) { - case PlayerState::PLAYING: - case PlayerState::ENTERING_NAME_GAME_COMPLETED: - case PlayerState::ENTERING_SCREEN: - case PlayerState::LEAVING_SCREEN: - case PlayerState::TITLE_ANIMATION: - case PlayerState::CREDITS: { + case State::PLAYING: + case State::ENTERING_NAME_GAME_COMPLETED: + case State::ENTERING_SCREEN: + case State::LEAVING_SCREEN: + case State::TITLE_ANIMATION: + case State::CREDITS: { // Crea cadenas de texto para componer el nombre de la animación - const std::string WALK_ANIMATION = walking_state_ == PlayerState::WALKING_STOP ? "stand" : "walk"; - const std::string FIRE_ANIMATION = firing_state_ == PlayerState::FIRING_UP ? "-fire-center" : "-fire-side"; - const std::string RECOIL_ANIMATION = firing_state_ == PlayerState::RECOILING_UP ? "-recoil-center" : "-recoil-side"; - const std::string COOL_ANIMATION = firing_state_ == PlayerState::COOLING_UP ? "-cool-center" : "-cool-side"; + const std::string WALK_ANIMATION = walking_state_ == State::WALKING_STOP ? "stand" : "walk"; + const std::string FIRE_ANIMATION = firing_state_ == State::FIRING_UP ? "-fire-center" : "-fire-side"; + const std::string RECOIL_ANIMATION = firing_state_ == State::RECOILING_UP ? "-recoil-center" : "-recoil-side"; + const std::string COOL_ANIMATION = firing_state_ == State::COOLING_UP ? "-cool-center" : "-cool-side"; - const SDL_FlipMode FLIP_WALK = walking_state_ == PlayerState::WALKING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; - const SDL_FlipMode FLIP_FIRE = firing_state_ == PlayerState::FIRING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; - const SDL_FlipMode FLIP_RECOIL = firing_state_ == PlayerState::RECOILING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; - const SDL_FlipMode FLIP_COOL = firing_state_ == PlayerState::COOLING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; + const SDL_FlipMode FLIP_WALK = walking_state_ == State::WALKING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; + const SDL_FlipMode FLIP_FIRE = firing_state_ == State::FIRING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; + const SDL_FlipMode FLIP_RECOIL = firing_state_ == State::RECOILING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; + const SDL_FlipMode FLIP_COOL = firing_state_ == State::COOLING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; // Establece la animación a partir de las cadenas - if (firing_state_ == PlayerState::FIRING_NONE) { + if (firing_state_ == State::FIRING_NONE) { // No esta disparando player_sprite_->setCurrentAnimation(WALK_ANIMATION, false); player_sprite_->setFlip(FLIP_WALK); @@ -413,18 +422,22 @@ void Player::setAnimation() { } break; } - case PlayerState::ROLLING: - case PlayerState::CONTINUE_TIME_OUT: { + case State::WAITING: { + player_sprite_->setCurrentAnimation("hello"); + break; + } + case State::ROLLING: + case State::CONTINUE_TIME_OUT: { player_sprite_->setCurrentAnimation("rolling"); break; } - case PlayerState::LYING_ON_THE_FLOOR_FOREVER: - case PlayerState::ENTERING_NAME: - case PlayerState::CONTINUE: { + case State::LYING_ON_THE_FLOOR_FOREVER: + case State::ENTERING_NAME: + case State::CONTINUE: { player_sprite_->setCurrentAnimation("dead"); break; } - case PlayerState::CELEBRATING: { + case State::CELEBRATING: { player_sprite_->setCurrentAnimation("celebration"); break; } @@ -439,7 +452,7 @@ void Player::setAnimation() { // Actualiza el valor de la variable void Player::updateCooldown() { - if (playing_state_ != PlayerState::PLAYING) { + if (playing_state_ != State::PLAYING) { return; } @@ -488,14 +501,14 @@ void Player::handleCoolingState() { void Player::transitionToRecoiling() { switch (firing_state_) { - case PlayerState::FIRING_LEFT: - setFiringState(PlayerState::RECOILING_LEFT); + case State::FIRING_LEFT: + setFiringState(State::RECOILING_LEFT); break; - case PlayerState::FIRING_RIGHT: - setFiringState(PlayerState::RECOILING_RIGHT); + case State::FIRING_RIGHT: + setFiringState(State::RECOILING_RIGHT); break; - case PlayerState::FIRING_UP: - setFiringState(PlayerState::RECOILING_UP); + case State::FIRING_UP: + setFiringState(State::RECOILING_UP); break; default: break; @@ -504,14 +517,14 @@ void Player::transitionToRecoiling() { void Player::transitionToCooling() { switch (firing_state_) { - case PlayerState::RECOILING_LEFT: - setFiringState(PlayerState::COOLING_LEFT); + case State::RECOILING_LEFT: + setFiringState(State::COOLING_LEFT); break; - case PlayerState::RECOILING_RIGHT: - setFiringState(PlayerState::COOLING_RIGHT); + case State::RECOILING_RIGHT: + setFiringState(State::COOLING_RIGHT); break; - case PlayerState::RECOILING_UP: - setFiringState(PlayerState::COOLING_UP); + case State::RECOILING_UP: + setFiringState(State::COOLING_UP); break; default: break; @@ -519,7 +532,7 @@ void Player::transitionToCooling() { } void Player::completeCooling() { - setFiringState(PlayerState::FIRING_NONE); + setFiringState(State::FIRING_NONE); cooling_state_counter_ = -1; } @@ -547,14 +560,14 @@ void Player::addScore(int score) { // Actualiza el panel del marcador void Player::updateScoreboard() { switch (playing_state_) { - case PlayerState::CONTINUE: { - Scoreboard::get()->setContinue(getScoreBoardPanel(), getContinueCounter()); + case State::CONTINUE: { + Scoreboard::get()->setContinue(scoreboard_panel_, getContinueCounter()); break; } - case PlayerState::ENTERING_NAME: - case PlayerState::ENTERING_NAME_GAME_COMPLETED: { - Scoreboard::get()->setRecordName(getScoreBoardPanel(), enter_name_->getCurrentName()); - Scoreboard::get()->setSelectorPos(getScoreBoardPanel(), getRecordNamePos()); + case State::ENTERING_NAME: + case State::ENTERING_NAME_GAME_COMPLETED: { + Scoreboard::get()->setRecordName(scoreboard_panel_, enter_name_->getCurrentName()); + Scoreboard::get()->setSelectorPos(scoreboard_panel_, getRecordNamePos()); break; } default: @@ -563,55 +576,70 @@ void Player::updateScoreboard() { } // Cambia el modo del marcador -void Player::setScoreboardMode(ScoreboardMode mode) const { +void Player::setScoreboardMode(Scoreboard::Mode mode) const { if (!demo_) { - Scoreboard::get()->setMode(getScoreBoardPanel(), mode); + Scoreboard::get()->setMode(scoreboard_panel_, mode); } } // Establece el estado del jugador en el juego -void Player::setPlayingState(PlayerState state) { +void Player::setPlayingState(State state) { playing_state_ = state; switch (playing_state_) { - case PlayerState::RESPAWNING: { + case State::RESPAWNING: { setInvulnerable(true); addCredit(); playSound("voice_thankyou.wav"); - setPlayingState(PlayerState::PLAYING); + setPlayingState(State::PLAYING); } - case PlayerState::PLAYING: { + case State::PLAYING: { init(); - playing_state_ = PlayerState::PLAYING; - setScoreboardMode(ScoreboardMode::SCORE); + playing_state_ = State::PLAYING; + setScoreboardMode(Scoreboard::Mode::SCORE); Stage::power_can_be_added = true; break; } - case PlayerState::CONTINUE: { + case State::CONTINUE: { // Inicializa el contador de continuar continue_ticks_ = SDL_GetTicks(); continue_counter_ = 9; - setScoreboardMode(ScoreboardMode::CONTINUE); + setScoreboardMode(Scoreboard::Mode::CONTINUE); playSound("continue_clock.wav"); break; } - case PlayerState::WAITING: { - pos_x_ = default_pos_x_; - setScoreboardMode(ScoreboardMode::WAITING); + case State::WAITING: { + switch (id_) { + case 1: + pos_x_ = param.game.game_area.rect.x; + break; + case 2: + pos_x_ = param.game.game_area.rect.w - WIDTH; + break; + default: + pos_x_ = 0; + break; + } + pos_y_ = default_pos_y_; + waiting_counter_ = 0; + shiftSprite(); + player_sprite_->setCurrentAnimation("hello"); + player_sprite_->animtionPause(); + setScoreboardMode(Scoreboard::Mode::WAITING); break; } - case PlayerState::ENTERING_NAME: { - setScoreboardMode(ScoreboardMode::ENTER_NAME); + case State::ENTERING_NAME: { + setScoreboardMode(Scoreboard::Mode::ENTER_NAME); break; } - case PlayerState::SHOWING_NAME: { + case State::SHOWING_NAME: { showing_name_ticks_ = SDL_GetTicks(); - setScoreboardMode(ScoreboardMode::SHOW_NAME); + setScoreboardMode(Scoreboard::Mode::SHOW_NAME); Scoreboard::get()->setRecordName(scoreboard_panel_, last_enter_name_); addScoreToScoreBoard(); break; } - case PlayerState::ROLLING: { + case State::ROLLING: { // Activa la animación de rodar player_sprite_->setCurrentAnimation("rolling"); player_sprite_->setAnimationSpeed(4); @@ -620,52 +648,52 @@ void Player::setPlayingState(PlayerState state) { (rand() % 2 == 0) ? player_sprite_->setVelX(3.3F) : player_sprite_->setVelX(-3.3F); break; } - case PlayerState::TITLE_ANIMATION: { + case State::TITLE_ANIMATION: { // Activa la animación de rodar player_sprite_->setCurrentAnimation("walk"); playSound("voice_thankyou.wav"); break; } - case PlayerState::TITLE_HIDDEN: { + case State::TITLE_HIDDEN: { player_sprite_->setVelX(0.0F); player_sprite_->setVelY(0.0F); break; } - case PlayerState::CONTINUE_TIME_OUT: { + case State::CONTINUE_TIME_OUT: { // Activa la animación de morir player_sprite_->setAccelY(0.2F); player_sprite_->setVelY(-4.0F); player_sprite_->setVelX(0.0F); player_sprite_->setCurrentAnimation("rolling"); player_sprite_->setAnimationSpeed(5); - setScoreboardMode(ScoreboardMode::GAME_OVER); + setScoreboardMode(Scoreboard::Mode::GAME_OVER); playSound("voice_aw_aw_aw.wav"); playSound("jump.wav"); break; } - case PlayerState::GAME_OVER: { - setScoreboardMode(ScoreboardMode::GAME_OVER); + case State::GAME_OVER: { + setScoreboardMode(Scoreboard::Mode::GAME_OVER); break; } - case PlayerState::CELEBRATING: { + case State::CELEBRATING: { game_completed_ = true; - setScoreboardMode(ScoreboardMode::SCORE); + setScoreboardMode(Scoreboard::Mode::SCORE); break; } - case PlayerState::ENTERING_NAME_GAME_COMPLETED: { - setWalkingState(PlayerState::WALKING_STOP); - setFiringState(PlayerState::FIRING_NONE); - setScoreboardMode(ScoreboardMode::ENTER_NAME); + case State::ENTERING_NAME_GAME_COMPLETED: { + setWalkingState(State::WALKING_STOP); + setFiringState(State::FIRING_NONE); + setScoreboardMode(Scoreboard::Mode::ENTER_NAME); break; } - case PlayerState::LEAVING_SCREEN: { + case State::LEAVING_SCREEN: { step_counter_ = 0; - setScoreboardMode(ScoreboardMode::GAME_COMPLETED); + setScoreboardMode(Scoreboard::Mode::GAME_COMPLETED); break; } - case PlayerState::ENTERING_SCREEN: { + case State::ENTERING_SCREEN: { step_counter_ = 0; - setScoreboardMode(ScoreboardMode::SCORE); + setScoreboardMode(Scoreboard::Mode::SCORE); switch (id_) { case 1: pos_x_ = param.game.game_area.rect.x - WIDTH; @@ -680,8 +708,8 @@ void Player::setPlayingState(PlayerState state) { } break; } - case PlayerState::CREDITS: { - vel_x_ = (walking_state_ == PlayerState::WALKING_RIGHT) ? BASE_SPEED : -BASE_SPEED; + case State::CREDITS: { + vel_x_ = (walking_state_ == State::WALKING_RIGHT) ? BASE_SPEED : -BASE_SPEED; break; } default: @@ -709,7 +737,7 @@ void Player::setInvulnerable(bool value) { // Monitoriza el estado void Player::updateInvulnerable() { - if (playing_state_ == PlayerState::PLAYING) { + if (playing_state_ == State::PLAYING) { if (invulnerable_) { if (invulnerable_counter_ > 0) { --invulnerable_counter_; @@ -730,7 +758,7 @@ void Player::setPowerUp() { // Actualiza el valor de la variable void Player::updatePowerUp() { - if (playing_state_ == PlayerState::PLAYING) { + if (playing_state_ == State::PLAYING) { if (power_up_) { --power_up_counter_; power_up_ = power_up_counter_ > 0; @@ -772,7 +800,7 @@ void Player::setPlayerTextures(const std::vector> &text // Actualiza el contador de continue void Player::updateContinueCounter() { - if (playing_state_ == PlayerState::CONTINUE) { + if (playing_state_ == State::CONTINUE) { constexpr int TICKS_SPEED = 1000; if (SDL_GetTicks() - continue_ticks_ > TICKS_SPEED) { decContinueCounter(); @@ -782,7 +810,7 @@ void Player::updateContinueCounter() { // Actualiza el contador de entrar nombre void Player::updateEnterNameCounter() { - if (playing_state_ == PlayerState::ENTERING_NAME || playing_state_ == PlayerState::ENTERING_NAME_GAME_COMPLETED) { + if (playing_state_ == State::ENTERING_NAME || playing_state_ == State::ENTERING_NAME_GAME_COMPLETED) { constexpr int TICKS_SPEED = 1000; if (SDL_GetTicks() - name_entry_ticks_ > TICKS_SPEED) { decNameEntryCounter(); @@ -792,10 +820,10 @@ void Player::updateEnterNameCounter() { // Actualiza el estado de SHOWING_NAME void Player::updateShowingName() { - if (playing_state_ == PlayerState::SHOWING_NAME) { + if (playing_state_ == State::SHOWING_NAME) { constexpr int TICKS_SPEED = 5000; if (SDL_GetTicks() - name_entry_ticks_ > TICKS_SPEED) { - game_completed_ ? setPlayingState(PlayerState::LEAVING_SCREEN) : setPlayingState(PlayerState::CONTINUE); + game_completed_ ? setPlayingState(State::LEAVING_SCREEN) : setPlayingState(State::CONTINUE); } } } @@ -805,7 +833,7 @@ void Player::decContinueCounter() { continue_ticks_ = SDL_GetTicks(); --continue_counter_; if (continue_counter_ < 0) { - setPlayingState(PlayerState::CONTINUE_TIME_OUT); + setPlayingState(State::CONTINUE_TIME_OUT); } else { playSound("continue_clock.wav"); } @@ -824,11 +852,11 @@ void Player::decNameEntryCounter() { (name_entry_idle_counter_ >= param.game.name_entry_idle_time)) { name_entry_total_counter_ = 0; name_entry_idle_counter_ = 0; - if (playing_state_ == PlayerState::ENTERING_NAME) { + if (playing_state_ == State::ENTERING_NAME) { last_enter_name_ = getRecordName(); - setPlayingState(PlayerState::SHOWING_NAME); + setPlayingState(State::SHOWING_NAME); } else { - setPlayingState(PlayerState::LEAVING_SCREEN); + setPlayingState(State::LEAVING_SCREEN); } } } @@ -861,7 +889,7 @@ void Player::playSound(const std::string &name) const { // Indica si se puede dibujar el objeto auto Player::isRenderable() const -> bool { - return !isWaiting() && !isGameOver() && !isTitleHidden(); + return !isGameOver() && !isTitleHidden(); }; // Añade una puntuación a la tabla de records diff --git a/source/player.h b/source/player.h index 1c5f590..4898637 100644 --- a/source/player.h +++ b/source/player.h @@ -10,58 +10,59 @@ #include "enter_name.h" // Para EnterName #include "manage_hiscore_table.h" // Para HiScoreEntry #include "options.h" // Para SettingsOptions, settings +#include "scoreboard.h" // Para Scoreboard #include "utils.h" // Para Circle class Texture; enum class InputAction : int; -enum class ScoreboardMode; - -// --- Estados posibles del jugador --- -enum class PlayerState { - // Estados de movimiento - WALKING_LEFT, // Caminando hacia la izquierda - WALKING_RIGHT, // Caminando hacia la derecha - WALKING_STOP, // Parado, sin moverse - - // Estados de disparo - FIRING_UP, // Disparando hacia arriba - FIRING_LEFT, // Disparando hacia la izquierda - FIRING_RIGHT, // Disparando hacia la derecha - FIRING_NONE, // No está disparando - - // Estados de retroceso tras disparar - RECOILING_UP, // Retroceso tras disparar hacia arriba - RECOILING_LEFT, // Retroceso tras disparar hacia la izquierda - RECOILING_RIGHT, // Retroceso tras disparar hacia la derecha - - // Estados de enfriamiento tras disparar - COOLING_UP, // Enfriando tras disparar hacia arriba - COOLING_LEFT, // Enfriando tras disparar hacia la izquierda - COOLING_RIGHT, // Enfriando tras disparar hacia la derecha - - // Estados generales del jugador - PLAYING, // Está jugando activamente - CONTINUE, // Cuenta atrás para continuar tras perder - CONTINUE_TIME_OUT, // Se ha terminado la cuenta atras para continuar y se retira al jugador de la zona de juego - WAITING, // Esperando para entrar a jugar - ENTERING_NAME, // Introduciendo nombre para la tabla de puntuaciones - SHOWING_NAME, // Mostrando el nombre introducido - ROLLING, // El jugador está muriendo (animación de muerte) - LYING_ON_THE_FLOOR_FOREVER, // El jugador está inconsciente para siempre en el suelo (demo) - GAME_OVER, // Fin de la partida, no puede jugar - CELEBRATING, // Celebrando victoria (pose de victoria) - ENTERING_NAME_GAME_COMPLETED, // Introduciendo nombre tras completar el juego - LEAVING_SCREEN, // Saliendo de la pantalla (animación) - ENTERING_SCREEN, // Entrando a la pantalla (animación) - CREDITS, // Estado para mostrar los créditos del juego - TITLE_ANIMATION, // Animacion para el titulo - TITLE_HIDDEN, // Animacion para el titulo - RESPAWNING, // Tras continuar y volver al juego -}; +enum class Mode; // --- Clase Player --- class Player { public: + // --- Estados posibles del jugador --- + enum class State { + // Estados de movimiento + WALKING_LEFT, // Caminando hacia la izquierda + WALKING_RIGHT, // Caminando hacia la derecha + WALKING_STOP, // Parado, sin moverse + + // Estados de disparo + FIRING_UP, // Disparando hacia arriba + FIRING_LEFT, // Disparando hacia la izquierda + FIRING_RIGHT, // Disparando hacia la derecha + FIRING_NONE, // No está disparando + + // Estados de retroceso tras disparar + RECOILING_UP, // Retroceso tras disparar hacia arriba + RECOILING_LEFT, // Retroceso tras disparar hacia la izquierda + RECOILING_RIGHT, // Retroceso tras disparar hacia la derecha + + // Estados de enfriamiento tras disparar + COOLING_UP, // Enfriando tras disparar hacia arriba + COOLING_LEFT, // Enfriando tras disparar hacia la izquierda + COOLING_RIGHT, // Enfriando tras disparar hacia la derecha + + // Estados generales del jugador + PLAYING, // Está jugando activamente + CONTINUE, // Cuenta atrás para continuar tras perder + CONTINUE_TIME_OUT, // Se ha terminado la cuenta atras para continuar y se retira al jugador de la zona de juego + WAITING, // Esperando para entrar a jugar + ENTERING_NAME, // Introduciendo nombre para la tabla de puntuaciones + SHOWING_NAME, // Mostrando el nombre introducido + ROLLING, // El jugador está muriendo (animación de muerte) + LYING_ON_THE_FLOOR_FOREVER, // El jugador está inconsciente para siempre en el suelo (demo) + GAME_OVER, // Fin de la partida, no puede jugar + CELEBRATING, // Celebrando victoria (pose de victoria) + ENTERING_NAME_GAME_COMPLETED, // Introduciendo nombre tras completar el juego + LEAVING_SCREEN, // Saliendo de la pantalla (animación) + ENTERING_SCREEN, // Entrando a la pantalla (animación) + CREDITS, // Estado para mostrar los créditos del juego + TITLE_ANIMATION, // Animacion para el titulo + TITLE_HIDDEN, // Animacion para el titulo + RESPAWNING, // Tras continuar y volver al juego + }; + // --- Constructor y destructor --- Player(int id, float x, int y, bool demo, SDL_FRect &play_area, std::vector> texture, const std::vector> &animations); ~Player() = default; @@ -92,36 +93,36 @@ class Player { void decScoreMultiplier(); // Decrementa el multiplicador // --- Estados de juego --- - void setPlayingState(PlayerState state); // Cambia el estado de juego - void setInvulnerable(bool value); // Establece el valor del estado de invulnerabilidad - void setPowerUp(); // Activa el modo PowerUp - void updatePowerUp(); // Actualiza el valor de PowerUp - void giveExtraHit(); // Concede un toque extra al jugador - void removeExtraHit(); // Quita el toque extra al jugador - void decContinueCounter(); // Decrementa el contador de continuar + void setPlayingState(State state); // Cambia el estado de juego + void setInvulnerable(bool value); // Establece el valor del estado de invulnerabilidad + void setPowerUp(); // Activa el modo PowerUp + void updatePowerUp(); // Actualiza el valor de PowerUp + void giveExtraHit(); // Concede un toque extra al jugador + void removeExtraHit(); // Quita el toque extra al jugador + void decContinueCounter(); // Decrementa el contador de continuar // --- Getters y comprobaciones de estado --- [[nodiscard]] auto getRecordNamePos() const -> int; // Obtiene la posición que se está editando del nombre del jugador para la tabla de mejores puntuaciones // Comprobación de playing_state - [[nodiscard]] auto isLyingOnTheFloorForever() const -> bool { return playing_state_ == PlayerState::LYING_ON_THE_FLOOR_FOREVER; } - [[nodiscard]] auto isCelebrating() const -> bool { return playing_state_ == PlayerState::CELEBRATING; } - [[nodiscard]] auto isContinue() const -> bool { return playing_state_ == PlayerState::CONTINUE; } - [[nodiscard]] auto isDying() const -> bool { return playing_state_ == PlayerState::ROLLING; } - [[nodiscard]] auto isEnteringName() const -> bool { return playing_state_ == PlayerState::ENTERING_NAME; } - [[nodiscard]] auto isShowingName() const -> bool { return playing_state_ == PlayerState::SHOWING_NAME; } - [[nodiscard]] auto isEnteringNameGameCompleted() const -> bool { return playing_state_ == PlayerState::ENTERING_NAME_GAME_COMPLETED; } - [[nodiscard]] auto isLeavingScreen() const -> bool { return playing_state_ == PlayerState::LEAVING_SCREEN; } - [[nodiscard]] auto isGameOver() const -> bool { return playing_state_ == PlayerState::GAME_OVER; } - [[nodiscard]] auto isPlaying() const -> bool { return playing_state_ == PlayerState::PLAYING; } - [[nodiscard]] auto isWaiting() const -> bool { return playing_state_ == PlayerState::WAITING; } - [[nodiscard]] auto isTitleHidden() const -> bool { return playing_state_ == PlayerState::TITLE_HIDDEN; } + [[nodiscard]] auto isLyingOnTheFloorForever() const -> bool { return playing_state_ == State::LYING_ON_THE_FLOOR_FOREVER; } + [[nodiscard]] auto isCelebrating() const -> bool { return playing_state_ == State::CELEBRATING; } + [[nodiscard]] auto isContinue() const -> bool { return playing_state_ == State::CONTINUE; } + [[nodiscard]] auto isDying() const -> bool { return playing_state_ == State::ROLLING; } + [[nodiscard]] auto isEnteringName() const -> bool { return playing_state_ == State::ENTERING_NAME; } + [[nodiscard]] auto isShowingName() const -> bool { return playing_state_ == State::SHOWING_NAME; } + [[nodiscard]] auto isEnteringNameGameCompleted() const -> bool { return playing_state_ == State::ENTERING_NAME_GAME_COMPLETED; } + [[nodiscard]] auto isLeavingScreen() const -> bool { return playing_state_ == State::LEAVING_SCREEN; } + [[nodiscard]] auto isGameOver() const -> bool { return playing_state_ == State::GAME_OVER; } + [[nodiscard]] auto isPlaying() const -> bool { return playing_state_ == State::PLAYING; } + [[nodiscard]] auto isWaiting() const -> bool { return playing_state_ == State::WAITING; } + [[nodiscard]] auto isTitleHidden() const -> bool { return playing_state_ == State::TITLE_HIDDEN; } // Getters [[nodiscard]] auto canFire() const -> bool { return cant_fire_counter_ <= 0; } [[nodiscard]] auto hasExtraHit() const -> bool { return extra_hit_; } - [[nodiscard]] auto isCooling() const -> bool { return firing_state_ == PlayerState::COOLING_LEFT || firing_state_ == PlayerState::COOLING_UP || firing_state_ == PlayerState::COOLING_RIGHT; } - [[nodiscard]] auto isRecoiling() const -> bool { return firing_state_ == PlayerState::RECOILING_LEFT || firing_state_ == PlayerState::RECOILING_UP || firing_state_ == PlayerState::RECOILING_RIGHT; } + [[nodiscard]] auto isCooling() const -> bool { return firing_state_ == State::COOLING_LEFT || firing_state_ == State::COOLING_UP || firing_state_ == State::COOLING_RIGHT; } + [[nodiscard]] auto isRecoiling() const -> bool { return firing_state_ == State::RECOILING_LEFT || firing_state_ == State::RECOILING_UP || firing_state_ == State::RECOILING_RIGHT; } [[nodiscard]] auto isEligibleForHighScore() const -> bool { return score_ > Options::settings.hi_score_table.back().score; } [[nodiscard]] auto isInvulnerable() const -> bool { return invulnerable_; } [[nodiscard]] auto isPowerUp() const -> bool { return power_up_; } @@ -139,9 +140,9 @@ class Player { [[nodiscard]] auto getRecordName() const -> std::string { return enter_name_ ? enter_name_->getFinalName() : "xxx"; } [[nodiscard]] auto getLastEnterName() const -> std::string { return last_enter_name_; } [[nodiscard]] auto getScore() const -> int { return score_; } - [[nodiscard]] auto getScoreBoardPanel() const -> int { return scoreboard_panel_; } + [[nodiscard]] auto getScoreBoardPanel() const -> Scoreboard::Id { return scoreboard_panel_; } [[nodiscard]] static auto getWidth() -> int { return WIDTH; } - [[nodiscard]] auto getPlayingState() const -> PlayerState { return playing_state_; } + [[nodiscard]] auto getPlayingState() const -> State { return playing_state_; } [[nodiscard]] auto getName() const -> const std::string & { return name_; } [[nodiscard]] auto get1CC() const -> bool { return game_completed_ && credits_used_ == 1; } [[nodiscard]] auto getEnterNamePositionOverflow() const -> bool { return enter_name_ ? enter_name_->getPositionOverflow() : false; } @@ -149,25 +150,26 @@ class Player { // Setters inline void setController(int index) { controller_index_ = index; } void setCantFireCounter(int counter) { recoiling_state_duration_ = cant_fire_counter_ = counter; } - void setFiringState(PlayerState state) { firing_state_ = state; } + void setFiringState(State state) { firing_state_ = state; } void setInvulnerableCounter(int value) { invulnerable_counter_ = value; } void setName(const std::string &name) { name_ = name; } void setPowerUpCounter(int value) { power_up_counter_ = value; } void setScore(int score) { score_ = score; } - void setScoreBoardPanel(int panel) { scoreboard_panel_ = panel; } + void setScoreBoardPanel(Scoreboard::Id panel) { scoreboard_panel_ = panel; } void setScoreMultiplier(float value) { score_multiplier_ = value; } - void setWalkingState(PlayerState state) { walking_state_ = state; } + void setWalkingState(State state) { walking_state_ = state; } void addCredit() { ++credits_used_; } private: // --- Constantes --- static constexpr int POWERUP_COUNTER = 1500; // Duración del estado PowerUp static constexpr int INVULNERABLE_COUNTER = 200; // Duración del estado invulnerable - static constexpr int WIDTH = 30; // Anchura - static constexpr int HEIGHT = 30; // Altura + static constexpr int WIDTH = 32; // Anchura + static constexpr int HEIGHT = 32; // Altura static constexpr float BASE_SPEED = 1.5F; // Velocidad base del jugador static constexpr int COOLING_DURATION = 50; static constexpr int COOLING_COMPLETE = 0; + static constexpr int WAITING_COUNTER = 1000; // --- Objetos y punteros --- std::unique_ptr player_sprite_; // Sprite para dibujar el jugador @@ -175,81 +177,83 @@ class Player { std::unique_ptr enter_name_; // Clase utilizada para introducir el nombre // --- Variables de estado --- - int id_; // Número de identificación para el jugador. Player1 = 1, Player2 = 2 - SDL_FRect play_area_; // Rectángulo con la zona de juego - float pos_x_ = 0.0F; // Posición en el eje X - int pos_y_ = 0; // Posición en el eje Y - float default_pos_x_; // Posición inicial para el jugador - int default_pos_y_; // Posición inicial para el jugador - float vel_x_ = 0.0F; // Cantidad de píxeles a desplazarse en el eje X - int vel_y_ = 0.0F; // Cantidad de píxeles a desplazarse en el eje Y - int cant_fire_counter_ = 0; // Contador durante el cual no puede disparar - int recoiling_state_counter_ = 0; // Contador para la animación del estado de retroceso - int recoiling_state_duration_ = 0; // Numero de frames que dura el estado de retroceso - int cooling_state_counter_ = 0; // Contador para la animación del estado cooling - int score_ = 0; // Puntos del jugador - float score_multiplier_ = 1.0F; // Multiplicador de puntos - PlayerState walking_state_ = PlayerState::WALKING_STOP; // Estado del jugador al moverse - PlayerState firing_state_ = PlayerState::FIRING_NONE; // Estado del jugador al disparar - PlayerState playing_state_ = PlayerState::WAITING; // Estado del jugador en el juego - bool invulnerable_ = true; // Indica si el jugador es invulnerable - int invulnerable_counter_ = INVULNERABLE_COUNTER; // Contador para la invulnerabilidad - bool extra_hit_ = false; // Indica si el jugador tiene un toque extra - int coffees_ = 0; // Indica cuántos cafés lleva acumulados - bool power_up_ = false; // Indica si el jugador tiene activo el modo PowerUp - int power_up_counter_ = POWERUP_COUNTER; // Temporizador para el modo PowerUp - int power_up_x_offset_ = 0; // Desplazamiento del sprite de PowerUp respecto al sprite del jugador - Circle collider_ = Circle(0, 0, 9); // Círculo de colisión del jugador - int continue_counter_ = 10; // Contador para poder continuar - Uint32 continue_ticks_ = 0; // Variable para poder cambiar el contador de continue en función del tiempo - int scoreboard_panel_ = 0; // Panel del marcador asociado al jugador - std::string name_; // Nombre del jugador - int controller_index_ = 0; // Índice del array de mandos que utilizará para moverse - bool demo_ = false; // Para que el jugador sepa si está en el modo demostración - int name_entry_idle_counter_ = 0; // Contador para poner nombre - int name_entry_total_counter_ = 0; // Segundos totales que lleva acumulados poniendo nombre - Uint32 name_entry_ticks_ = 0; // Variable para poder cambiar el contador de poner nombre en función del tiempo - Uint32 showing_name_ticks_ = 0; // Tiempo en el que se entra al estado SHOWING_NAME - int step_counter_ = 0; // Cuenta los pasos para los estados en los que camina automáticamente - bool game_completed_ = false; // Indica si ha completado el juego - int credits_used_ = 1; // Indica el número de veces que ha continuado - std::string last_enter_name_; // Último nombre introducido en la tabla de puntuaciones + int id_; // Número de identificación para el jugador. Player1 = 1, Player2 = 2 + SDL_FRect play_area_; // Rectángulo con la zona de juego + float pos_x_ = 0.0F; // Posición en el eje X + int pos_y_ = 0; // Posición en el eje Y + float default_pos_x_; // Posición inicial para el jugador + int default_pos_y_; // Posición inicial para el jugador + float vel_x_ = 0.0F; // Cantidad de píxeles a desplazarse en el eje X + int vel_y_ = 0.0F; // Cantidad de píxeles a desplazarse en el eje Y + int cant_fire_counter_ = 0; // Contador durante el cual no puede disparar + int recoiling_state_counter_ = 0; // Contador para la animación del estado de retroceso + int recoiling_state_duration_ = 0; // Numero de frames que dura el estado de retroceso + int cooling_state_counter_ = 0; // Contador para la animación del estado cooling + int score_ = 0; // Puntos del jugador + float score_multiplier_ = 1.0F; // Multiplicador de puntos + State walking_state_ = State::WALKING_STOP; // Estado del jugador al moverse + State firing_state_ = State::FIRING_NONE; // Estado del jugador al disparar + State playing_state_ = State::WAITING; // Estado del jugador en el juego + bool invulnerable_ = true; // Indica si el jugador es invulnerable + int invulnerable_counter_ = INVULNERABLE_COUNTER; // Contador para la invulnerabilidad + bool extra_hit_ = false; // Indica si el jugador tiene un toque extra + int coffees_ = 0; // Indica cuántos cafés lleva acumulados + bool power_up_ = false; // Indica si el jugador tiene activo el modo PowerUp + int power_up_counter_ = POWERUP_COUNTER; // Temporizador para el modo PowerUp + int power_up_x_offset_ = 0; // Desplazamiento del sprite de PowerUp respecto al sprite del jugador + Circle collider_ = Circle(0, 0, 9); // Círculo de colisión del jugador + int continue_counter_ = 10; // Contador para poder continuar + Uint32 continue_ticks_ = 0; // Variable para poder cambiar el contador de continue en función del tiempo + Scoreboard::Id scoreboard_panel_ = Scoreboard::Id::LEFT; // Panel del marcador asociado al jugador + std::string name_; // Nombre del jugador + int controller_index_ = 0; // Índice del array de mandos que utilizará para moverse + bool demo_ = false; // Para que el jugador sepa si está en el modo demostración + int name_entry_idle_counter_ = 0; // Contador para poner nombre + int name_entry_total_counter_ = 0; // Segundos totales que lleva acumulados poniendo nombre + Uint32 name_entry_ticks_ = 0; // Variable para poder cambiar el contador de poner nombre en función del tiempo + Uint32 showing_name_ticks_ = 0; // Tiempo en el que se entra al estado SHOWING_NAME + int step_counter_ = 0; // Cuenta los pasos para los estados en los que camina automáticamente + bool game_completed_ = false; // Indica si ha completado el juego + int credits_used_ = 1; // Indica el número de veces que ha continuado + std::string last_enter_name_; // Último nombre introducido en la tabla de puntuaciones + int waiting_counter_ = 0; // Contador para el estado de espera // --- Métodos internos --- - void shiftColliders(); // Actualiza el círculo de colisión a la posición del jugador - void shiftSprite(); // Recoloca el sprite - void updateInvulnerable(); // Monitoriza el estado de invulnerabilidad - void updateContinueCounter(); // Actualiza el contador de continue - void updateEnterNameCounter(); // Actualiza el contador de entrar nombre - void updateShowingName(); // Actualiza el estado SHOWING_NAME - void decNameEntryCounter(); // Decrementa el contador de entrar nombre - void updateScoreboard(); // Actualiza el panel del marcador - void setScoreboardMode(ScoreboardMode mode) const; // Cambia el modo del marcador - void playSound(const std::string &name) const; // Hace sonar un sonido - [[nodiscard]] auto isRenderable() const -> bool; // Indica si se puede dibujar el objeto - void addScoreToScoreBoard() const; // Añade una puntuación a la tabla de records - void handleFiringCooldown(); // Gestiona el tiempo de espera después de disparar antes de permitir otro disparo - void handleRecoilAndCooling(); // Procesa simultáneamente el retroceso del arma y la transición al estado de enfriamiento si aplica - void handleCoolingState(); // Actualiza la lógica interna mientras el sistema está en estado de enfriamiento - void transitionToRecoiling(); // Cambia el estado actual al de retroceso después de disparar - void transitionToCooling(); // Cambia el estado actual al de enfriamiento (por ejemplo, tras una ráfaga o sobrecalentamiento) - void completeCooling(); // Finaliza el proceso de enfriamiento y restablece el estado listo para disparar - void handlePlayingMovement(); // Gestiona el movimiento del personaje u objeto durante el estado de juego activo - void handleRollingMovement(); // Actualiza la lógica de movimiento de "rodar" (posiblemente tras impacto o acción especial) - void handleRollingBoundaryCollision(); // Detecta y maneja colisiones del objeto rodante con los límites de la pantalla - void handleRollingGroundCollision(); // Gestiona la interacción del objeto rodante con el suelo (rebotes, frenado, etc.) - void handleRollingStop(); // Detiene el movimiento del objeto rodante cuando se cumplen las condiciones necesarias - void handleRollingBounce(); // Aplica una lógica de rebote al colisionar con superficies durante el rodamiento - void handleTitleAnimation(); // Ejecuta la animación del título en pantalla (ej. entrada, parpadeo o desplazamiento) - void handleContinueTimeOut(); // Gestiona el tiempo de espera en la pantalla de "Continuar" y decide si pasar a otro estado - void handleLeavingScreen(); // Lógica para salir de la pantalla actual (transición visual o cambio de escena) - void handleEnteringScreen(); // Lógica para entrar en una nueva pantalla, posiblemente con animación o retraso - void handlePlayer1Entering(); // Controla la animación o posición de entrada del Jugador 1 en pantalla - void handlePlayer2Entering(); // Controla la animación o posición de entrada del Jugador 2 en pantalla - void handleCreditsMovement(); // Movimiento general en la pantalla de créditos (desplazamiento vertical u horizontal) - void handleCreditsRightMovement(); // Lógica específica para mover los créditos hacia la derecha - void handleCreditsLeftMovement(); // Lógica específica para mover los créditos hacia la izquierda - void updateWalkingStateForCredits(); // Actualiza el estado de caminata de algún personaje u elemento animado en los créditos - void setInputBasedOnPlayerId(); // Asocia las entradas de control en función del identificador del jugador (teclas, mando, etc.) - void updateStepCounter(); // Incrementa o ajusta el contador de pasos para animaciones o mecánicas relacionadas con movimiento + void shiftColliders(); // Actualiza el círculo de colisión a la posición del jugador + void shiftSprite(); // Recoloca el sprite + void updateInvulnerable(); // Monitoriza el estado de invulnerabilidad + void updateContinueCounter(); // Actualiza el contador de continue + void updateEnterNameCounter(); // Actualiza el contador de entrar nombre + void updateShowingName(); // Actualiza el estado SHOWING_NAME + void decNameEntryCounter(); // Decrementa el contador de entrar nombre + void updateScoreboard(); // Actualiza el panel del marcador + void setScoreboardMode(Scoreboard::Mode mode) const; // Cambia el modo del marcador + void playSound(const std::string &name) const; // Hace sonar un sonido + [[nodiscard]] auto isRenderable() const -> bool; // Indica si se puede dibujar el objeto + void addScoreToScoreBoard() const; // Añade una puntuación a la tabla de records + void handleFiringCooldown(); // Gestiona el tiempo de espera después de disparar antes de permitir otro disparo + void handleRecoilAndCooling(); // Procesa simultáneamente el retroceso del arma y la transición al estado de enfriamiento si aplica + void handleCoolingState(); // Actualiza la lógica interna mientras el sistema está en estado de enfriamiento + void transitionToRecoiling(); // Cambia el estado actual al de retroceso después de disparar + void transitionToCooling(); // Cambia el estado actual al de enfriamiento (por ejemplo, tras una ráfaga o sobrecalentamiento) + void completeCooling(); // Finaliza el proceso de enfriamiento y restablece el estado listo para disparar + void handlePlayingMovement(); // Gestiona el movimiento del personaje u objeto durante el estado de juego activo + void handleRollingMovement(); // Actualiza la lógica de movimiento de "rodar" (posiblemente tras impacto o acción especial) + void handleRollingBoundaryCollision(); // Detecta y maneja colisiones del objeto rodante con los límites de la pantalla + void handleRollingGroundCollision(); // Gestiona la interacción del objeto rodante con el suelo (rebotes, frenado, etc.) + void handleRollingStop(); // Detiene el movimiento del objeto rodante cuando se cumplen las condiciones necesarias + void handleRollingBounce(); // Aplica una lógica de rebote al colisionar con superficies durante el rodamiento + void handleTitleAnimation(); // Ejecuta la animación del título en pantalla (ej. entrada, parpadeo o desplazamiento) + void handleContinueTimeOut(); // Gestiona el tiempo de espera en la pantalla de "Continuar" y decide si pasar a otro estado + void handleLeavingScreen(); // Lógica para salir de la pantalla actual (transición visual o cambio de escena) + void handleEnteringScreen(); // Lógica para entrar en una nueva pantalla, posiblemente con animación o retraso + void handlePlayer1Entering(); // Controla la animación o posición de entrada del Jugador 1 en pantalla + void handlePlayer2Entering(); // Controla la animación o posición de entrada del Jugador 2 en pantalla + void handleCreditsMovement(); // Movimiento general en la pantalla de créditos (desplazamiento vertical u horizontal) + void handleCreditsRightMovement(); // Lógica específica para mover los créditos hacia la derecha + void handleCreditsLeftMovement(); // Lógica específica para mover los créditos hacia la izquierda + void handleWaitingMovement(); // Controla la animación del jugador saludando + void updateWalkingStateForCredits(); // Actualiza el estado de caminata de algún personaje u elemento animado en los créditos + void setInputBasedOnPlayerId(); // Asocia las entradas de control en función del identificador del jugador (teclas, mando, etc.) + void updateStepCounter(); // Incrementa o ajusta el contador de pasos para animaciones o mecánicas relacionadas con movimiento }; \ No newline at end of file diff --git a/source/scoreboard.cpp b/source/scoreboard.cpp index a16e928..d58a09e 100644 --- a/source/scoreboard.cpp +++ b/source/scoreboard.cpp @@ -17,20 +17,20 @@ #include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR #include "texture.h" // Para Texture -// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado +// .at(SINGLETON) Hay que definir las variables estáticas, desde el .h sólo la hemos declarado Scoreboard *Scoreboard::instance = nullptr; -// [SINGLETON] Crearemos el objeto score_board con esta función estática +// .at(SINGLETON) Crearemos el objeto score_board con esta función estática void Scoreboard::init() { Scoreboard::instance = new Scoreboard(); } -// [SINGLETON] Destruiremos el objeto score_board con esta función estática +// .at(SINGLETON) Destruiremos el objeto score_board con esta función estática void Scoreboard::destroy() { delete Scoreboard::instance; } -// [SINGLETON] Con este método obtenemos el objeto score_board y podemos trabajar con él +// .at(SINGLETON) Con este método obtenemos el objeto score_board y podemos trabajar con él auto Scoreboard::get() -> Scoreboard * { return Scoreboard::instance; } @@ -42,18 +42,18 @@ Scoreboard::Scoreboard() power_meter_sprite_(std::make_unique(game_power_meter_texture_)), text_scoreboard_(Resource::get()->getText("8bithud")) { // Inicializa variables - for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) { - name_[i].clear(); - record_name_[i].clear(); - selector_pos_[i] = 0; - score_[i] = 0; - mult_[i] = 0; - continue_counter_[i] = 0; + for (size_t i = 0; i < static_cast(Id::SIZE); ++i) { + name_.at(i).clear(); + record_name_.at(i).clear(); + selector_pos_.at(i) = 0; + score_.at(i) = 0; + mult_.at(i) = 0; + continue_counter_.at(i) = 0; } - panel_[SCOREBOARD_LEFT_PANEL].mode = ScoreboardMode::SCORE; - panel_[SCOREBOARD_RIGHT_PANEL].mode = ScoreboardMode::SCORE; - panel_[SCOREBOARD_CENTER_PANEL].mode = ScoreboardMode::STAGE_INFO; + panel_.at(static_cast(Id::LEFT)).mode = Mode::SCORE; + panel_.at(static_cast(Id::RIGHT)).mode = Mode::SCORE; + panel_.at(static_cast(Id::CENTER)).mode = Mode::STAGE_INFO; // Recalcula las anclas de los elementos recalculateAnchors(); @@ -147,9 +147,9 @@ void Scoreboard::fillPanelTextures() { auto *temp = SDL_GetRenderTarget(renderer_); // Genera el contenido de cada panel_ - for (size_t i = 0; i < SCOREBOARD_MAX_PANELS; ++i) { + for (size_t i = 0; i < static_cast(Id::SIZE); ++i) { // Cambia el destino del renderizador - SDL_SetRenderTarget(renderer_, panel_texture_[i]); + SDL_SetRenderTarget(renderer_, panel_texture_.at(i)); // Dibuja el fondo de la textura SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0); @@ -163,32 +163,32 @@ void Scoreboard::fillPanelTextures() { } void Scoreboard::renderPanelContent(size_t panel_index) { - switch (panel_[panel_index].mode) { - case ScoreboardMode::SCORE: + switch (panel_.at(panel_index).mode) { + case Mode::SCORE: renderScoreMode(panel_index); break; - case ScoreboardMode::DEMO: + case Mode::DEMO: renderDemoMode(); break; - case ScoreboardMode::WAITING: + case Mode::WAITING: renderWaitingMode(); break; - case ScoreboardMode::GAME_OVER: + case Mode::GAME_OVER: renderGameOverMode(); break; - case ScoreboardMode::STAGE_INFO: + case Mode::STAGE_INFO: renderStageInfoMode(); break; - case ScoreboardMode::CONTINUE: + case Mode::CONTINUE: renderContinueMode(panel_index); break; - case ScoreboardMode::ENTER_NAME: + case Mode::ENTER_NAME: renderEnterNameMode(panel_index); break; - case ScoreboardMode::SHOW_NAME: + case Mode::SHOW_NAME: renderShowNameMode(panel_index); break; - case ScoreboardMode::GAME_COMPLETED: + case Mode::GAME_COMPLETED: renderGameCompletedMode(panel_index); break; default: @@ -198,12 +198,12 @@ void Scoreboard::renderPanelContent(size_t panel_index) { void Scoreboard::renderScoreMode(size_t panel_index) { // SCORE - text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_1_.x, slot4_1_.y, name_[panel_index], 1, text_color1_); - text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_2_.x, slot4_2_.y, updateScoreText(score_[panel_index]), 1, text_color2_); + text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_1_.x, slot4_1_.y, name_.at(panel_index), 1, text_color1_); + text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_2_.x, slot4_2_.y, updateScoreText(score_.at(panel_index)), 1, text_color2_); // MULT text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 3"), 1, text_color1_); - text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_4_.x, slot4_4_.y, "x" + std::to_string(mult_[panel_index]).substr(0, 3), 1, text_color2_); + text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_4_.x, slot4_4_.y, "x" + std::to_string(mult_.at(panel_index)).substr(0, 3), 1, text_color2_); } void Scoreboard::renderDemoMode() { @@ -257,18 +257,18 @@ void Scoreboard::renderStageInfoMode() { void Scoreboard::renderContinueMode(size_t panel_index) { // SCORE - text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y, name_[panel_index], 1, text_color1_); - text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_2_.x, slot4_2_.y, updateScoreText(score_[panel_index]), 1, text_color2_); + text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y, name_.at(panel_index), 1, text_color1_); + text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_2_.x, slot4_2_.y, updateScoreText(score_.at(panel_index)), 1, text_color2_); // CONTINUE text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 10"), 1, text_color1_); - text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y, std::to_string(continue_counter_[panel_index]), 1, text_color2_); + text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y, std::to_string(continue_counter_.at(panel_index)), 1, text_color2_); } void Scoreboard::renderEnterNameMode(size_t panel_index) { // SCORE - text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y, name_[panel_index], 1, text_color1_); - text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_2_.x, slot4_2_.y, updateScoreText(score_[panel_index]), 1, text_color2_); + text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y, name_.at(panel_index), 1, text_color1_); + text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_2_.x, slot4_2_.y, updateScoreText(score_.at(panel_index)), 1, text_color2_); // ENTER NAME text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 11"), 1, text_color1_); @@ -282,18 +282,18 @@ void Scoreboard::renderNameInputField(size_t panel_index) { // Recorre todos los slots de letras del nombre for (size_t j = 0; j < NAME_SIZE; ++j) { // Selecciona el color - const Color COLOR = j < selector_pos_[panel_index] ? text_color2_ : text_color1_; + const Color COLOR = j < selector_pos_.at(panel_index) ? text_color2_ : text_color1_; - if (j != selector_pos_[panel_index] || time_counter_ % 3 == 0) { + if (j != selector_pos_.at(panel_index) || time_counter_ % 3 == 0) { // Dibuja la linea - if (j >= selector_pos_[panel_index]) { + if (j >= selector_pos_.at(panel_index)) { SDL_SetRenderDrawColor(renderer_, COLOR.r, COLOR.g, COLOR.b, 255); SDL_RenderLine(renderer_, rect.x, rect.y + rect.h, rect.x + rect.w, rect.y + rect.h); } // Dibuja la letra - if (j < record_name_[panel_index].size()) { - text_scoreboard_->writeColored(rect.x, rect.y, record_name_[panel_index].substr(j, 1), COLOR); + if (j < record_name_.at(panel_index).size()) { + text_scoreboard_->writeColored(rect.x, rect.y, record_name_.at(panel_index).substr(j, 1), COLOR); } } rect.x += 7; @@ -302,17 +302,17 @@ void Scoreboard::renderNameInputField(size_t panel_index) { void Scoreboard::renderShowNameMode(size_t panel_index) { // SCORE - text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y, name_[panel_index], 1, text_color1_); - text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_2_.x, slot4_2_.y, updateScoreText(score_[panel_index]), 1, text_color2_); + text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y, name_.at(panel_index), 1, text_color1_); + text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_2_.x, slot4_2_.y, updateScoreText(score_.at(panel_index)), 1, text_color2_); // NAME text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 11"), 1, text_color1_); /* TEXTO CENTRADO */ - text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y, record_name_[panel_index], 1, getColorLikeKnightRider(name_colors_, loop_counter_ / 5)); + text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y, record_name_.at(panel_index), 1, getColorLikeKnightRider(name_colors_, loop_counter_ / 5)); /* TEXTO A LA IZQUIERDA */ - // text_scoreboard_->writeColored(enter_name_pos_.x, enter_name_pos_.y, record_name_[panelIndex], getColorLikeKnightRider(name_colors_, loop_counter_ / 5)); + // text_scoreboard_->writeColored(enter_name_pos_.x, enter_name_pos_.y, record_name_.at(panelIndex), getColorLikeKnightRider(name_colors_, loop_counter_ / 5)); } void Scoreboard::renderGameCompletedMode(size_t panel_index) { @@ -322,7 +322,7 @@ void Scoreboard::renderGameCompletedMode(size_t panel_index) { // SCORE if (time_counter_ % 10 < 8) { text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y - 2, Lang::getText("[SCOREBOARD] 14"), 1, text_color1_); - text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y - 2, updateScoreText(score_[panel_index]), 1, text_color2_); + text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y - 2, updateScoreText(score_.at(panel_index)), 1, text_color2_); } } @@ -340,8 +340,8 @@ void Scoreboard::fillBackgroundTexture() { SDL_RenderClear(renderer_); // Copia las texturas de los paneles - for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) { - SDL_RenderTexture(renderer_, panel_texture_[i], nullptr, &panel_[i].pos); + for (int i = 0; i < static_cast(Id::SIZE); ++i) { + SDL_RenderTexture(renderer_, panel_texture_.at(i), nullptr, &panel_.at(i).pos); } // Dibuja la linea que separa la zona de juego del marcador @@ -354,12 +354,12 @@ void Scoreboard::fillBackgroundTexture() { // Recalcula las anclas de los elementos void Scoreboard::recalculateAnchors() { // Recalcula la posición y el tamaño de los paneles - const float PANEL_WIDTH = rect_.w / (float)SCOREBOARD_MAX_PANELS; - for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) { - panel_[i].pos.x = roundf(PANEL_WIDTH * i); - panel_[i].pos.y = 0; - panel_[i].pos.w = roundf(PANEL_WIDTH * (i + 1)) - panel_[i].pos.x; - panel_[i].pos.h = rect_.h; + const float PANEL_WIDTH = rect_.w / (float)static_cast(Id::SIZE); + for (int i = 0; i < static_cast(Id::SIZE); ++i) { + panel_.at(i).pos.x = roundf(PANEL_WIDTH * i); + panel_.at(i).pos.y = 0; + panel_.at(i).pos.w = roundf(PANEL_WIDTH * (i + 1)) - panel_.at(i).pos.x; + panel_.at(i).pos.h = rect_.h; } // Constantes para definir las zonas del panel_: 4 filas y 1 columna diff --git a/source/scoreboard.h b/source/scoreboard.h index 8778393..c9a4ebf 100644 --- a/source/scoreboard.h +++ b/source/scoreboard.h @@ -14,35 +14,36 @@ class Sprite; class Text; class Texture; -// --- Defines --- -constexpr int SCOREBOARD_LEFT_PANEL = 0; -constexpr int SCOREBOARD_CENTER_PANEL = 1; -constexpr int SCOREBOARD_RIGHT_PANEL = 2; -constexpr int SCOREBOARD_MAX_PANELS = 3; - -// --- Enums --- -enum class ScoreboardMode : int { - SCORE, - STAGE_INFO, - CONTINUE, - WAITING, - GAME_OVER, - DEMO, - ENTER_NAME, - SHOW_NAME, - GAME_COMPLETED, - NUM_MODES, -}; - -// --- Structs --- -struct Panel { - ScoreboardMode mode; // Modo en el que se encuentra el panel - SDL_FRect pos; // Posición donde dibujar el panel dentro del marcador -}; - // --- Clase Scoreboard --- class Scoreboard { public: + // --- Enums --- + enum class Id : size_t { + LEFT = 0, + CENTER = 1, + RIGHT = 2, + SIZE = 3 + }; + + enum class Mode : int { + SCORE, + STAGE_INFO, + CONTINUE, + WAITING, + GAME_OVER, + DEMO, + ENTER_NAME, + SHOW_NAME, + GAME_COMPLETED, + NUM_MODES, + }; + + // --- Structs --- + struct Panel { + Mode mode; // Modo en el que se encuentra el panel + SDL_FRect pos; // Posición donde dibujar el panel dentro del marcador + }; + // --- Métodos de singleton --- static void init(); // Crea el objeto Scoreboard static void destroy(); // Libera el objeto Scoreboard @@ -55,16 +56,16 @@ class Scoreboard { // --- Setters --- void setColor(Color color); // Establece el color del marcador void setPos(SDL_FRect rect); // Establece la posición y tamaño del marcador - void setContinue(int panel, int continue_counter) { continue_counter_[panel] = continue_counter; } + void setContinue(Id id, int continue_counter) { continue_counter_.at(static_cast(id)) = continue_counter; } void setHiScore(int hi_score) { hi_score_ = hi_score; } void setHiScoreName(const std::string &name) { hi_score_name_ = name; } - void setMode(int index, ScoreboardMode mode) { panel_[index].mode = mode; } - void setMult(int panel, float mult) { mult_[panel] = mult; } - void setName(int panel, const std::string &name) { name_[panel] = name; } + void setMode(Id id, Mode mode) { panel_.at(static_cast(id)).mode = mode; } + void setMult(Id id, float mult) { mult_.at(static_cast(id)) = mult; } + void setName(Id id, const std::string &name) { name_.at(static_cast(id)) = name; } void setPower(float power) { power_ = power; } - void setRecordName(int panel, const std::string &record_name) { record_name_[panel] = record_name; } - void setScore(int panel, int score) { score_[panel] = score; } - void setSelectorPos(int panel, int pos) { selector_pos_[panel] = pos; } + void setRecordName(Id id, const std::string &record_name) { record_name_.at(static_cast(id)) = record_name; } + void setScore(Id id, int score) { score_.at(static_cast(id)) = score; } + void setSelectorPos(Id id, int pos) { selector_pos_.at(static_cast(id)) = pos; } void setStage(int stage) { stage_ = stage; } private: @@ -77,13 +78,13 @@ class Scoreboard { std::vector panel_texture_; // Texturas para dibujar cada panel // --- Variables de estado --- - std::array name_ = {}; // Nombre de cada jugador - std::array record_name_ = {}; // Nombre introducido para la tabla de records - std::array selector_pos_ = {}; // Posición del selector de letra para introducir el nombre - std::array score_ = {}; // Puntuación de los jugadores - std::array mult_ = {}; // Multiplicador de los jugadores - std::array continue_counter_ = {}; // Tiempo para continuar de los jugadores - std::array panel_ = {}; // Lista con todos los paneles del marcador + std::array(Id::SIZE)> name_ = {}; // Nombre de cada jugador + std::array(Id::SIZE)> record_name_ = {}; // Nombre introducido para la tabla de records + std::array(Id::SIZE)> selector_pos_ = {}; // Posición del selector de letra para introducir el nombre + std::array(Id::SIZE)> score_ = {}; // Puntuación de los jugadores + std::array(Id::SIZE)> mult_ = {}; // Multiplicador de los jugadores + std::array(Id::SIZE)> continue_counter_ = {}; // Tiempo para continuar de los jugadores + std::array(Id::SIZE)> panel_ = {}; // Lista con todos los paneles del marcador int stage_ = 1; // Número de fase actual int hi_score_ = 0; // Máxima puntuación diff --git a/source/sections/credits.cpp b/source/sections/credits.cpp index e6de052..b1eb8aa 100644 --- a/source/sections/credits.cpp +++ b/source/sections/credits.cpp @@ -354,12 +354,12 @@ void Credits::initPlayers() { constexpr bool DEMO = false; constexpr int AWAY_DISTANCE = 700; players_.emplace_back(std::make_unique(1, play_area_.x - AWAY_DISTANCE - PLAYER_WIDTH, Y, DEMO, play_area_, player_textures.at(0), player_animations)); - players_.back()->setWalkingState(PlayerState::WALKING_RIGHT); - players_.back()->setPlayingState(PlayerState::CREDITS); + players_.back()->setWalkingState(Player::State::WALKING_RIGHT); + players_.back()->setPlayingState(Player::State::CREDITS); players_.emplace_back(std::make_unique(2, play_area_.x + play_area_.w + AWAY_DISTANCE, Y, DEMO, play_area_, player_textures.at(1), player_animations)); - players_.back()->setWalkingState(PlayerState::WALKING_LEFT); - players_.back()->setPlayingState(PlayerState::CREDITS); + players_.back()->setWalkingState(Player::State::WALKING_LEFT); + players_.back()->setPlayingState(Player::State::CREDITS); } // Actualiza los rectangulos negros diff --git a/source/sections/game.cpp b/source/sections/game.cpp index 3647c5c..6a0d52a 100644 --- a/source/sections/game.cpp +++ b/source/sections/game.cpp @@ -237,9 +237,7 @@ void Game::updatePlayers() { // Dibuja a los jugadores void Game::renderPlayers() { for (auto &player : players_) { - if (!player->isWaiting()) { - player->render(); - } + player->render(); } } @@ -363,9 +361,9 @@ void Game::updateGameStateCompleted() { for (auto &player : players_) { if (player->isPlaying()) { player->addScore(1000000); - player->setPlayingState(PlayerState::CELEBRATING); + player->setPlayingState(Player::State::CELEBRATING); } else { - player->setPlayingState(PlayerState::GAME_OVER); + player->setPlayingState(Player::State::GAME_OVER); } } @@ -376,14 +374,14 @@ void Game::updateGameStateCompleted() { if (game_completed_counter_ == END_CELEBRATIONS) { for (auto &player : players_) { if (player->isCelebrating()) { - player->setPlayingState(player->isEligibleForHighScore() ? PlayerState::ENTERING_NAME_GAME_COMPLETED : PlayerState::LEAVING_SCREEN); + player->setPlayingState(player->isEligibleForHighScore() ? Player::State::ENTERING_NAME_GAME_COMPLETED : Player::State::LEAVING_SCREEN); } } } // Si los jugadores ya no estan y no quedan mensajes en pantalla if (allPlayersAreGameOver() && path_sprites_.empty()) { - setState(GameState::GAME_OVER); + setState(State::GAME_OVER); } // Incrementa el contador al final @@ -392,12 +390,12 @@ void Game::updateGameStateCompleted() { // Comprueba el estado del juego void Game::checkState() { - if (state_ != GameState::COMPLETED && Stage::number == 10) { - setState(GameState::COMPLETED); + if (state_ != State::COMPLETED && Stage::number == 10) { + setState(State::COMPLETED); } - if (state_ != GameState::GAME_OVER && allPlayersAreGameOver()) { - setState(GameState::GAME_OVER); + if (state_ != State::GAME_OVER && allPlayersAreGameOver()) { + setState(State::GAME_OVER); } } @@ -525,7 +523,7 @@ auto Game::checkBulletTabeCollision(std::shared_ptr bullet) -> bool { return false; } - tabe_->setState(TabeState::HIT); + tabe_->setState(Tabe::State::HIT); bullet->disable(); handleTabeHitEffects(); @@ -859,7 +857,7 @@ void Game::handlePlayerCollision(std::shared_ptr &player, std::shared_pt } screen_->shake(); playSound("voice_no.wav"); - player->setPlayingState(PlayerState::ROLLING); + player->setPlayingState(Player::State::ROLLING); players_to_reorder_.push_back(player); if (allPlayersAreNotPlaying()) { Stage::power_can_be_added = false; // No se puede subir poder de fase si no hay nadie jugando @@ -924,22 +922,22 @@ void Game::render() { void Game::updateGameStates() { if (!paused_) { switch (state_) { - case GameState::FADE_IN: + case State::FADE_IN: updateGameStateFadeIn(); break; - case GameState::ENTERING_PLAYER: + case State::ENTERING_PLAYER: updateGameStateEnteringPlayer(); break; - case GameState::SHOWING_GET_READY_MESSAGE: + case State::SHOWING_GET_READY_MESSAGE: updateGameStateShowingGetReadyMessage(); break; - case GameState::PLAYING: + case State::PLAYING: updateGameStatePlaying(); break; - case GameState::COMPLETED: + case State::COMPLETED: updateGameStateCompleted(); break; - case GameState::GAME_OVER: + case State::GAME_OVER: updateGameStateGameOver(); break; default: @@ -951,7 +949,7 @@ void Game::updateGameStates() { // Actualiza el fondo void Game::updateBackground() { // Si el juego está completado, se reduce la velocidad de las nubes - if (state_ == GameState::COMPLETED) { + if (state_ == State::COMPLETED) { Stage::total_power = (Stage::total_power > 200) ? (Stage::total_power - 25) : 200; } @@ -1184,7 +1182,7 @@ void Game::addScoreToScoreBoard(const std::shared_ptr &player) { // Saca del estado de GAME OVER al jugador si el otro está activo void Game::checkAndUpdatePlayerStatus(int active_player_index, int inactive_player_index) { if (players_[active_player_index]->isGameOver() && !players_[inactive_player_index]->isGameOver() && !players_[inactive_player_index]->isWaiting()) { - players_[active_player_index]->setPlayingState(PlayerState::WAITING); + players_[active_player_index]->setPlayingState(Player::State::WAITING); } } @@ -1198,7 +1196,7 @@ void Game::checkPlayersStatusPlaying() { if (allPlayersAreWaitingOrGameOver()) { // Entonces los pone en estado de Game Over for (auto &player : players_) { - player->setPlayingState(PlayerState::GAME_OVER); + player->setPlayingState(Player::State::GAME_OVER); } } @@ -1415,7 +1413,11 @@ void Game::handleFireInputs(const std::shared_ptr &player, bool autofire void Game::handlePlayerContinue(const std::shared_ptr &player) { const auto CONTROLLER_INDEX = player->getController(); if (input_->checkInput(InputAction::START, INPUT_DO_NOT_ALLOW_REPEAT, Options::controllers[CONTROLLER_INDEX].type, Options::controllers[CONTROLLER_INDEX].index)) { - player->setPlayingState(PlayerState::RESPAWNING); + if (player->isContinue()) { + player->setPlayingState(Player::State::RESPAWNING); + } else if (player->isWaiting()) { + player->setPlayingState(Player::State::ENTERING_SCREEN); + } } // Disminuye el contador de continuación si se presiona cualquier botón de disparo. @@ -1433,18 +1435,18 @@ void Game::handleNameInput(const std::shared_ptr &player) { const auto CONTROLLER_INDEX = player->getController(); if (input_->checkInput(InputAction::FIRE_LEFT, INPUT_DO_NOT_ALLOW_REPEAT, Options::controllers[CONTROLLER_INDEX].type, Options::controllers[CONTROLLER_INDEX].index)) { if (player->isShowingName()) { - player->setPlayingState(PlayerState::CONTINUE); + player->setPlayingState(Player::State::CONTINUE); } else if (player->getEnterNamePositionOverflow()) { player->setInput(InputAction::START); addScoreToScoreBoard(player); - player->setPlayingState(PlayerState::SHOWING_NAME); + player->setPlayingState(Player::State::SHOWING_NAME); } else { player->setInput(InputAction::RIGHT); } } else if (input_->checkInput(InputAction::FIRE_CENTER, INPUT_DO_NOT_ALLOW_REPEAT, Options::controllers[CONTROLLER_INDEX].type, Options::controllers[CONTROLLER_INDEX].index) || input_->checkInput(InputAction::FIRE_RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, Options::controllers[CONTROLLER_INDEX].type, Options::controllers[CONTROLLER_INDEX].index)) { if (player->isShowingName()) { - player->setPlayingState(PlayerState::CONTINUE); + player->setPlayingState(Player::State::CONTINUE); } else { player->setInput(InputAction::LEFT); } @@ -1454,11 +1456,11 @@ void Game::handleNameInput(const std::shared_ptr &player) { player->setInput(InputAction::DOWN); } else if (input_->checkInput(InputAction::START, INPUT_DO_NOT_ALLOW_REPEAT, Options::controllers[CONTROLLER_INDEX].type, Options::controllers[CONTROLLER_INDEX].index)) { if (player->isShowingName()) { - player->setPlayingState(PlayerState::CONTINUE); + player->setPlayingState(Player::State::CONTINUE); } else { player->setInput(InputAction::START); addScoreToScoreBoard(player); - player->setPlayingState(PlayerState::SHOWING_NAME); + player->setPlayingState(Player::State::SHOWING_NAME); } } } @@ -1467,7 +1469,7 @@ void Game::handleNameInput(const std::shared_ptr &player) { void Game::initDemo(int player_id) { if (demo_.enabled) { // Cambia el estado del juego - setState(GameState::PLAYING); + setState(State::PLAYING); // Aleatoriza la asignación del fichero con los datos del modo demostracion { @@ -1494,7 +1496,7 @@ void Game::initDemo(int player_id) { if (rand() % 3 != 0) { const auto OTHER_PLAYER_ID = player_id == 1 ? 2 : 1; auto other_player = getPlayer(OTHER_PLAYER_ID); - other_player->setPlayingState(PlayerState::PLAYING); + other_player->setPlayingState(Player::State::PLAYING); } // Asigna cafes a los jugadores @@ -1507,8 +1509,8 @@ void Game::initDemo(int player_id) { } // Configura los marcadores - scoreboard_->setMode(SCOREBOARD_LEFT_PANEL, ScoreboardMode::DEMO); - scoreboard_->setMode(SCOREBOARD_RIGHT_PANEL, ScoreboardMode::DEMO); + scoreboard_->setMode(Scoreboard::Id::LEFT, Scoreboard::Mode::DEMO); + scoreboard_->setMode(Scoreboard::Id::RIGHT, Scoreboard::Mode::DEMO); // Silencia los globos balloon_manager_->setSounds(false); @@ -1534,11 +1536,11 @@ void Game::setTotalPower() { // Inicializa el marcador void Game::initScoreboard() { scoreboard_->setPos(param.scoreboard.rect); - scoreboard_->setMode(SCOREBOARD_CENTER_PANEL, ScoreboardMode::STAGE_INFO); + scoreboard_->setMode(Scoreboard::Id::CENTER, Scoreboard::Mode::STAGE_INFO); for (const auto &player : players_) { scoreboard_->setName(player->getScoreBoardPanel(), player->getName()); if (player->isWaiting()) { - scoreboard_->setMode(player->getScoreBoardPanel(), ScoreboardMode::WAITING); + scoreboard_->setMode(player->getScoreBoardPanel(), Scoreboard::Mode::WAITING); } } } @@ -1577,27 +1579,31 @@ void Game::initDifficultyVars() { // Inicializa los jugadores void Game::initPlayers(int player_id) { - // Crea los dos jugadores constexpr int PLAYER_HEIGHT = 32; constexpr int PLAYER_WIDTH = 32; const int Y = param.game.play_area.rect.h - PLAYER_HEIGHT + 1; + + // Crea al jugador uno y lo pone en modo espera players_.emplace_back(std::make_unique(1, param.game.play_area.first_quarter_x - (PLAYER_WIDTH / 2), Y, demo_.enabled, param.game.play_area.rect, player_textures_[0], player_animations_)); - players_.back()->setScoreBoardPanel(SCOREBOARD_LEFT_PANEL); + players_.back()->setScoreBoardPanel(Scoreboard::Id::LEFT); players_.back()->setName(Lang::getText("[SCOREBOARD] 1")); players_.back()->setController(getController(players_.back()->getId())); + players_.back()->setPlayingState(Player::State::WAITING); + // Crea al jugador dos y lo pone en modo espera players_.emplace_back(std::make_unique(2, param.game.play_area.third_quarter_x - (PLAYER_WIDTH / 2), Y, demo_.enabled, param.game.play_area.rect, player_textures_[1], player_animations_)); - players_.back()->setScoreBoardPanel(SCOREBOARD_RIGHT_PANEL); + players_.back()->setScoreBoardPanel(Scoreboard::Id::RIGHT); players_.back()->setName(Lang::getText("[SCOREBOARD] 2")); players_.back()->setController(getController(players_.back()->getId())); + players_.back()->setPlayingState(Player::State::WAITING); // Activa el jugador que coincide con el "player_id" o ambos si es "0" if (player_id == 0) { // Activa ambos jugadores - getPlayer(1)->setPlayingState(demo_.enabled ? PlayerState::PLAYING : PlayerState::ENTERING_SCREEN); - getPlayer(2)->setPlayingState(demo_.enabled ? PlayerState::PLAYING : PlayerState::ENTERING_SCREEN); + getPlayer(1)->setPlayingState(demo_.enabled ? Player::State::PLAYING : Player::State::ENTERING_SCREEN); + getPlayer(2)->setPlayingState(demo_.enabled ? Player::State::PLAYING : Player::State::ENTERING_SCREEN); } else { - getPlayer(player_id)->setPlayingState(demo_.enabled ? PlayerState::PLAYING : PlayerState::ENTERING_SCREEN); + getPlayer(player_id)->setPlayingState(demo_.enabled ? Player::State::PLAYING : Player::State::ENTERING_SCREEN); } } @@ -1675,7 +1681,7 @@ void Game::updateGameStateFadeIn() { updateScoreboard(); updateBackground(); if (fade_in_->hasEnded()) { - setState(GameState::ENTERING_PLAYER); + setState(State::ENTERING_PLAYER); balloon_manager_->createTwoBigBalloons(); evaluateAndSetMenace(); } @@ -1689,7 +1695,7 @@ void Game::updateGameStateEnteringPlayer() { updateBackground(); for (const auto &player : players_) { if (player->isPlaying()) { - setState(GameState::SHOWING_GET_READY_MESSAGE); + setState(State::SHOWING_GET_READY_MESSAGE); createMessage({paths_.at(0), paths_.at(1)}, Resource::get()->getTexture("game_text_get_ready")); playSound("voice_get_ready.wav"); } @@ -1700,7 +1706,7 @@ void Game::updateGameStateEnteringPlayer() { void Game::updateGameStateShowingGetReadyMessage() { updateGameStatePlaying(); if (path_sprites_.empty()) { - setState(GameState::PLAYING); + setState(State::PLAYING); } if (counter_ == 100) { playMusic(); @@ -1746,7 +1752,7 @@ void Game::cleanVectors() { // Gestiona el nivel de amenaza void Game::updateMenace() { - if (state_ == GameState::PLAYING) { + if (state_ == State::PLAYING) { const auto STAGE = Stage::get(Stage::number); const float PERCENT = Stage::power / STAGE.power_to_complete; const int DIFFERENCE = STAGE.max_menace - STAGE.min_menace; @@ -1787,7 +1793,7 @@ void Game::checkAndUpdateBalloonSpeed() { } // Cambia el estado del juego -void Game::setState(GameState state) { +void Game::setState(State state) { state_ = state; counter_ = 0; } diff --git a/source/sections/game.h b/source/sections/game.h index 26113b6..3ed3624 100644 --- a/source/sections/game.h +++ b/source/sections/game.h @@ -49,7 +49,7 @@ class Game { private: // --- Tipos internos --- - enum class GameState { + enum class State { FADE_IN, ENTERING_PLAYER, SHOWING_GET_READY_MESSAGE, @@ -146,7 +146,7 @@ class Game { int total_power_to_complete_game_; // La suma del poder necesario para completar todas las fases int menace_current_ = 0; // Nivel de amenaza actual int menace_threshold_ = 0; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el número de globos - GameState state_ = GameState::FADE_IN; // Estado + State state_ = State::FADE_IN; // Estado std::vector> players_to_reorder_; Hit hit_; // Para representar colisiones en pantalla @@ -155,13 +155,13 @@ class Game { #endif // --- Ciclo principal del juego --- - void update(); // Actualiza la lógica principal del juego - void render(); // Renderiza todos los elementos del juego - void checkEvents(); // Procesa los eventos del sistema en cola - void checkState(); // Verifica y actualiza el estado actual del juego - void setState(GameState state); // Cambia el estado del juego - void pause(bool value); // Pausa o reanuda el juego - void cleanVectors(); // Limpia vectores de elementos deshabilitados + void update(); // Actualiza la lógica principal del juego + void render(); // Renderiza todos los elementos del juego + void checkEvents(); // Procesa los eventos del sistema en cola + void checkState(); // Verifica y actualiza el estado actual del juego + void setState(State state); // Cambia el estado del juego + void pause(bool value); // Pausa o reanuda el juego + void cleanVectors(); // Limpia vectores de elementos deshabilitados // --- Gestión de estados del juego --- void updateGameStates(); // Actualiza todos los estados del juego diff --git a/source/sections/title.cpp b/source/sections/title.cpp index e124aa7..751720f 100644 --- a/source/sections/title.cpp +++ b/source/sections/title.cpp @@ -80,7 +80,7 @@ void Title::update() { if (SDL_GetTicks() - ticks_ > param.game.speed) { ticks_ = SDL_GetTicks(); Screen::get()->update(); - + updateFade(); updateState(); updateStartPrompt(); @@ -308,7 +308,7 @@ void Title::processPlayer2Start() { } void Title::activatePlayerAndSetState(int player_id) { - getPlayer(player_id)->setPlayingState(PlayerState::TITLE_ANIMATION); + getPlayer(player_id)->setPlayingState(Player::State::TITLE_ANIMATION); setState(TitleState::START_HAS_BEEN_PRESSED); counter_ = 0; } @@ -559,10 +559,10 @@ void Title::initPlayers() { const int Y = param.title.press_start_position - (PLAYER_HEIGHT / 2); constexpr bool DEMO = false; players_.emplace_back(std::make_unique(1, param.game.game_area.center_x - (PLAYER_WIDTH / 2), Y, DEMO, param.game.play_area.rect, player_textures.at(0), player_animations)); - players_.back()->setPlayingState(PlayerState::TITLE_HIDDEN); + players_.back()->setPlayingState(Player::State::TITLE_HIDDEN); players_.emplace_back(std::make_unique(2, param.game.game_area.center_x - (PLAYER_WIDTH / 2), Y, DEMO, param.game.play_area.rect, player_textures.at(1), player_animations)); - players_.back()->setPlayingState(PlayerState::TITLE_HIDDEN); + players_.back()->setPlayingState(Player::State::TITLE_HIDDEN); } // Actualza los jugadores diff --git a/source/tabe.cpp b/source/tabe.cpp index f8a35c6..208c7a9 100644 --- a/source/tabe.cpp +++ b/source/tabe.cpp @@ -15,7 +15,7 @@ // Constructor Tabe::Tabe() : sprite_(std::make_unique(Resource::get()->getTexture("tabe.png"), Resource::get()->getAnimation("tabe.ani"))), - timer_(TabeTimer(2.5F, 4.0F)) {} + timer_(Timer(2.5F, 4.0F)) {} // Actualiza la lógica void Tabe::update() { @@ -49,23 +49,23 @@ void Tabe::move() { const float MIN_X = param.game.game_area.rect.x - WIDTH; const float MAX_X = param.game.game_area.rect.x + param.game.game_area.rect.w; switch (destiny_) { - case TabeDirection::TO_THE_LEFT: { + case Direction::TO_THE_LEFT: { if (x_ < MIN_X) { disable(); } - if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH && direction_ == TabeDirection::TO_THE_RIGHT) { - setRandomFlyPath(TabeDirection::TO_THE_LEFT, 80); + if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH && direction_ == Direction::TO_THE_RIGHT) { + setRandomFlyPath(Direction::TO_THE_LEFT, 80); x_ = param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH; } break; } - case TabeDirection::TO_THE_RIGHT: { + case Direction::TO_THE_RIGHT: { if (x_ > MAX_X) { disable(); } - if (x_ < param.game.game_area.rect.x && direction_ == TabeDirection::TO_THE_LEFT) { - setRandomFlyPath(TabeDirection::TO_THE_RIGHT, 80); + if (x_ < param.game.game_area.rect.x && direction_ == Direction::TO_THE_LEFT) { + setRandomFlyPath(Direction::TO_THE_RIGHT, 80); x_ = param.game.game_area.rect.x; } break; @@ -80,19 +80,19 @@ void Tabe::move() { --waiting_counter_; } else { constexpr int CHOICES = 4; - const std::array LEFT = { - TabeDirection::TO_THE_LEFT, - TabeDirection::TO_THE_LEFT, - TabeDirection::TO_THE_LEFT, - TabeDirection::TO_THE_RIGHT}; + const std::array LEFT = { + Direction::TO_THE_LEFT, + Direction::TO_THE_LEFT, + Direction::TO_THE_LEFT, + Direction::TO_THE_RIGHT}; - const std::array RIGHT = { - TabeDirection::TO_THE_LEFT, - TabeDirection::TO_THE_RIGHT, - TabeDirection::TO_THE_RIGHT, - TabeDirection::TO_THE_RIGHT}; + const std::array RIGHT = { + Direction::TO_THE_LEFT, + Direction::TO_THE_RIGHT, + Direction::TO_THE_RIGHT, + Direction::TO_THE_RIGHT}; - const TabeDirection DIRECTION = destiny_ == TabeDirection::TO_THE_LEFT + const Direction DIRECTION = destiny_ == Direction::TO_THE_LEFT ? LEFT[rand() % CHOICES] : RIGHT[rand() % CHOICES]; @@ -113,10 +113,10 @@ void Tabe::enable() { y_ = param.game.game_area.rect.y + 20.0F; // Establece una dirección aleatoria - destiny_ = direction_ = rand() % 2 == 0 ? TabeDirection::TO_THE_LEFT : TabeDirection::TO_THE_RIGHT; + destiny_ = direction_ = rand() % 2 == 0 ? Direction::TO_THE_LEFT : Direction::TO_THE_RIGHT; // Establece la posición inicial - x_ = (direction_ == TabeDirection::TO_THE_LEFT) ? param.game.game_area.rect.x + param.game.game_area.rect.w : param.game.game_area.rect.x - WIDTH; + x_ = (direction_ == Direction::TO_THE_LEFT) ? param.game.game_area.rect.x + param.game.game_area.rect.w : param.game.game_area.rect.x - WIDTH; // Crea una ruta de vuelo setRandomFlyPath(direction_, 60); @@ -125,7 +125,7 @@ void Tabe::enable() { } // Establece un vuelo aleatorio -void Tabe::setRandomFlyPath(TabeDirection direction, int lenght) { +void Tabe::setRandomFlyPath(Direction direction, int lenght) { direction_ = direction; fly_distance_ = lenght; waiting_counter_ = 5 + rand() % 15; @@ -134,14 +134,14 @@ void Tabe::setRandomFlyPath(TabeDirection direction, int lenght) { constexpr float SPEED = 2.0F; switch (direction) { - case TabeDirection::TO_THE_LEFT: { + case Direction::TO_THE_LEFT: { speed_ = -1.0F * SPEED; accel_ = -1.0F * (1 + rand() % 10) / 30.0F; sprite_->setFlip(SDL_FLIP_NONE); break; } - case TabeDirection::TO_THE_RIGHT: { + case Direction::TO_THE_RIGHT: { speed_ = SPEED; accel_ = (1 + rand() % 10) / 30.0F; sprite_->setFlip(SDL_FLIP_HORIZONTAL); @@ -154,16 +154,16 @@ void Tabe::setRandomFlyPath(TabeDirection direction, int lenght) { } // Establece el estado -void Tabe::setState(TabeState state) { +void Tabe::setState(State state) { if (enabled_) { state_ = state; switch (state) { - case TabeState::FLY: + case State::FLY: sprite_->setCurrentAnimation("fly"); break; - case TabeState::HIT: + case State::HIT: sprite_->setCurrentAnimation("hit"); hit_counter_ = 5; ++number_of_hits_; @@ -177,10 +177,10 @@ void Tabe::setState(TabeState state) { // Actualiza el estado void Tabe::updateState() { - if (state_ == TabeState::HIT) { + if (state_ == State::HIT) { --hit_counter_; if (hit_counter_ == 0) { - setState(TabeState::FLY); + setState(State::FLY); } } } diff --git a/source/tabe.h b/source/tabe.h index 269d8b6..746fd7b 100644 --- a/source/tabe.h +++ b/source/tabe.h @@ -7,96 +7,31 @@ #include "animated_sprite.h" // Para AnimatedSprite -// --- Enumeraciones para dirección y estado --- -enum class TabeDirection : int { - TO_THE_LEFT = 0, - TO_THE_RIGHT = 1, -}; - -enum class TabeState : int { - FLY = 0, - HIT = 1, -}; - -// --- Estructura para el temporizador del Tabe --- -struct TabeTimer { - private: - static constexpr Uint32 MINUTES_TO_MILLISECONDS = 60000; // Factor de conversión de minutos a milisegundos - - public: - Uint32 time_until_next_spawn; // Tiempo restante para la próxima aparición - Uint32 min_spawn_time; // Tiempo mínimo entre apariciones (en milisegundos) - Uint32 max_spawn_time; // Tiempo máximo entre apariciones (en milisegundos) - Uint32 current_time; // Tiempo actual - Uint32 delta_time; // Diferencia de tiempo desde la última actualización - Uint32 last_time; // Tiempo de la última actualización - bool is_paused{false}; // Indica si el temporizador está pausado - - // Constructor - los parámetros min_time y max_time están en mintos - TabeTimer(float min_time, float max_time) - : min_spawn_time(static_cast(min_time * MINUTES_TO_MILLISECONDS)), - max_spawn_time(static_cast(max_time * MINUTES_TO_MILLISECONDS)), - current_time(SDL_GetTicks()) { - reset(); - } - - // Restablece el temporizador con un nuevo tiempo hasta la próxima aparición - void reset() { - Uint32 range = max_spawn_time - min_spawn_time; - time_until_next_spawn = min_spawn_time + rand() % (range + 1); - last_time = SDL_GetTicks(); - } - - // Actualiza el temporizador, decrementando el tiempo hasta la próxima aparición - void update() { - current_time = SDL_GetTicks(); - - // Solo actualizar si no está pausado - if (!is_paused) { - delta_time = current_time - last_time; - - if (time_until_next_spawn > delta_time) { - time_until_next_spawn -= delta_time; - } else { - time_until_next_spawn = 0; - } - } - - // Siempre actualizar last_time para evitar saltos de tiempo al despausar - last_time = current_time; - } - - // Pausa o reanuda el temporizador - void setPaused(bool paused) { - if (is_paused != paused) { - is_paused = paused; - // Al despausar, actualizar last_time para evitar saltos - if (!paused) { - last_time = SDL_GetTicks(); - } - } - } - - // Indica si el temporizador ha finalizado - [[nodiscard]] auto shouldSpawn() const -> bool { - return time_until_next_spawn == 0 && !is_paused; - } -}; - // --- Clase Tabe --- class Tabe { public: + // --- Enumeraciones para dirección y estado --- + enum class Direction : int { + TO_THE_LEFT = 0, + TO_THE_RIGHT = 1, + }; + + enum class State : int { + FLY = 0, + HIT = 1, + }; + // --- Constructores y destructor --- Tabe(); ~Tabe() = default; // --- Métodos principales --- - void update(); // Actualiza la lógica - void render(); // Dibuja el objeto - void enable(); // Habilita el objeto - void setState(TabeState state); // Establece el estado - auto tryToGetBonus() -> bool; // Intenta obtener el bonus - void pauseTimer(bool value); // Detiene/activa el timer + void update(); // Actualiza la lógica + void render(); // Dibuja el objeto + void enable(); // Habilita el objeto + void setState(State state); // Establece el estado + auto tryToGetBonus() -> bool; // Intenta obtener el bonus + void pauseTimer(bool value); // Detiene/activa el timer // --- Getters --- auto getCollider() -> SDL_FRect& { return sprite_->getRect(); } // Obtiene el área de colisión @@ -107,30 +42,95 @@ class Tabe { static constexpr int WIDTH = 32; static constexpr int HEIGHT = 32; + // --- Estructura para el temporizador del Tabe --- + struct Timer { + private: + static constexpr Uint32 MINUTES_TO_MILLISECONDS = 60000; // Factor de conversión de minutos a milisegundos + + public: + Uint32 time_until_next_spawn; // Tiempo restante para la próxima aparición + Uint32 min_spawn_time; // Tiempo mínimo entre apariciones (en milisegundos) + Uint32 max_spawn_time; // Tiempo máximo entre apariciones (en milisegundos) + Uint32 current_time; // Tiempo actual + Uint32 delta_time; // Diferencia de tiempo desde la última actualización + Uint32 last_time; // Tiempo de la última actualización + bool is_paused{false}; // Indica si el temporizador está pausado + + // Constructor - los parámetros min_time y max_time están en mintos + Timer(float min_time, float max_time) + : min_spawn_time(static_cast(min_time * MINUTES_TO_MILLISECONDS)), + max_spawn_time(static_cast(max_time * MINUTES_TO_MILLISECONDS)), + current_time(SDL_GetTicks()) { + reset(); + } + + // Restablece el temporizador con un nuevo tiempo hasta la próxima aparición + void reset() { + Uint32 range = max_spawn_time - min_spawn_time; + time_until_next_spawn = min_spawn_time + rand() % (range + 1); + last_time = SDL_GetTicks(); + } + + // Actualiza el temporizador, decrementando el tiempo hasta la próxima aparición + void update() { + current_time = SDL_GetTicks(); + + // Solo actualizar si no está pausado + if (!is_paused) { + delta_time = current_time - last_time; + + if (time_until_next_spawn > delta_time) { + time_until_next_spawn -= delta_time; + } else { + time_until_next_spawn = 0; + } + } + + // Siempre actualizar last_time para evitar saltos de tiempo al despausar + last_time = current_time; + } + + // Pausa o reanuda el temporizador + void setPaused(bool paused) { + if (is_paused != paused) { + is_paused = paused; + // Al despausar, actualizar last_time para evitar saltos + if (!paused) { + last_time = SDL_GetTicks(); + } + } + } + + // Indica si el temporizador ha finalizado + [[nodiscard]] auto shouldSpawn() const -> bool { + return time_until_next_spawn == 0 && !is_paused; + } + }; + // --- Objetos y punteros --- std::unique_ptr sprite_; // Sprite con los gráficos y animaciones // --- Variables de estado --- - float x_ = 0; // Posición X - float y_ = 0; // Posición Y - float speed_ = 0.0F; // Velocidad de movimiento - float accel_ = 0.0F; // Aceleración - int fly_distance_ = 0; // Distancia de vuelo - int waiting_counter_ = 0; // Tiempo que pasa quieto - bool enabled_ = false; // Indica si el objeto está activo - TabeDirection direction_ = TabeDirection::TO_THE_LEFT; // Dirección actual - TabeDirection destiny_ = TabeDirection::TO_THE_LEFT; // Destino - TabeState state_ = TabeState::FLY; // Estado actual - int hit_counter_ = 0; // Contador para el estado HIT - int number_of_hits_ = 0; // Cantidad de disparos recibidos - bool has_bonus_ = true; // Indica si aún tiene el bonus para soltar - TabeTimer timer_; // Temporizador para gestionar la aparición + float x_ = 0; // Posición X + float y_ = 0; // Posición Y + float speed_ = 0.0F; // Velocidad de movimiento + float accel_ = 0.0F; // Aceleración + int fly_distance_ = 0; // Distancia de vuelo + int waiting_counter_ = 0; // Tiempo que pasa quieto + bool enabled_ = false; // Indica si el objeto está activo + Direction direction_ = Direction::TO_THE_LEFT; // Dirección actual + Direction destiny_ = Direction::TO_THE_LEFT; // Destino + State state_ = State::FLY; // Estado actual + int hit_counter_ = 0; // Contador para el estado HIT + int number_of_hits_ = 0; // Cantidad de disparos recibidos + bool has_bonus_ = true; // Indica si aún tiene el bonus para soltar + Timer timer_; // Temporizador para gestionar la aparición // --- Métodos internos --- - void move(); // Mueve el objeto - void shiftSprite() { sprite_->setPos(x_, y_); } // Actualiza la posición del sprite - void setRandomFlyPath(TabeDirection direction, int lenght); // Establece un vuelo aleatorio - void updateState(); // Actualiza el estado - void updateTimer(); // Actualiza el temporizador - void disable(); // Deshabilita el objeto + void move(); // Mueve el objeto + void shiftSprite() { sprite_->setPos(x_, y_); } // Actualiza la posición del sprite + void setRandomFlyPath(Direction direction, int lenght); // Establece un vuelo aleatorio + void updateState(); // Actualiza el estado + void updateTimer(); // Actualiza el temporizador + void disable(); // Deshabilita el objeto }; \ No newline at end of file