Player: afegides animacions per al estat WAITING

Player: si tires a jugar desde el estat WAITING passes al ENTERING_SCREEN i despres sempre tens inmunitat, fins i tot la primera volta (al començar el joc)
falta: arregñar el z-order per al estat WAITING
This commit is contained in:
2025-07-25 20:54:00 +02:00
parent b165484e03
commit 03a7bbc6d1
17 changed files with 619 additions and 554 deletions

View File

@@ -119,3 +119,10 @@ speed=5
loop=0 loop=0
frames=47,48,49,50,51,52,53 frames=47,48,49,50,51,52,53
[/animation] [/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]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -66,7 +66,7 @@ auto AnimatedSprite::getIndex(const std::string& name) -> int {
// Calcula el frame correspondiente a la animación // Calcula el frame correspondiente a la animación
void AnimatedSprite::animate() { void AnimatedSprite::animate() {
if (animations_[current_animation_].speed == 0) { if (animations_[current_animation_].speed == 0 || animations_[current_animation_].paused) {
return; return;
} }
@@ -87,7 +87,7 @@ void AnimatedSprite::animate() {
// En caso contrario // En caso contrario
else { else {
// Escoge el frame correspondiente de la animación // 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 // Incrementa el contador de la animacion
animations_[current_animation_].counter++; 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_].counter = 0;
animations_[current_animation_].completed = false; animations_[current_animation_].completed = false;
} else { } 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_].counter = animations_[OLD_ANIMATION].counter;
animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed; 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_].counter = animations_[OLD_ANIMATION].counter;
animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed; 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_].current_frame = 0;
animations_[current_animation_].counter = 0; animations_[current_animation_].counter = 0;
animations_[current_animation_].completed = false; animations_[current_animation_].completed = false;
animations_[current_animation_].paused = false;
updateSpriteClip();
} }
// Carga la animación desde un vector de cadenas // 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) { void AnimatedSprite::setAnimationSpeed(size_t value) {
animations_[current_animation_].speed = 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]);
}

View File

@@ -25,6 +25,7 @@ struct Animation {
bool completed{false}; // Indica si la animación ha finalizado bool completed{false}; // Indica si la animación ha finalizado
size_t current_frame{0}; // Frame actual en reproducción size_t current_frame{0}; // Frame actual en reproducción
int counter{0}; // Contador para la animación int counter{0}; // Contador para la animación
bool paused{false}; // La animación no avanza
Animation() = default; Animation() = default;
}; };
@@ -60,6 +61,8 @@ class AnimatedSprite : public MovingSprite {
void resetAnimation(); // Reinicia la animación actual void resetAnimation(); // Reinicia la animación actual
void setAnimationSpeed(size_t value); // Establece la velocidad de la animación 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 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 --- // --- Consultas ---
auto animationIsCompleted() -> bool; // Comprueba si la animación ha terminado 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 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 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) 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
}; };

View File

@@ -30,6 +30,13 @@ MovingSprite::MovingSprite(std::shared_ptr<Texture> texture)
// Reinicia todas las variables // Reinicia todas las variables
void MovingSprite::clear() { void MovingSprite::clear() {
stop();
Sprite::clear();
}
// Elimina el movimiento del sprite
void MovingSprite::stop()
{
x_ = 0.0F; // Posición en el eje X x_ = 0.0F; // Posición en el eje X
y_ = 0.0F; // Posición en el eje Y 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 vertical_zoom_ = 1.0F; // Zoom aplicado a la altura
flip_ = SDL_FLIP_NONE; // Establece como se ha de voltear el sprite flip_ = SDL_FLIP_NONE; // Establece como se ha de voltear el sprite
Sprite::clear();
} }
// Mueve el sprite // Mueve el sprite

View File

@@ -33,6 +33,7 @@ class MovingSprite : public Sprite {
// --- Métodos principales --- // --- Métodos principales ---
virtual void update(); // Actualiza las variables internas del objeto virtual void update(); // Actualiza las variables internas del objeto
void clear() override; // Reinicia todas las variables a cero void clear() override; // Reinicia todas las variables a cero
void stop(); // Elimina el movimiento del sprite
void render() override; // Muestra el sprite por pantalla void render() override; // Muestra el sprite por pantalla
// --- Getters de posición y movimiento --- // --- Getters de posición y movimiento ---

View File

@@ -42,9 +42,8 @@ Player::Player(int id, float x, int y, bool demo, SDL_FRect &play_area, std::vec
void Player::init() { void Player::init() {
// Inicializa variables de estado // Inicializa variables de estado
pos_y_ = default_pos_y_; pos_y_ = default_pos_y_;
walking_state_ = PlayerState::WALKING_STOP; walking_state_ = State::WALKING_STOP;
firing_state_ = PlayerState::FIRING_NONE; firing_state_ = State::FIRING_NONE;
playing_state_ = PlayerState::WAITING;
power_up_ = false; power_up_ = false;
power_up_counter_ = POWERUP_COUNTER; power_up_counter_ = POWERUP_COUNTER;
extra_hit_ = false; extra_hit_ = false;
@@ -73,12 +72,12 @@ void Player::init() {
// Actua en consecuencia de la entrada recibida // Actua en consecuencia de la entrada recibida
void Player::setInput(InputAction input) { void Player::setInput(InputAction input) {
switch (playing_state_) { switch (playing_state_) {
case PlayerState::PLAYING: { case State::PLAYING: {
setInputPlaying(input); setInputPlaying(input);
break; break;
} }
case PlayerState::ENTERING_NAME: case State::ENTERING_NAME:
case PlayerState::ENTERING_NAME_GAME_COMPLETED: { case State::ENTERING_NAME_GAME_COMPLETED: {
setInputEnteringName(input); setInputEnteringName(input);
break; break;
} }
@@ -92,29 +91,29 @@ void Player::setInputPlaying(InputAction input) {
switch (input) { switch (input) {
case InputAction::LEFT: { case InputAction::LEFT: {
vel_x_ = -BASE_SPEED; vel_x_ = -BASE_SPEED;
setWalkingState(PlayerState::WALKING_LEFT); setWalkingState(State::WALKING_LEFT);
break; break;
} }
case InputAction::RIGHT: { case InputAction::RIGHT: {
vel_x_ = BASE_SPEED; vel_x_ = BASE_SPEED;
setWalkingState(PlayerState::WALKING_RIGHT); setWalkingState(State::WALKING_RIGHT);
break; break;
} }
case InputAction::FIRE_CENTER: { case InputAction::FIRE_CENTER: {
setFiringState(PlayerState::FIRING_UP); setFiringState(State::FIRING_UP);
break; break;
} }
case InputAction::FIRE_LEFT: { case InputAction::FIRE_LEFT: {
setFiringState(PlayerState::FIRING_LEFT); setFiringState(State::FIRING_LEFT);
break; break;
} }
case InputAction::FIRE_RIGHT: { case InputAction::FIRE_RIGHT: {
setFiringState(PlayerState::FIRING_RIGHT); setFiringState(State::FIRING_RIGHT);
break; break;
} }
default: { default: {
vel_x_ = 0; vel_x_ = 0;
setWalkingState(PlayerState::WALKING_STOP); setWalkingState(State::WALKING_STOP);
break; break;
} }
} }
@@ -147,27 +146,30 @@ void Player::setInputEnteringName(InputAction input) {
// Mueve el jugador a la posición y animación que le corresponde // Mueve el jugador a la posición y animación que le corresponde
void Player::move() { void Player::move() {
switch (playing_state_) { switch (playing_state_) {
case PlayerState::PLAYING: case State::PLAYING:
handlePlayingMovement(); handlePlayingMovement();
break; break;
case PlayerState::ROLLING: case State::ROLLING:
handleRollingMovement(); handleRollingMovement();
break; break;
case PlayerState::TITLE_ANIMATION: case State::TITLE_ANIMATION:
handleTitleAnimation(); handleTitleAnimation();
break; break;
case PlayerState::CONTINUE_TIME_OUT: case State::CONTINUE_TIME_OUT:
handleContinueTimeOut(); handleContinueTimeOut();
break; break;
case PlayerState::LEAVING_SCREEN: case State::LEAVING_SCREEN:
handleLeavingScreen(); handleLeavingScreen();
break; break;
case PlayerState::ENTERING_SCREEN: case State::ENTERING_SCREEN:
handleEnteringScreen(); handleEnteringScreen();
break; break;
case PlayerState::CREDITS: case State::CREDITS:
handleCreditsMovement(); handleCreditsMovement();
break; break;
case State::WAITING:
handleWaitingMovement();
break;
default: default:
break; break;
} }
@@ -215,9 +217,9 @@ void Player::handleRollingGroundCollision() {
} }
void Player::handleRollingStop() { 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); setPlayingState(NEXT_STATE);
pos_x_ = player_sprite_->getPosX(); pos_x_ = player_sprite_->getPosX();
@@ -245,14 +247,15 @@ void Player::handleTitleAnimation() {
shiftSprite(); shiftSprite();
if (pos_x_ == MIN_X || pos_x_ == MAX_X) { if (pos_x_ == MIN_X || pos_x_ == MAX_X) {
setPlayingState(PlayerState::TITLE_HIDDEN); setPlayingState(State::TITLE_HIDDEN);
} }
} }
void Player::handleContinueTimeOut() { void Player::handleContinueTimeOut() {
// Si el cadaver desaparece por el suelo, cambia de estado // Si el cadaver desaparece por el suelo, cambia de estado
if (player_sprite_->getPosY() > play_area_.h) { if (player_sprite_->getPosY() > play_area_.h) {
setPlayingState(PlayerState::WAITING); player_sprite_->stop();
setPlayingState(State::WAITING);
} }
} }
@@ -267,7 +270,7 @@ void Player::handleLeavingScreen() {
shiftSprite(); shiftSprite();
if (pos_x_ == MIN_X || pos_x_ == MAX_X) { 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_; pos_x_ += vel_x_;
if (pos_x_ > default_pos_x_) { if (pos_x_ > default_pos_x_) {
pos_x_ = default_pos_x_; pos_x_ = default_pos_x_;
setPlayingState(PlayerState::PLAYING); setPlayingState(State::RESPAWNING);
setInvulnerable(false);
} }
} }
@@ -298,8 +300,7 @@ void Player::handlePlayer2Entering() {
pos_x_ += vel_x_; pos_x_ += vel_x_;
if (pos_x_ < default_pos_x_) { if (pos_x_ < default_pos_x_) {
pos_x_ = default_pos_x_; pos_x_ = default_pos_x_;
setPlayingState(PlayerState::PLAYING); setPlayingState(State::RESPAWNING);
setInvulnerable(false);
} }
} }
@@ -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() { void Player::updateWalkingStateForCredits() {
if (pos_x_ > param.game.game_area.center_x - WIDTH / 2) { if (pos_x_ > param.game.game_area.center_x - WIDTH / 2) {
setWalkingState(PlayerState::WALKING_LEFT); setWalkingState(State::WALKING_LEFT);
} else { } else {
setWalkingState(PlayerState::WALKING_RIGHT); setWalkingState(State::WALKING_RIGHT);
} }
} }
@@ -374,25 +383,25 @@ void Player::render() {
// Establece la animación correspondiente al estado // Establece la animación correspondiente al estado
void Player::setAnimation() { void Player::setAnimation() {
switch (playing_state_) { switch (playing_state_) {
case PlayerState::PLAYING: case State::PLAYING:
case PlayerState::ENTERING_NAME_GAME_COMPLETED: case State::ENTERING_NAME_GAME_COMPLETED:
case PlayerState::ENTERING_SCREEN: case State::ENTERING_SCREEN:
case PlayerState::LEAVING_SCREEN: case State::LEAVING_SCREEN:
case PlayerState::TITLE_ANIMATION: case State::TITLE_ANIMATION:
case PlayerState::CREDITS: { case State::CREDITS: {
// Crea cadenas de texto para componer el nombre de la animación // 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 WALK_ANIMATION = walking_state_ == State::WALKING_STOP ? "stand" : "walk";
const std::string FIRE_ANIMATION = firing_state_ == PlayerState::FIRING_UP ? "-fire-center" : "-fire-side"; const std::string FIRE_ANIMATION = firing_state_ == State::FIRING_UP ? "-fire-center" : "-fire-side";
const std::string RECOIL_ANIMATION = firing_state_ == PlayerState::RECOILING_UP ? "-recoil-center" : "-recoil-side"; const std::string RECOIL_ANIMATION = firing_state_ == State::RECOILING_UP ? "-recoil-center" : "-recoil-side";
const std::string COOL_ANIMATION = firing_state_ == PlayerState::COOLING_UP ? "-cool-center" : "-cool-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_WALK = walking_state_ == State::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_FIRE = firing_state_ == State::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_RECOIL = firing_state_ == State::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_COOL = firing_state_ == State::COOLING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
// Establece la animación a partir de las cadenas // Establece la animación a partir de las cadenas
if (firing_state_ == PlayerState::FIRING_NONE) { if (firing_state_ == State::FIRING_NONE) {
// No esta disparando // No esta disparando
player_sprite_->setCurrentAnimation(WALK_ANIMATION, false); player_sprite_->setCurrentAnimation(WALK_ANIMATION, false);
player_sprite_->setFlip(FLIP_WALK); player_sprite_->setFlip(FLIP_WALK);
@@ -413,18 +422,22 @@ void Player::setAnimation() {
} }
break; break;
} }
case PlayerState::ROLLING: case State::WAITING: {
case PlayerState::CONTINUE_TIME_OUT: { player_sprite_->setCurrentAnimation("hello");
break;
}
case State::ROLLING:
case State::CONTINUE_TIME_OUT: {
player_sprite_->setCurrentAnimation("rolling"); player_sprite_->setCurrentAnimation("rolling");
break; break;
} }
case PlayerState::LYING_ON_THE_FLOOR_FOREVER: case State::LYING_ON_THE_FLOOR_FOREVER:
case PlayerState::ENTERING_NAME: case State::ENTERING_NAME:
case PlayerState::CONTINUE: { case State::CONTINUE: {
player_sprite_->setCurrentAnimation("dead"); player_sprite_->setCurrentAnimation("dead");
break; break;
} }
case PlayerState::CELEBRATING: { case State::CELEBRATING: {
player_sprite_->setCurrentAnimation("celebration"); player_sprite_->setCurrentAnimation("celebration");
break; break;
} }
@@ -439,7 +452,7 @@ void Player::setAnimation() {
// Actualiza el valor de la variable // Actualiza el valor de la variable
void Player::updateCooldown() { void Player::updateCooldown() {
if (playing_state_ != PlayerState::PLAYING) { if (playing_state_ != State::PLAYING) {
return; return;
} }
@@ -488,14 +501,14 @@ void Player::handleCoolingState() {
void Player::transitionToRecoiling() { void Player::transitionToRecoiling() {
switch (firing_state_) { switch (firing_state_) {
case PlayerState::FIRING_LEFT: case State::FIRING_LEFT:
setFiringState(PlayerState::RECOILING_LEFT); setFiringState(State::RECOILING_LEFT);
break; break;
case PlayerState::FIRING_RIGHT: case State::FIRING_RIGHT:
setFiringState(PlayerState::RECOILING_RIGHT); setFiringState(State::RECOILING_RIGHT);
break; break;
case PlayerState::FIRING_UP: case State::FIRING_UP:
setFiringState(PlayerState::RECOILING_UP); setFiringState(State::RECOILING_UP);
break; break;
default: default:
break; break;
@@ -504,14 +517,14 @@ void Player::transitionToRecoiling() {
void Player::transitionToCooling() { void Player::transitionToCooling() {
switch (firing_state_) { switch (firing_state_) {
case PlayerState::RECOILING_LEFT: case State::RECOILING_LEFT:
setFiringState(PlayerState::COOLING_LEFT); setFiringState(State::COOLING_LEFT);
break; break;
case PlayerState::RECOILING_RIGHT: case State::RECOILING_RIGHT:
setFiringState(PlayerState::COOLING_RIGHT); setFiringState(State::COOLING_RIGHT);
break; break;
case PlayerState::RECOILING_UP: case State::RECOILING_UP:
setFiringState(PlayerState::COOLING_UP); setFiringState(State::COOLING_UP);
break; break;
default: default:
break; break;
@@ -519,7 +532,7 @@ void Player::transitionToCooling() {
} }
void Player::completeCooling() { void Player::completeCooling() {
setFiringState(PlayerState::FIRING_NONE); setFiringState(State::FIRING_NONE);
cooling_state_counter_ = -1; cooling_state_counter_ = -1;
} }
@@ -547,14 +560,14 @@ void Player::addScore(int score) {
// Actualiza el panel del marcador // Actualiza el panel del marcador
void Player::updateScoreboard() { void Player::updateScoreboard() {
switch (playing_state_) { switch (playing_state_) {
case PlayerState::CONTINUE: { case State::CONTINUE: {
Scoreboard::get()->setContinue(getScoreBoardPanel(), getContinueCounter()); Scoreboard::get()->setContinue(scoreboard_panel_, getContinueCounter());
break; break;
} }
case PlayerState::ENTERING_NAME: case State::ENTERING_NAME:
case PlayerState::ENTERING_NAME_GAME_COMPLETED: { case State::ENTERING_NAME_GAME_COMPLETED: {
Scoreboard::get()->setRecordName(getScoreBoardPanel(), enter_name_->getCurrentName()); Scoreboard::get()->setRecordName(scoreboard_panel_, enter_name_->getCurrentName());
Scoreboard::get()->setSelectorPos(getScoreBoardPanel(), getRecordNamePos()); Scoreboard::get()->setSelectorPos(scoreboard_panel_, getRecordNamePos());
break; break;
} }
default: default:
@@ -563,55 +576,70 @@ void Player::updateScoreboard() {
} }
// Cambia el modo del marcador // Cambia el modo del marcador
void Player::setScoreboardMode(ScoreboardMode mode) const { void Player::setScoreboardMode(Scoreboard::Mode mode) const {
if (!demo_) { if (!demo_) {
Scoreboard::get()->setMode(getScoreBoardPanel(), mode); Scoreboard::get()->setMode(scoreboard_panel_, mode);
} }
} }
// Establece el estado del jugador en el juego // Establece el estado del jugador en el juego
void Player::setPlayingState(PlayerState state) { void Player::setPlayingState(State state) {
playing_state_ = state; playing_state_ = state;
switch (playing_state_) { switch (playing_state_) {
case PlayerState::RESPAWNING: { case State::RESPAWNING: {
setInvulnerable(true); setInvulnerable(true);
addCredit(); addCredit();
playSound("voice_thankyou.wav"); playSound("voice_thankyou.wav");
setPlayingState(PlayerState::PLAYING); setPlayingState(State::PLAYING);
} }
case PlayerState::PLAYING: { case State::PLAYING: {
init(); init();
playing_state_ = PlayerState::PLAYING; playing_state_ = State::PLAYING;
setScoreboardMode(ScoreboardMode::SCORE); setScoreboardMode(Scoreboard::Mode::SCORE);
Stage::power_can_be_added = true; Stage::power_can_be_added = true;
break; break;
} }
case PlayerState::CONTINUE: { case State::CONTINUE: {
// Inicializa el contador de continuar // Inicializa el contador de continuar
continue_ticks_ = SDL_GetTicks(); continue_ticks_ = SDL_GetTicks();
continue_counter_ = 9; continue_counter_ = 9;
setScoreboardMode(ScoreboardMode::CONTINUE); setScoreboardMode(Scoreboard::Mode::CONTINUE);
playSound("continue_clock.wav"); playSound("continue_clock.wav");
break; break;
} }
case PlayerState::WAITING: { case State::WAITING: {
pos_x_ = default_pos_x_; switch (id_) {
setScoreboardMode(ScoreboardMode::WAITING); 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; break;
} }
case PlayerState::ENTERING_NAME: { case State::ENTERING_NAME: {
setScoreboardMode(ScoreboardMode::ENTER_NAME); setScoreboardMode(Scoreboard::Mode::ENTER_NAME);
break; break;
} }
case PlayerState::SHOWING_NAME: { case State::SHOWING_NAME: {
showing_name_ticks_ = SDL_GetTicks(); showing_name_ticks_ = SDL_GetTicks();
setScoreboardMode(ScoreboardMode::SHOW_NAME); setScoreboardMode(Scoreboard::Mode::SHOW_NAME);
Scoreboard::get()->setRecordName(scoreboard_panel_, last_enter_name_); Scoreboard::get()->setRecordName(scoreboard_panel_, last_enter_name_);
addScoreToScoreBoard(); addScoreToScoreBoard();
break; break;
} }
case PlayerState::ROLLING: { case State::ROLLING: {
// Activa la animación de rodar // Activa la animación de rodar
player_sprite_->setCurrentAnimation("rolling"); player_sprite_->setCurrentAnimation("rolling");
player_sprite_->setAnimationSpeed(4); 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); (rand() % 2 == 0) ? player_sprite_->setVelX(3.3F) : player_sprite_->setVelX(-3.3F);
break; break;
} }
case PlayerState::TITLE_ANIMATION: { case State::TITLE_ANIMATION: {
// Activa la animación de rodar // Activa la animación de rodar
player_sprite_->setCurrentAnimation("walk"); player_sprite_->setCurrentAnimation("walk");
playSound("voice_thankyou.wav"); playSound("voice_thankyou.wav");
break; break;
} }
case PlayerState::TITLE_HIDDEN: { case State::TITLE_HIDDEN: {
player_sprite_->setVelX(0.0F); player_sprite_->setVelX(0.0F);
player_sprite_->setVelY(0.0F); player_sprite_->setVelY(0.0F);
break; break;
} }
case PlayerState::CONTINUE_TIME_OUT: { case State::CONTINUE_TIME_OUT: {
// Activa la animación de morir // Activa la animación de morir
player_sprite_->setAccelY(0.2F); player_sprite_->setAccelY(0.2F);
player_sprite_->setVelY(-4.0F); player_sprite_->setVelY(-4.0F);
player_sprite_->setVelX(0.0F); player_sprite_->setVelX(0.0F);
player_sprite_->setCurrentAnimation("rolling"); player_sprite_->setCurrentAnimation("rolling");
player_sprite_->setAnimationSpeed(5); player_sprite_->setAnimationSpeed(5);
setScoreboardMode(ScoreboardMode::GAME_OVER); setScoreboardMode(Scoreboard::Mode::GAME_OVER);
playSound("voice_aw_aw_aw.wav"); playSound("voice_aw_aw_aw.wav");
playSound("jump.wav"); playSound("jump.wav");
break; break;
} }
case PlayerState::GAME_OVER: { case State::GAME_OVER: {
setScoreboardMode(ScoreboardMode::GAME_OVER); setScoreboardMode(Scoreboard::Mode::GAME_OVER);
break; break;
} }
case PlayerState::CELEBRATING: { case State::CELEBRATING: {
game_completed_ = true; game_completed_ = true;
setScoreboardMode(ScoreboardMode::SCORE); setScoreboardMode(Scoreboard::Mode::SCORE);
break; break;
} }
case PlayerState::ENTERING_NAME_GAME_COMPLETED: { case State::ENTERING_NAME_GAME_COMPLETED: {
setWalkingState(PlayerState::WALKING_STOP); setWalkingState(State::WALKING_STOP);
setFiringState(PlayerState::FIRING_NONE); setFiringState(State::FIRING_NONE);
setScoreboardMode(ScoreboardMode::ENTER_NAME); setScoreboardMode(Scoreboard::Mode::ENTER_NAME);
break; break;
} }
case PlayerState::LEAVING_SCREEN: { case State::LEAVING_SCREEN: {
step_counter_ = 0; step_counter_ = 0;
setScoreboardMode(ScoreboardMode::GAME_COMPLETED); setScoreboardMode(Scoreboard::Mode::GAME_COMPLETED);
break; break;
} }
case PlayerState::ENTERING_SCREEN: { case State::ENTERING_SCREEN: {
step_counter_ = 0; step_counter_ = 0;
setScoreboardMode(ScoreboardMode::SCORE); setScoreboardMode(Scoreboard::Mode::SCORE);
switch (id_) { switch (id_) {
case 1: case 1:
pos_x_ = param.game.game_area.rect.x - WIDTH; pos_x_ = param.game.game_area.rect.x - WIDTH;
@@ -680,8 +708,8 @@ void Player::setPlayingState(PlayerState state) {
} }
break; break;
} }
case PlayerState::CREDITS: { case State::CREDITS: {
vel_x_ = (walking_state_ == PlayerState::WALKING_RIGHT) ? BASE_SPEED : -BASE_SPEED; vel_x_ = (walking_state_ == State::WALKING_RIGHT) ? BASE_SPEED : -BASE_SPEED;
break; break;
} }
default: default:
@@ -709,7 +737,7 @@ void Player::setInvulnerable(bool value) {
// Monitoriza el estado // Monitoriza el estado
void Player::updateInvulnerable() { void Player::updateInvulnerable() {
if (playing_state_ == PlayerState::PLAYING) { if (playing_state_ == State::PLAYING) {
if (invulnerable_) { if (invulnerable_) {
if (invulnerable_counter_ > 0) { if (invulnerable_counter_ > 0) {
--invulnerable_counter_; --invulnerable_counter_;
@@ -730,7 +758,7 @@ void Player::setPowerUp() {
// Actualiza el valor de la variable // Actualiza el valor de la variable
void Player::updatePowerUp() { void Player::updatePowerUp() {
if (playing_state_ == PlayerState::PLAYING) { if (playing_state_ == State::PLAYING) {
if (power_up_) { if (power_up_) {
--power_up_counter_; --power_up_counter_;
power_up_ = power_up_counter_ > 0; power_up_ = power_up_counter_ > 0;
@@ -772,7 +800,7 @@ void Player::setPlayerTextures(const std::vector<std::shared_ptr<Texture>> &text
// Actualiza el contador de continue // Actualiza el contador de continue
void Player::updateContinueCounter() { void Player::updateContinueCounter() {
if (playing_state_ == PlayerState::CONTINUE) { if (playing_state_ == State::CONTINUE) {
constexpr int TICKS_SPEED = 1000; constexpr int TICKS_SPEED = 1000;
if (SDL_GetTicks() - continue_ticks_ > TICKS_SPEED) { if (SDL_GetTicks() - continue_ticks_ > TICKS_SPEED) {
decContinueCounter(); decContinueCounter();
@@ -782,7 +810,7 @@ void Player::updateContinueCounter() {
// Actualiza el contador de entrar nombre // Actualiza el contador de entrar nombre
void Player::updateEnterNameCounter() { 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; constexpr int TICKS_SPEED = 1000;
if (SDL_GetTicks() - name_entry_ticks_ > TICKS_SPEED) { if (SDL_GetTicks() - name_entry_ticks_ > TICKS_SPEED) {
decNameEntryCounter(); decNameEntryCounter();
@@ -792,10 +820,10 @@ void Player::updateEnterNameCounter() {
// Actualiza el estado de SHOWING_NAME // Actualiza el estado de SHOWING_NAME
void Player::updateShowingName() { void Player::updateShowingName() {
if (playing_state_ == PlayerState::SHOWING_NAME) { if (playing_state_ == State::SHOWING_NAME) {
constexpr int TICKS_SPEED = 5000; constexpr int TICKS_SPEED = 5000;
if (SDL_GetTicks() - name_entry_ticks_ > TICKS_SPEED) { 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_ticks_ = SDL_GetTicks();
--continue_counter_; --continue_counter_;
if (continue_counter_ < 0) { if (continue_counter_ < 0) {
setPlayingState(PlayerState::CONTINUE_TIME_OUT); setPlayingState(State::CONTINUE_TIME_OUT);
} else { } else {
playSound("continue_clock.wav"); playSound("continue_clock.wav");
} }
@@ -824,11 +852,11 @@ void Player::decNameEntryCounter() {
(name_entry_idle_counter_ >= param.game.name_entry_idle_time)) { (name_entry_idle_counter_ >= param.game.name_entry_idle_time)) {
name_entry_total_counter_ = 0; name_entry_total_counter_ = 0;
name_entry_idle_counter_ = 0; name_entry_idle_counter_ = 0;
if (playing_state_ == PlayerState::ENTERING_NAME) { if (playing_state_ == State::ENTERING_NAME) {
last_enter_name_ = getRecordName(); last_enter_name_ = getRecordName();
setPlayingState(PlayerState::SHOWING_NAME); setPlayingState(State::SHOWING_NAME);
} else { } 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 // Indica si se puede dibujar el objeto
auto Player::isRenderable() const -> bool { auto Player::isRenderable() const -> bool {
return !isWaiting() && !isGameOver() && !isTitleHidden(); return !isGameOver() && !isTitleHidden();
}; };
// Añade una puntuación a la tabla de records // Añade una puntuación a la tabla de records

View File

@@ -10,58 +10,59 @@
#include "enter_name.h" // Para EnterName #include "enter_name.h" // Para EnterName
#include "manage_hiscore_table.h" // Para HiScoreEntry #include "manage_hiscore_table.h" // Para HiScoreEntry
#include "options.h" // Para SettingsOptions, settings #include "options.h" // Para SettingsOptions, settings
#include "scoreboard.h" // Para Scoreboard
#include "utils.h" // Para Circle #include "utils.h" // Para Circle
class Texture; class Texture;
enum class InputAction : int; enum class InputAction : int;
enum class ScoreboardMode; enum class Mode;
// --- 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
};
// --- Clase Player --- // --- Clase Player ---
class Player { class Player {
public: 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 --- // --- Constructor y destructor ---
Player(int id, float x, int y, bool demo, SDL_FRect &play_area, std::vector<std::shared_ptr<Texture>> texture, const std::vector<std::vector<std::string>> &animations); Player(int id, float x, int y, bool demo, SDL_FRect &play_area, std::vector<std::shared_ptr<Texture>> texture, const std::vector<std::vector<std::string>> &animations);
~Player() = default; ~Player() = default;
@@ -92,36 +93,36 @@ class Player {
void decScoreMultiplier(); // Decrementa el multiplicador void decScoreMultiplier(); // Decrementa el multiplicador
// --- Estados de juego --- // --- Estados de juego ---
void setPlayingState(PlayerState state); // Cambia el estado de juego void setPlayingState(State state); // Cambia el estado de juego
void setInvulnerable(bool value); // Establece el valor del estado de invulnerabilidad void setInvulnerable(bool value); // Establece el valor del estado de invulnerabilidad
void setPowerUp(); // Activa el modo PowerUp void setPowerUp(); // Activa el modo PowerUp
void updatePowerUp(); // Actualiza el valor de PowerUp void updatePowerUp(); // Actualiza el valor de PowerUp
void giveExtraHit(); // Concede un toque extra al jugador void giveExtraHit(); // Concede un toque extra al jugador
void removeExtraHit(); // Quita el toque extra al jugador void removeExtraHit(); // Quita el toque extra al jugador
void decContinueCounter(); // Decrementa el contador de continuar void decContinueCounter(); // Decrementa el contador de continuar
// --- Getters y comprobaciones de estado --- // --- 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 [[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 // Comprobación de playing_state
[[nodiscard]] auto isLyingOnTheFloorForever() const -> bool { return playing_state_ == PlayerState::LYING_ON_THE_FLOOR_FOREVER; } [[nodiscard]] auto isLyingOnTheFloorForever() const -> bool { return playing_state_ == State::LYING_ON_THE_FLOOR_FOREVER; }
[[nodiscard]] auto isCelebrating() const -> bool { return playing_state_ == PlayerState::CELEBRATING; } [[nodiscard]] auto isCelebrating() const -> bool { return playing_state_ == State::CELEBRATING; }
[[nodiscard]] auto isContinue() const -> bool { return playing_state_ == PlayerState::CONTINUE; } [[nodiscard]] auto isContinue() const -> bool { return playing_state_ == State::CONTINUE; }
[[nodiscard]] auto isDying() const -> bool { return playing_state_ == PlayerState::ROLLING; } [[nodiscard]] auto isDying() const -> bool { return playing_state_ == State::ROLLING; }
[[nodiscard]] auto isEnteringName() const -> bool { return playing_state_ == PlayerState::ENTERING_NAME; } [[nodiscard]] auto isEnteringName() const -> bool { return playing_state_ == State::ENTERING_NAME; }
[[nodiscard]] auto isShowingName() const -> bool { return playing_state_ == PlayerState::SHOWING_NAME; } [[nodiscard]] auto isShowingName() const -> bool { return playing_state_ == State::SHOWING_NAME; }
[[nodiscard]] auto isEnteringNameGameCompleted() const -> bool { return playing_state_ == PlayerState::ENTERING_NAME_GAME_COMPLETED; } [[nodiscard]] auto isEnteringNameGameCompleted() const -> bool { return playing_state_ == State::ENTERING_NAME_GAME_COMPLETED; }
[[nodiscard]] auto isLeavingScreen() const -> bool { return playing_state_ == PlayerState::LEAVING_SCREEN; } [[nodiscard]] auto isLeavingScreen() const -> bool { return playing_state_ == State::LEAVING_SCREEN; }
[[nodiscard]] auto isGameOver() const -> bool { return playing_state_ == PlayerState::GAME_OVER; } [[nodiscard]] auto isGameOver() const -> bool { return playing_state_ == State::GAME_OVER; }
[[nodiscard]] auto isPlaying() const -> bool { return playing_state_ == PlayerState::PLAYING; } [[nodiscard]] auto isPlaying() const -> bool { return playing_state_ == State::PLAYING; }
[[nodiscard]] auto isWaiting() const -> bool { return playing_state_ == PlayerState::WAITING; } [[nodiscard]] auto isWaiting() const -> bool { return playing_state_ == State::WAITING; }
[[nodiscard]] auto isTitleHidden() const -> bool { return playing_state_ == PlayerState::TITLE_HIDDEN; } [[nodiscard]] auto isTitleHidden() const -> bool { return playing_state_ == State::TITLE_HIDDEN; }
// Getters // Getters
[[nodiscard]] auto canFire() const -> bool { return cant_fire_counter_ <= 0; } [[nodiscard]] auto canFire() const -> bool { return cant_fire_counter_ <= 0; }
[[nodiscard]] auto hasExtraHit() const -> bool { return extra_hit_; } [[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 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_ == PlayerState::RECOILING_LEFT || firing_state_ == PlayerState::RECOILING_UP || firing_state_ == PlayerState::RECOILING_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 isEligibleForHighScore() const -> bool { return score_ > Options::settings.hi_score_table.back().score; }
[[nodiscard]] auto isInvulnerable() const -> bool { return invulnerable_; } [[nodiscard]] auto isInvulnerable() const -> bool { return invulnerable_; }
[[nodiscard]] auto isPowerUp() const -> bool { return power_up_; } [[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 getRecordName() const -> std::string { return enter_name_ ? enter_name_->getFinalName() : "xxx"; }
[[nodiscard]] auto getLastEnterName() const -> std::string { return last_enter_name_; } [[nodiscard]] auto getLastEnterName() const -> std::string { return last_enter_name_; }
[[nodiscard]] auto getScore() const -> int { return score_; } [[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]] 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 getName() const -> const std::string & { return name_; }
[[nodiscard]] auto get1CC() const -> bool { return game_completed_ && credits_used_ == 1; } [[nodiscard]] auto get1CC() const -> bool { return game_completed_ && credits_used_ == 1; }
[[nodiscard]] auto getEnterNamePositionOverflow() const -> bool { return enter_name_ ? enter_name_->getPositionOverflow() : false; } [[nodiscard]] auto getEnterNamePositionOverflow() const -> bool { return enter_name_ ? enter_name_->getPositionOverflow() : false; }
@@ -149,25 +150,26 @@ class Player {
// Setters inline // Setters inline
void setController(int index) { controller_index_ = index; } void setController(int index) { controller_index_ = index; }
void setCantFireCounter(int counter) { recoiling_state_duration_ = cant_fire_counter_ = counter; } 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 setInvulnerableCounter(int value) { invulnerable_counter_ = value; }
void setName(const std::string &name) { name_ = name; } void setName(const std::string &name) { name_ = name; }
void setPowerUpCounter(int value) { power_up_counter_ = value; } void setPowerUpCounter(int value) { power_up_counter_ = value; }
void setScore(int score) { score_ = score; } 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 setScoreMultiplier(float value) { score_multiplier_ = value; }
void setWalkingState(PlayerState state) { walking_state_ = state; } void setWalkingState(State state) { walking_state_ = state; }
void addCredit() { ++credits_used_; } void addCredit() { ++credits_used_; }
private: private:
// --- Constantes --- // --- Constantes ---
static constexpr int POWERUP_COUNTER = 1500; // Duración del estado PowerUp 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 INVULNERABLE_COUNTER = 200; // Duración del estado invulnerable
static constexpr int WIDTH = 30; // Anchura static constexpr int WIDTH = 32; // Anchura
static constexpr int HEIGHT = 30; // Altura static constexpr int HEIGHT = 32; // Altura
static constexpr float BASE_SPEED = 1.5F; // Velocidad base del jugador static constexpr float BASE_SPEED = 1.5F; // Velocidad base del jugador
static constexpr int COOLING_DURATION = 50; static constexpr int COOLING_DURATION = 50;
static constexpr int COOLING_COMPLETE = 0; static constexpr int COOLING_COMPLETE = 0;
static constexpr int WAITING_COUNTER = 1000;
// --- Objetos y punteros --- // --- Objetos y punteros ---
std::unique_ptr<AnimatedSprite> player_sprite_; // Sprite para dibujar el jugador std::unique_ptr<AnimatedSprite> player_sprite_; // Sprite para dibujar el jugador
@@ -175,81 +177,83 @@ class Player {
std::unique_ptr<EnterName> enter_name_; // Clase utilizada para introducir el nombre std::unique_ptr<EnterName> enter_name_; // Clase utilizada para introducir el nombre
// --- Variables de estado --- // --- Variables de estado ---
int id_; // Número de identificación para el jugador. Player1 = 1, Player2 = 2 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 SDL_FRect play_area_; // Rectángulo con la zona de juego
float pos_x_ = 0.0F; // Posición en el eje X float pos_x_ = 0.0F; // Posición en el eje X
int pos_y_ = 0; // Posición en el eje Y int pos_y_ = 0; // Posición en el eje Y
float default_pos_x_; // Posición inicial para el jugador float default_pos_x_; // Posición inicial para el jugador
int default_pos_y_; // 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 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 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 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_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 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 cooling_state_counter_ = 0; // Contador para la animación del estado cooling
int score_ = 0; // Puntos del jugador int score_ = 0; // Puntos del jugador
float score_multiplier_ = 1.0F; // Multiplicador de puntos float score_multiplier_ = 1.0F; // Multiplicador de puntos
PlayerState walking_state_ = PlayerState::WALKING_STOP; // Estado del jugador al moverse State walking_state_ = State::WALKING_STOP; // Estado del jugador al moverse
PlayerState firing_state_ = PlayerState::FIRING_NONE; // Estado del jugador al disparar State firing_state_ = State::FIRING_NONE; // Estado del jugador al disparar
PlayerState playing_state_ = PlayerState::WAITING; // Estado del jugador en el juego State playing_state_ = State::WAITING; // Estado del jugador en el juego
bool invulnerable_ = true; // Indica si el jugador es invulnerable bool invulnerable_ = true; // Indica si el jugador es invulnerable
int invulnerable_counter_ = INVULNERABLE_COUNTER; // Contador para la invulnerabilidad int invulnerable_counter_ = INVULNERABLE_COUNTER; // Contador para la invulnerabilidad
bool extra_hit_ = false; // Indica si el jugador tiene un toque extra bool extra_hit_ = false; // Indica si el jugador tiene un toque extra
int coffees_ = 0; // Indica cuántos cafés lleva acumulados int coffees_ = 0; // Indica cuántos cafés lleva acumulados
bool power_up_ = false; // Indica si el jugador tiene activo el modo PowerUp 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_counter_ = POWERUP_COUNTER; // Temporizador para el modo PowerUp
int power_up_x_offset_ = 0; // Desplazamiento del sprite de PowerUp respecto al sprite del jugador 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 Circle collider_ = Circle(0, 0, 9); // Círculo de colisión del jugador
int continue_counter_ = 10; // Contador para poder continuar 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 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 Scoreboard::Id scoreboard_panel_ = Scoreboard::Id::LEFT; // Panel del marcador asociado al jugador
std::string name_; // Nombre del jugador std::string name_; // Nombre del jugador
int controller_index_ = 0; // Índice del array de mandos que utilizará para moverse 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 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_idle_counter_ = 0; // Contador para poner nombre
int name_entry_total_counter_ = 0; // Segundos totales que lleva acumulados poniendo 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 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 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 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 bool game_completed_ = false; // Indica si ha completado el juego
int credits_used_ = 1; // Indica el número de veces que ha continuado 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 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 --- // --- Métodos internos ---
void shiftColliders(); // Actualiza el círculo de colisión a la posición del jugador void shiftColliders(); // Actualiza el círculo de colisión a la posición del jugador
void shiftSprite(); // Recoloca el sprite void shiftSprite(); // Recoloca el sprite
void updateInvulnerable(); // Monitoriza el estado de invulnerabilidad void updateInvulnerable(); // Monitoriza el estado de invulnerabilidad
void updateContinueCounter(); // Actualiza el contador de continue void updateContinueCounter(); // Actualiza el contador de continue
void updateEnterNameCounter(); // Actualiza el contador de entrar nombre void updateEnterNameCounter(); // Actualiza el contador de entrar nombre
void updateShowingName(); // Actualiza el estado SHOWING_NAME void updateShowingName(); // Actualiza el estado SHOWING_NAME
void decNameEntryCounter(); // Decrementa el contador de entrar nombre void decNameEntryCounter(); // Decrementa el contador de entrar nombre
void updateScoreboard(); // Actualiza el panel del marcador void updateScoreboard(); // Actualiza el panel del marcador
void setScoreboardMode(ScoreboardMode mode) const; // Cambia el modo del marcador void setScoreboardMode(Scoreboard::Mode mode) const; // Cambia el modo del marcador
void playSound(const std::string &name) const; // Hace sonar un sonido void playSound(const std::string &name) const; // Hace sonar un sonido
[[nodiscard]] auto isRenderable() const -> bool; // Indica si se puede dibujar el objeto [[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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 handleWaitingMovement(); // Controla la animación del jugador saludando
void setInputBasedOnPlayerId(); // Asocia las entradas de control en función del identificador del jugador (teclas, mando, etc.) void updateWalkingStateForCredits(); // Actualiza el estado de caminata de algún personaje u elemento animado en los créditos
void updateStepCounter(); // Incrementa o ajusta el contador de pasos para animaciones o mecánicas relacionadas con movimiento 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
}; };

View File

@@ -17,20 +17,20 @@
#include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR #include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR
#include "texture.h" // Para Texture #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; 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() { void Scoreboard::init() {
Scoreboard::instance = new Scoreboard(); 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() { void Scoreboard::destroy() {
delete Scoreboard::instance; 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 * { auto Scoreboard::get() -> Scoreboard * {
return Scoreboard::instance; return Scoreboard::instance;
} }
@@ -42,18 +42,18 @@ Scoreboard::Scoreboard()
power_meter_sprite_(std::make_unique<Sprite>(game_power_meter_texture_)), power_meter_sprite_(std::make_unique<Sprite>(game_power_meter_texture_)),
text_scoreboard_(Resource::get()->getText("8bithud")) { text_scoreboard_(Resource::get()->getText("8bithud")) {
// Inicializa variables // Inicializa variables
for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) { for (size_t i = 0; i < static_cast<size_t>(Id::SIZE); ++i) {
name_[i].clear(); name_.at(i).clear();
record_name_[i].clear(); record_name_.at(i).clear();
selector_pos_[i] = 0; selector_pos_.at(i) = 0;
score_[i] = 0; score_.at(i) = 0;
mult_[i] = 0; mult_.at(i) = 0;
continue_counter_[i] = 0; continue_counter_.at(i) = 0;
} }
panel_[SCOREBOARD_LEFT_PANEL].mode = ScoreboardMode::SCORE; panel_.at(static_cast<size_t>(Id::LEFT)).mode = Mode::SCORE;
panel_[SCOREBOARD_RIGHT_PANEL].mode = ScoreboardMode::SCORE; panel_.at(static_cast<size_t>(Id::RIGHT)).mode = Mode::SCORE;
panel_[SCOREBOARD_CENTER_PANEL].mode = ScoreboardMode::STAGE_INFO; panel_.at(static_cast<size_t>(Id::CENTER)).mode = Mode::STAGE_INFO;
// Recalcula las anclas de los elementos // Recalcula las anclas de los elementos
recalculateAnchors(); recalculateAnchors();
@@ -147,9 +147,9 @@ void Scoreboard::fillPanelTextures() {
auto *temp = SDL_GetRenderTarget(renderer_); auto *temp = SDL_GetRenderTarget(renderer_);
// Genera el contenido de cada panel_ // Genera el contenido de cada panel_
for (size_t i = 0; i < SCOREBOARD_MAX_PANELS; ++i) { for (size_t i = 0; i < static_cast<int>(Id::SIZE); ++i) {
// Cambia el destino del renderizador // Cambia el destino del renderizador
SDL_SetRenderTarget(renderer_, panel_texture_[i]); SDL_SetRenderTarget(renderer_, panel_texture_.at(i));
// Dibuja el fondo de la textura // Dibuja el fondo de la textura
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0); SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
@@ -163,32 +163,32 @@ void Scoreboard::fillPanelTextures() {
} }
void Scoreboard::renderPanelContent(size_t panel_index) { void Scoreboard::renderPanelContent(size_t panel_index) {
switch (panel_[panel_index].mode) { switch (panel_.at(panel_index).mode) {
case ScoreboardMode::SCORE: case Mode::SCORE:
renderScoreMode(panel_index); renderScoreMode(panel_index);
break; break;
case ScoreboardMode::DEMO: case Mode::DEMO:
renderDemoMode(); renderDemoMode();
break; break;
case ScoreboardMode::WAITING: case Mode::WAITING:
renderWaitingMode(); renderWaitingMode();
break; break;
case ScoreboardMode::GAME_OVER: case Mode::GAME_OVER:
renderGameOverMode(); renderGameOverMode();
break; break;
case ScoreboardMode::STAGE_INFO: case Mode::STAGE_INFO:
renderStageInfoMode(); renderStageInfoMode();
break; break;
case ScoreboardMode::CONTINUE: case Mode::CONTINUE:
renderContinueMode(panel_index); renderContinueMode(panel_index);
break; break;
case ScoreboardMode::ENTER_NAME: case Mode::ENTER_NAME:
renderEnterNameMode(panel_index); renderEnterNameMode(panel_index);
break; break;
case ScoreboardMode::SHOW_NAME: case Mode::SHOW_NAME:
renderShowNameMode(panel_index); renderShowNameMode(panel_index);
break; break;
case ScoreboardMode::GAME_COMPLETED: case Mode::GAME_COMPLETED:
renderGameCompletedMode(panel_index); renderGameCompletedMode(panel_index);
break; break;
default: default:
@@ -198,12 +198,12 @@ void Scoreboard::renderPanelContent(size_t panel_index) {
void Scoreboard::renderScoreMode(size_t panel_index) { void Scoreboard::renderScoreMode(size_t panel_index) {
// SCORE // 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_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_[panel_index]), 1, text_color2_); text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_2_.x, slot4_2_.y, updateScoreText(score_.at(panel_index)), 1, text_color2_);
// MULT // 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_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() { void Scoreboard::renderDemoMode() {
@@ -257,18 +257,18 @@ void Scoreboard::renderStageInfoMode() {
void Scoreboard::renderContinueMode(size_t panel_index) { void Scoreboard::renderContinueMode(size_t panel_index) {
// SCORE // 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_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_[panel_index]), 1, text_color2_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_2_.x, slot4_2_.y, updateScoreText(score_.at(panel_index)), 1, text_color2_);
// CONTINUE // 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_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) { void Scoreboard::renderEnterNameMode(size_t panel_index) {
// SCORE // 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_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_[panel_index]), 1, text_color2_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_2_.x, slot4_2_.y, updateScoreText(score_.at(panel_index)), 1, text_color2_);
// ENTER NAME // ENTER NAME
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 11"), 1, text_color1_); 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 // Recorre todos los slots de letras del nombre
for (size_t j = 0; j < NAME_SIZE; ++j) { for (size_t j = 0; j < NAME_SIZE; ++j) {
// Selecciona el color // 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 // 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_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); SDL_RenderLine(renderer_, rect.x, rect.y + rect.h, rect.x + rect.w, rect.y + rect.h);
} }
// Dibuja la letra // Dibuja la letra
if (j < record_name_[panel_index].size()) { if (j < record_name_.at(panel_index).size()) {
text_scoreboard_->writeColored(rect.x, rect.y, record_name_[panel_index].substr(j, 1), COLOR); text_scoreboard_->writeColored(rect.x, rect.y, record_name_.at(panel_index).substr(j, 1), COLOR);
} }
} }
rect.x += 7; rect.x += 7;
@@ -302,17 +302,17 @@ void Scoreboard::renderNameInputField(size_t panel_index) {
void Scoreboard::renderShowNameMode(size_t panel_index) { void Scoreboard::renderShowNameMode(size_t panel_index) {
// SCORE // 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_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_[panel_index]), 1, text_color2_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_2_.x, slot4_2_.y, updateScoreText(score_.at(panel_index)), 1, text_color2_);
// NAME // NAME
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 11"), 1, text_color1_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 11"), 1, text_color1_);
/* TEXTO CENTRADO */ /* 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 */ /* 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) { void Scoreboard::renderGameCompletedMode(size_t panel_index) {
@@ -322,7 +322,7 @@ void Scoreboard::renderGameCompletedMode(size_t panel_index) {
// SCORE // SCORE
if (time_counter_ % 10 < 8) { 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_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_); SDL_RenderClear(renderer_);
// Copia las texturas de los paneles // Copia las texturas de los paneles
for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) { for (int i = 0; i < static_cast<int>(Id::SIZE); ++i) {
SDL_RenderTexture(renderer_, panel_texture_[i], nullptr, &panel_[i].pos); SDL_RenderTexture(renderer_, panel_texture_.at(i), nullptr, &panel_.at(i).pos);
} }
// Dibuja la linea que separa la zona de juego del marcador // Dibuja la linea que separa la zona de juego del marcador
@@ -354,12 +354,12 @@ void Scoreboard::fillBackgroundTexture() {
// Recalcula las anclas de los elementos // Recalcula las anclas de los elementos
void Scoreboard::recalculateAnchors() { void Scoreboard::recalculateAnchors() {
// Recalcula la posición y el tamaño de los paneles // Recalcula la posición y el tamaño de los paneles
const float PANEL_WIDTH = rect_.w / (float)SCOREBOARD_MAX_PANELS; const float PANEL_WIDTH = rect_.w / (float)static_cast<int>(Id::SIZE);
for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) { for (int i = 0; i < static_cast<int>(Id::SIZE); ++i) {
panel_[i].pos.x = roundf(PANEL_WIDTH * i); panel_.at(i).pos.x = roundf(PANEL_WIDTH * i);
panel_[i].pos.y = 0; panel_.at(i).pos.y = 0;
panel_[i].pos.w = roundf(PANEL_WIDTH * (i + 1)) - panel_[i].pos.x; panel_.at(i).pos.w = roundf(PANEL_WIDTH * (i + 1)) - panel_.at(i).pos.x;
panel_[i].pos.h = rect_.h; panel_.at(i).pos.h = rect_.h;
} }
// Constantes para definir las zonas del panel_: 4 filas y 1 columna // Constantes para definir las zonas del panel_: 4 filas y 1 columna

View File

@@ -14,35 +14,36 @@ class Sprite;
class Text; class Text;
class Texture; 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 --- // --- Clase Scoreboard ---
class Scoreboard { class Scoreboard {
public: 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 --- // --- Métodos de singleton ---
static void init(); // Crea el objeto Scoreboard static void init(); // Crea el objeto Scoreboard
static void destroy(); // Libera el objeto Scoreboard static void destroy(); // Libera el objeto Scoreboard
@@ -55,16 +56,16 @@ class Scoreboard {
// --- Setters --- // --- Setters ---
void setColor(Color color); // Establece el color del marcador void setColor(Color color); // Establece el color del marcador
void setPos(SDL_FRect rect); // Establece la posición y tamaño 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<size_t>(id)) = continue_counter; }
void setHiScore(int hi_score) { hi_score_ = hi_score; } void setHiScore(int hi_score) { hi_score_ = hi_score; }
void setHiScoreName(const std::string &name) { hi_score_name_ = name; } void setHiScoreName(const std::string &name) { hi_score_name_ = name; }
void setMode(int index, ScoreboardMode mode) { panel_[index].mode = mode; } void setMode(Id id, Mode mode) { panel_.at(static_cast<size_t>(id)).mode = mode; }
void setMult(int panel, float mult) { mult_[panel] = mult; } void setMult(Id id, float mult) { mult_.at(static_cast<size_t>(id)) = mult; }
void setName(int panel, const std::string &name) { name_[panel] = name; } void setName(Id id, const std::string &name) { name_.at(static_cast<size_t>(id)) = name; }
void setPower(float power) { power_ = power; } void setPower(float power) { power_ = power; }
void setRecordName(int panel, const std::string &record_name) { record_name_[panel] = record_name; } void setRecordName(Id id, const std::string &record_name) { record_name_.at(static_cast<size_t>(id)) = record_name; }
void setScore(int panel, int score) { score_[panel] = score; } void setScore(Id id, int score) { score_.at(static_cast<size_t>(id)) = score; }
void setSelectorPos(int panel, int pos) { selector_pos_[panel] = pos; } void setSelectorPos(Id id, int pos) { selector_pos_.at(static_cast<size_t>(id)) = pos; }
void setStage(int stage) { stage_ = stage; } void setStage(int stage) { stage_ = stage; }
private: private:
@@ -77,13 +78,13 @@ class Scoreboard {
std::vector<SDL_Texture *> panel_texture_; // Texturas para dibujar cada panel std::vector<SDL_Texture *> panel_texture_; // Texturas para dibujar cada panel
// --- Variables de estado --- // --- Variables de estado ---
std::array<std::string, SCOREBOARD_MAX_PANELS> name_ = {}; // Nombre de cada jugador std::array<std::string, static_cast<int>(Id::SIZE)> name_ = {}; // Nombre de cada jugador
std::array<std::string, SCOREBOARD_MAX_PANELS> record_name_ = {}; // Nombre introducido para la tabla de records std::array<std::string, static_cast<int>(Id::SIZE)> record_name_ = {}; // Nombre introducido para la tabla de records
std::array<size_t, SCOREBOARD_MAX_PANELS> selector_pos_ = {}; // Posición del selector de letra para introducir el nombre std::array<size_t, static_cast<int>(Id::SIZE)> selector_pos_ = {}; // Posición del selector de letra para introducir el nombre
std::array<int, SCOREBOARD_MAX_PANELS> score_ = {}; // Puntuación de los jugadores std::array<int, static_cast<int>(Id::SIZE)> score_ = {}; // Puntuación de los jugadores
std::array<float, SCOREBOARD_MAX_PANELS> mult_ = {}; // Multiplicador de los jugadores std::array<float, static_cast<int>(Id::SIZE)> mult_ = {}; // Multiplicador de los jugadores
std::array<int, SCOREBOARD_MAX_PANELS> continue_counter_ = {}; // Tiempo para continuar de los jugadores std::array<int, static_cast<int>(Id::SIZE)> continue_counter_ = {}; // Tiempo para continuar de los jugadores
std::array<Panel, SCOREBOARD_MAX_PANELS> panel_ = {}; // Lista con todos los paneles del marcador std::array<Panel, static_cast<int>(Id::SIZE)> panel_ = {}; // Lista con todos los paneles del marcador
int stage_ = 1; // Número de fase actual int stage_ = 1; // Número de fase actual
int hi_score_ = 0; // Máxima puntuación int hi_score_ = 0; // Máxima puntuación

View File

@@ -354,12 +354,12 @@ void Credits::initPlayers() {
constexpr bool DEMO = false; constexpr bool DEMO = false;
constexpr int AWAY_DISTANCE = 700; constexpr int AWAY_DISTANCE = 700;
players_.emplace_back(std::make_unique<Player>(1, play_area_.x - AWAY_DISTANCE - PLAYER_WIDTH, Y, DEMO, play_area_, player_textures.at(0), player_animations)); players_.emplace_back(std::make_unique<Player>(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()->setWalkingState(Player::State::WALKING_RIGHT);
players_.back()->setPlayingState(PlayerState::CREDITS); players_.back()->setPlayingState(Player::State::CREDITS);
players_.emplace_back(std::make_unique<Player>(2, play_area_.x + play_area_.w + AWAY_DISTANCE, Y, DEMO, play_area_, player_textures.at(1), player_animations)); players_.emplace_back(std::make_unique<Player>(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()->setWalkingState(Player::State::WALKING_LEFT);
players_.back()->setPlayingState(PlayerState::CREDITS); players_.back()->setPlayingState(Player::State::CREDITS);
} }
// Actualiza los rectangulos negros // Actualiza los rectangulos negros

View File

@@ -237,9 +237,7 @@ void Game::updatePlayers() {
// Dibuja a los jugadores // Dibuja a los jugadores
void Game::renderPlayers() { void Game::renderPlayers() {
for (auto &player : players_) { for (auto &player : players_) {
if (!player->isWaiting()) { player->render();
player->render();
}
} }
} }
@@ -363,9 +361,9 @@ void Game::updateGameStateCompleted() {
for (auto &player : players_) { for (auto &player : players_) {
if (player->isPlaying()) { if (player->isPlaying()) {
player->addScore(1000000); player->addScore(1000000);
player->setPlayingState(PlayerState::CELEBRATING); player->setPlayingState(Player::State::CELEBRATING);
} else { } 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) { if (game_completed_counter_ == END_CELEBRATIONS) {
for (auto &player : players_) { for (auto &player : players_) {
if (player->isCelebrating()) { 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 // Si los jugadores ya no estan y no quedan mensajes en pantalla
if (allPlayersAreGameOver() && path_sprites_.empty()) { if (allPlayersAreGameOver() && path_sprites_.empty()) {
setState(GameState::GAME_OVER); setState(State::GAME_OVER);
} }
// Incrementa el contador al final // Incrementa el contador al final
@@ -392,12 +390,12 @@ void Game::updateGameStateCompleted() {
// Comprueba el estado del juego // Comprueba el estado del juego
void Game::checkState() { void Game::checkState() {
if (state_ != GameState::COMPLETED && Stage::number == 10) { if (state_ != State::COMPLETED && Stage::number == 10) {
setState(GameState::COMPLETED); setState(State::COMPLETED);
} }
if (state_ != GameState::GAME_OVER && allPlayersAreGameOver()) { if (state_ != State::GAME_OVER && allPlayersAreGameOver()) {
setState(GameState::GAME_OVER); setState(State::GAME_OVER);
} }
} }
@@ -525,7 +523,7 @@ auto Game::checkBulletTabeCollision(std::shared_ptr<Bullet> bullet) -> bool {
return false; return false;
} }
tabe_->setState(TabeState::HIT); tabe_->setState(Tabe::State::HIT);
bullet->disable(); bullet->disable();
handleTabeHitEffects(); handleTabeHitEffects();
@@ -859,7 +857,7 @@ void Game::handlePlayerCollision(std::shared_ptr<Player> &player, std::shared_pt
} }
screen_->shake(); screen_->shake();
playSound("voice_no.wav"); playSound("voice_no.wav");
player->setPlayingState(PlayerState::ROLLING); player->setPlayingState(Player::State::ROLLING);
players_to_reorder_.push_back(player); players_to_reorder_.push_back(player);
if (allPlayersAreNotPlaying()) { if (allPlayersAreNotPlaying()) {
Stage::power_can_be_added = false; // No se puede subir poder de fase si no hay nadie jugando 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() { void Game::updateGameStates() {
if (!paused_) { if (!paused_) {
switch (state_) { switch (state_) {
case GameState::FADE_IN: case State::FADE_IN:
updateGameStateFadeIn(); updateGameStateFadeIn();
break; break;
case GameState::ENTERING_PLAYER: case State::ENTERING_PLAYER:
updateGameStateEnteringPlayer(); updateGameStateEnteringPlayer();
break; break;
case GameState::SHOWING_GET_READY_MESSAGE: case State::SHOWING_GET_READY_MESSAGE:
updateGameStateShowingGetReadyMessage(); updateGameStateShowingGetReadyMessage();
break; break;
case GameState::PLAYING: case State::PLAYING:
updateGameStatePlaying(); updateGameStatePlaying();
break; break;
case GameState::COMPLETED: case State::COMPLETED:
updateGameStateCompleted(); updateGameStateCompleted();
break; break;
case GameState::GAME_OVER: case State::GAME_OVER:
updateGameStateGameOver(); updateGameStateGameOver();
break; break;
default: default:
@@ -951,7 +949,7 @@ void Game::updateGameStates() {
// Actualiza el fondo // Actualiza el fondo
void Game::updateBackground() { void Game::updateBackground() {
// Si el juego está completado, se reduce la velocidad de las nubes // 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; Stage::total_power = (Stage::total_power > 200) ? (Stage::total_power - 25) : 200;
} }
@@ -1184,7 +1182,7 @@ void Game::addScoreToScoreBoard(const std::shared_ptr<Player> &player) {
// Saca del estado de GAME OVER al jugador si el otro está activo // Saca del estado de GAME OVER al jugador si el otro está activo
void Game::checkAndUpdatePlayerStatus(int active_player_index, int inactive_player_index) { 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()) { 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()) { if (allPlayersAreWaitingOrGameOver()) {
// Entonces los pone en estado de Game Over // Entonces los pone en estado de Game Over
for (auto &player : players_) { 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> &player, bool autofire
void Game::handlePlayerContinue(const std::shared_ptr<Player> &player) { void Game::handlePlayerContinue(const std::shared_ptr<Player> &player) {
const auto CONTROLLER_INDEX = player->getController(); 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)) { 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. // 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> &player) {
const auto CONTROLLER_INDEX = player->getController(); 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 (input_->checkInput(InputAction::FIRE_LEFT, INPUT_DO_NOT_ALLOW_REPEAT, Options::controllers[CONTROLLER_INDEX].type, Options::controllers[CONTROLLER_INDEX].index)) {
if (player->isShowingName()) { if (player->isShowingName()) {
player->setPlayingState(PlayerState::CONTINUE); player->setPlayingState(Player::State::CONTINUE);
} else if (player->getEnterNamePositionOverflow()) { } else if (player->getEnterNamePositionOverflow()) {
player->setInput(InputAction::START); player->setInput(InputAction::START);
addScoreToScoreBoard(player); addScoreToScoreBoard(player);
player->setPlayingState(PlayerState::SHOWING_NAME); player->setPlayingState(Player::State::SHOWING_NAME);
} else { } else {
player->setInput(InputAction::RIGHT); 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) || } 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)) { input_->checkInput(InputAction::FIRE_RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, Options::controllers[CONTROLLER_INDEX].type, Options::controllers[CONTROLLER_INDEX].index)) {
if (player->isShowingName()) { if (player->isShowingName()) {
player->setPlayingState(PlayerState::CONTINUE); player->setPlayingState(Player::State::CONTINUE);
} else { } else {
player->setInput(InputAction::LEFT); player->setInput(InputAction::LEFT);
} }
@@ -1454,11 +1456,11 @@ void Game::handleNameInput(const std::shared_ptr<Player> &player) {
player->setInput(InputAction::DOWN); 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)) { } else if (input_->checkInput(InputAction::START, INPUT_DO_NOT_ALLOW_REPEAT, Options::controllers[CONTROLLER_INDEX].type, Options::controllers[CONTROLLER_INDEX].index)) {
if (player->isShowingName()) { if (player->isShowingName()) {
player->setPlayingState(PlayerState::CONTINUE); player->setPlayingState(Player::State::CONTINUE);
} else { } else {
player->setInput(InputAction::START); player->setInput(InputAction::START);
addScoreToScoreBoard(player); 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> &player) {
void Game::initDemo(int player_id) { void Game::initDemo(int player_id) {
if (demo_.enabled) { if (demo_.enabled) {
// Cambia el estado del juego // Cambia el estado del juego
setState(GameState::PLAYING); setState(State::PLAYING);
// Aleatoriza la asignación del fichero con los datos del modo demostracion // 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) { if (rand() % 3 != 0) {
const auto OTHER_PLAYER_ID = player_id == 1 ? 2 : 1; const auto OTHER_PLAYER_ID = player_id == 1 ? 2 : 1;
auto other_player = getPlayer(OTHER_PLAYER_ID); auto other_player = getPlayer(OTHER_PLAYER_ID);
other_player->setPlayingState(PlayerState::PLAYING); other_player->setPlayingState(Player::State::PLAYING);
} }
// Asigna cafes a los jugadores // Asigna cafes a los jugadores
@@ -1507,8 +1509,8 @@ void Game::initDemo(int player_id) {
} }
// Configura los marcadores // Configura los marcadores
scoreboard_->setMode(SCOREBOARD_LEFT_PANEL, ScoreboardMode::DEMO); scoreboard_->setMode(Scoreboard::Id::LEFT, Scoreboard::Mode::DEMO);
scoreboard_->setMode(SCOREBOARD_RIGHT_PANEL, ScoreboardMode::DEMO); scoreboard_->setMode(Scoreboard::Id::RIGHT, Scoreboard::Mode::DEMO);
// Silencia los globos // Silencia los globos
balloon_manager_->setSounds(false); balloon_manager_->setSounds(false);
@@ -1534,11 +1536,11 @@ void Game::setTotalPower() {
// Inicializa el marcador // Inicializa el marcador
void Game::initScoreboard() { void Game::initScoreboard() {
scoreboard_->setPos(param.scoreboard.rect); 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_) { for (const auto &player : players_) {
scoreboard_->setName(player->getScoreBoardPanel(), player->getName()); scoreboard_->setName(player->getScoreBoardPanel(), player->getName());
if (player->isWaiting()) { 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 // Inicializa los jugadores
void Game::initPlayers(int player_id) { void Game::initPlayers(int player_id) {
// Crea los dos jugadores
constexpr int PLAYER_HEIGHT = 32; constexpr int PLAYER_HEIGHT = 32;
constexpr int PLAYER_WIDTH = 32; constexpr int PLAYER_WIDTH = 32;
const int Y = param.game.play_area.rect.h - PLAYER_HEIGHT + 1; 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<Player>(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_.emplace_back(std::make_unique<Player>(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()->setName(Lang::getText("[SCOREBOARD] 1"));
players_.back()->setController(getController(players_.back()->getId())); 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<Player>(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_.emplace_back(std::make_unique<Player>(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()->setName(Lang::getText("[SCOREBOARD] 2"));
players_.back()->setController(getController(players_.back()->getId())); 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" // Activa el jugador que coincide con el "player_id" o ambos si es "0"
if (player_id == 0) { if (player_id == 0) {
// Activa ambos jugadores // Activa ambos jugadores
getPlayer(1)->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 ? PlayerState::PLAYING : PlayerState::ENTERING_SCREEN); getPlayer(2)->setPlayingState(demo_.enabled ? Player::State::PLAYING : Player::State::ENTERING_SCREEN);
} else { } 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(); updateScoreboard();
updateBackground(); updateBackground();
if (fade_in_->hasEnded()) { if (fade_in_->hasEnded()) {
setState(GameState::ENTERING_PLAYER); setState(State::ENTERING_PLAYER);
balloon_manager_->createTwoBigBalloons(); balloon_manager_->createTwoBigBalloons();
evaluateAndSetMenace(); evaluateAndSetMenace();
} }
@@ -1689,7 +1695,7 @@ void Game::updateGameStateEnteringPlayer() {
updateBackground(); updateBackground();
for (const auto &player : players_) { for (const auto &player : players_) {
if (player->isPlaying()) { 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")); createMessage({paths_.at(0), paths_.at(1)}, Resource::get()->getTexture("game_text_get_ready"));
playSound("voice_get_ready.wav"); playSound("voice_get_ready.wav");
} }
@@ -1700,7 +1706,7 @@ void Game::updateGameStateEnteringPlayer() {
void Game::updateGameStateShowingGetReadyMessage() { void Game::updateGameStateShowingGetReadyMessage() {
updateGameStatePlaying(); updateGameStatePlaying();
if (path_sprites_.empty()) { if (path_sprites_.empty()) {
setState(GameState::PLAYING); setState(State::PLAYING);
} }
if (counter_ == 100) { if (counter_ == 100) {
playMusic(); playMusic();
@@ -1746,7 +1752,7 @@ void Game::cleanVectors() {
// Gestiona el nivel de amenaza // Gestiona el nivel de amenaza
void Game::updateMenace() { void Game::updateMenace() {
if (state_ == GameState::PLAYING) { if (state_ == State::PLAYING) {
const auto STAGE = Stage::get(Stage::number); const auto STAGE = Stage::get(Stage::number);
const float PERCENT = Stage::power / STAGE.power_to_complete; const float PERCENT = Stage::power / STAGE.power_to_complete;
const int DIFFERENCE = STAGE.max_menace - STAGE.min_menace; const int DIFFERENCE = STAGE.max_menace - STAGE.min_menace;
@@ -1787,7 +1793,7 @@ void Game::checkAndUpdateBalloonSpeed() {
} }
// Cambia el estado del juego // Cambia el estado del juego
void Game::setState(GameState state) { void Game::setState(State state) {
state_ = state; state_ = state;
counter_ = 0; counter_ = 0;
} }

View File

@@ -49,7 +49,7 @@ class Game {
private: private:
// --- Tipos internos --- // --- Tipos internos ---
enum class GameState { enum class State {
FADE_IN, FADE_IN,
ENTERING_PLAYER, ENTERING_PLAYER,
SHOWING_GET_READY_MESSAGE, 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 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_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 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<std::shared_ptr<Player>> players_to_reorder_; std::vector<std::shared_ptr<Player>> players_to_reorder_;
Hit hit_; // Para representar colisiones en pantalla Hit hit_; // Para representar colisiones en pantalla
@@ -155,13 +155,13 @@ class Game {
#endif #endif
// --- Ciclo principal del juego --- // --- Ciclo principal del juego ---
void update(); // Actualiza la lógica principal del juego void update(); // Actualiza la lógica principal del juego
void render(); // Renderiza todos los elementos del juego void render(); // Renderiza todos los elementos del juego
void checkEvents(); // Procesa los eventos del sistema en cola void checkEvents(); // Procesa los eventos del sistema en cola
void checkState(); // Verifica y actualiza el estado actual del juego void checkState(); // Verifica y actualiza el estado actual del juego
void setState(GameState state); // Cambia el estado del juego void setState(State state); // Cambia el estado del juego
void pause(bool value); // Pausa o reanuda el juego void pause(bool value); // Pausa o reanuda el juego
void cleanVectors(); // Limpia vectores de elementos deshabilitados void cleanVectors(); // Limpia vectores de elementos deshabilitados
// --- Gestión de estados del juego --- // --- Gestión de estados del juego ---
void updateGameStates(); // Actualiza todos los estados del juego void updateGameStates(); // Actualiza todos los estados del juego

View File

@@ -308,7 +308,7 @@ void Title::processPlayer2Start() {
} }
void Title::activatePlayerAndSetState(int player_id) { 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); setState(TitleState::START_HAS_BEEN_PRESSED);
counter_ = 0; counter_ = 0;
} }
@@ -559,10 +559,10 @@ void Title::initPlayers() {
const int Y = param.title.press_start_position - (PLAYER_HEIGHT / 2); const int Y = param.title.press_start_position - (PLAYER_HEIGHT / 2);
constexpr bool DEMO = false; constexpr bool DEMO = false;
players_.emplace_back(std::make_unique<Player>(1, param.game.game_area.center_x - (PLAYER_WIDTH / 2), Y, DEMO, param.game.play_area.rect, player_textures.at(0), player_animations)); players_.emplace_back(std::make_unique<Player>(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<Player>(2, param.game.game_area.center_x - (PLAYER_WIDTH / 2), Y, DEMO, param.game.play_area.rect, player_textures.at(1), player_animations)); players_.emplace_back(std::make_unique<Player>(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 // Actualza los jugadores

View File

@@ -15,7 +15,7 @@
// Constructor // Constructor
Tabe::Tabe() Tabe::Tabe()
: sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("tabe.png"), Resource::get()->getAnimation("tabe.ani"))), : sprite_(std::make_unique<AnimatedSprite>(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 // Actualiza la lógica
void Tabe::update() { void Tabe::update() {
@@ -49,23 +49,23 @@ void Tabe::move() {
const float MIN_X = param.game.game_area.rect.x - WIDTH; 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; const float MAX_X = param.game.game_area.rect.x + param.game.game_area.rect.w;
switch (destiny_) { switch (destiny_) {
case TabeDirection::TO_THE_LEFT: { case Direction::TO_THE_LEFT: {
if (x_ < MIN_X) { if (x_ < MIN_X) {
disable(); disable();
} }
if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH && direction_ == TabeDirection::TO_THE_RIGHT) { if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH && direction_ == Direction::TO_THE_RIGHT) {
setRandomFlyPath(TabeDirection::TO_THE_LEFT, 80); setRandomFlyPath(Direction::TO_THE_LEFT, 80);
x_ = param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH; x_ = param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH;
} }
break; break;
} }
case TabeDirection::TO_THE_RIGHT: { case Direction::TO_THE_RIGHT: {
if (x_ > MAX_X) { if (x_ > MAX_X) {
disable(); disable();
} }
if (x_ < param.game.game_area.rect.x && direction_ == TabeDirection::TO_THE_LEFT) { if (x_ < param.game.game_area.rect.x && direction_ == Direction::TO_THE_LEFT) {
setRandomFlyPath(TabeDirection::TO_THE_RIGHT, 80); setRandomFlyPath(Direction::TO_THE_RIGHT, 80);
x_ = param.game.game_area.rect.x; x_ = param.game.game_area.rect.x;
} }
break; break;
@@ -80,19 +80,19 @@ void Tabe::move() {
--waiting_counter_; --waiting_counter_;
} else { } else {
constexpr int CHOICES = 4; constexpr int CHOICES = 4;
const std::array<TabeDirection, CHOICES> LEFT = { const std::array<Direction, CHOICES> LEFT = {
TabeDirection::TO_THE_LEFT, Direction::TO_THE_LEFT,
TabeDirection::TO_THE_LEFT, Direction::TO_THE_LEFT,
TabeDirection::TO_THE_LEFT, Direction::TO_THE_LEFT,
TabeDirection::TO_THE_RIGHT}; Direction::TO_THE_RIGHT};
const std::array<TabeDirection, CHOICES> RIGHT = { const std::array<Direction, CHOICES> RIGHT = {
TabeDirection::TO_THE_LEFT, Direction::TO_THE_LEFT,
TabeDirection::TO_THE_RIGHT, Direction::TO_THE_RIGHT,
TabeDirection::TO_THE_RIGHT, Direction::TO_THE_RIGHT,
TabeDirection::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] ? LEFT[rand() % CHOICES]
: RIGHT[rand() % CHOICES]; : RIGHT[rand() % CHOICES];
@@ -113,10 +113,10 @@ void Tabe::enable() {
y_ = param.game.game_area.rect.y + 20.0F; y_ = param.game.game_area.rect.y + 20.0F;
// Establece una dirección aleatoria // 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 // 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 // Crea una ruta de vuelo
setRandomFlyPath(direction_, 60); setRandomFlyPath(direction_, 60);
@@ -125,7 +125,7 @@ void Tabe::enable() {
} }
// Establece un vuelo aleatorio // Establece un vuelo aleatorio
void Tabe::setRandomFlyPath(TabeDirection direction, int lenght) { void Tabe::setRandomFlyPath(Direction direction, int lenght) {
direction_ = direction; direction_ = direction;
fly_distance_ = lenght; fly_distance_ = lenght;
waiting_counter_ = 5 + rand() % 15; waiting_counter_ = 5 + rand() % 15;
@@ -134,14 +134,14 @@ void Tabe::setRandomFlyPath(TabeDirection direction, int lenght) {
constexpr float SPEED = 2.0F; constexpr float SPEED = 2.0F;
switch (direction) { switch (direction) {
case TabeDirection::TO_THE_LEFT: { case Direction::TO_THE_LEFT: {
speed_ = -1.0F * SPEED; speed_ = -1.0F * SPEED;
accel_ = -1.0F * (1 + rand() % 10) / 30.0F; accel_ = -1.0F * (1 + rand() % 10) / 30.0F;
sprite_->setFlip(SDL_FLIP_NONE); sprite_->setFlip(SDL_FLIP_NONE);
break; break;
} }
case TabeDirection::TO_THE_RIGHT: { case Direction::TO_THE_RIGHT: {
speed_ = SPEED; speed_ = SPEED;
accel_ = (1 + rand() % 10) / 30.0F; accel_ = (1 + rand() % 10) / 30.0F;
sprite_->setFlip(SDL_FLIP_HORIZONTAL); sprite_->setFlip(SDL_FLIP_HORIZONTAL);
@@ -154,16 +154,16 @@ void Tabe::setRandomFlyPath(TabeDirection direction, int lenght) {
} }
// Establece el estado // Establece el estado
void Tabe::setState(TabeState state) { void Tabe::setState(State state) {
if (enabled_) { if (enabled_) {
state_ = state; state_ = state;
switch (state) { switch (state) {
case TabeState::FLY: case State::FLY:
sprite_->setCurrentAnimation("fly"); sprite_->setCurrentAnimation("fly");
break; break;
case TabeState::HIT: case State::HIT:
sprite_->setCurrentAnimation("hit"); sprite_->setCurrentAnimation("hit");
hit_counter_ = 5; hit_counter_ = 5;
++number_of_hits_; ++number_of_hits_;
@@ -177,10 +177,10 @@ void Tabe::setState(TabeState state) {
// Actualiza el estado // Actualiza el estado
void Tabe::updateState() { void Tabe::updateState() {
if (state_ == TabeState::HIT) { if (state_ == State::HIT) {
--hit_counter_; --hit_counter_;
if (hit_counter_ == 0) { if (hit_counter_ == 0) {
setState(TabeState::FLY); setState(State::FLY);
} }
} }
} }

View File

@@ -7,96 +7,31 @@
#include "animated_sprite.h" // Para AnimatedSprite #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<Uint32>(min_time * MINUTES_TO_MILLISECONDS)),
max_spawn_time(static_cast<Uint32>(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 --- // --- Clase Tabe ---
class Tabe { class Tabe {
public: 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 --- // --- Constructores y destructor ---
Tabe(); Tabe();
~Tabe() = default; ~Tabe() = default;
// --- Métodos principales --- // --- Métodos principales ---
void update(); // Actualiza la lógica void update(); // Actualiza la lógica
void render(); // Dibuja el objeto void render(); // Dibuja el objeto
void enable(); // Habilita el objeto void enable(); // Habilita el objeto
void setState(TabeState state); // Establece el estado void setState(State state); // Establece el estado
auto tryToGetBonus() -> bool; // Intenta obtener el bonus auto tryToGetBonus() -> bool; // Intenta obtener el bonus
void pauseTimer(bool value); // Detiene/activa el timer void pauseTimer(bool value); // Detiene/activa el timer
// --- Getters --- // --- Getters ---
auto getCollider() -> SDL_FRect& { return sprite_->getRect(); } // Obtiene el área de colisión 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 WIDTH = 32;
static constexpr int HEIGHT = 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<Uint32>(min_time * MINUTES_TO_MILLISECONDS)),
max_spawn_time(static_cast<Uint32>(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 --- // --- Objetos y punteros ---
std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos y animaciones std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos y animaciones
// --- Variables de estado --- // --- Variables de estado ---
float x_ = 0; // Posición X float x_ = 0; // Posición X
float y_ = 0; // Posición Y float y_ = 0; // Posición Y
float speed_ = 0.0F; // Velocidad de movimiento float speed_ = 0.0F; // Velocidad de movimiento
float accel_ = 0.0F; // Aceleración float accel_ = 0.0F; // Aceleración
int fly_distance_ = 0; // Distancia de vuelo int fly_distance_ = 0; // Distancia de vuelo
int waiting_counter_ = 0; // Tiempo que pasa quieto int waiting_counter_ = 0; // Tiempo que pasa quieto
bool enabled_ = false; // Indica si el objeto está activo bool enabled_ = false; // Indica si el objeto está activo
TabeDirection direction_ = TabeDirection::TO_THE_LEFT; // Dirección actual Direction direction_ = Direction::TO_THE_LEFT; // Dirección actual
TabeDirection destiny_ = TabeDirection::TO_THE_LEFT; // Destino Direction destiny_ = Direction::TO_THE_LEFT; // Destino
TabeState state_ = TabeState::FLY; // Estado actual State state_ = State::FLY; // Estado actual
int hit_counter_ = 0; // Contador para el estado HIT int hit_counter_ = 0; // Contador para el estado HIT
int number_of_hits_ = 0; // Cantidad de disparos recibidos int number_of_hits_ = 0; // Cantidad de disparos recibidos
bool has_bonus_ = true; // Indica si aún tiene el bonus para soltar bool has_bonus_ = true; // Indica si aún tiene el bonus para soltar
TabeTimer timer_; // Temporizador para gestionar la aparición Timer timer_; // Temporizador para gestionar la aparición
// --- Métodos internos --- // --- Métodos internos ---
void move(); // Mueve el objeto void move(); // Mueve el objeto
void shiftSprite() { sprite_->setPos(x_, y_); } // Actualiza la posición del sprite void shiftSprite() { sprite_->setPos(x_, y_); } // Actualiza la posición del sprite
void setRandomFlyPath(TabeDirection direction, int lenght); // Establece un vuelo aleatorio void setRandomFlyPath(Direction direction, int lenght); // Establece un vuelo aleatorio
void updateState(); // Actualiza el estado void updateState(); // Actualiza el estado
void updateTimer(); // Actualiza el temporizador void updateTimer(); // Actualiza el temporizador
void disable(); // Deshabilita el objeto void disable(); // Deshabilita el objeto
}; };