// IWYU pragma: no_include #include "tabe.h" #include // Para SDL_FLIP_HORIZONTAL, SDL_FLIP_NONE #include // Para rand, abs #include // Para max #include "jail_audio.h" // Para JA_PlaySound #include "param.h" // Para Param, ParamGame, param #include "resource.h" // Para Resource #include "utils.h" // Para Zone // Constructor Tabe::Tabe() : sprite_(std::make_unique(Resource::get()->getTexture("tabe.png"), Resource::get()->getAnimation("tabe.ani"))), timer_(TabeTimer(2.5f, 4.0f)) {} // Actualiza la lógica void Tabe::update() { if (enabled_) { sprite_->update(); move(); updateState(); } timer_.update(); if (timer_.should_spawn()) { enable(); } } // Dibuja el objeto void Tabe::render() { if (enabled_) { sprite_->render(); } } // Mueve el objeto void Tabe::move() { const int x = static_cast(x_); speed_ += accel_; x_ += speed_; fly_distance_ -= std::abs(x - static_cast(x_)); // Comprueba si sale por los bordes const float min_x = param.game.game_area.rect.x - WIDTH_; const float max_x = param.game.game_area.rect.x + param.game.game_area.rect.w; switch (destiny_) { case TabeDirection::TO_THE_LEFT: { if (x_ < min_x) { disable(); } if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_ && direction_ == TabeDirection::TO_THE_RIGHT) { setRandomFlyPath(TabeDirection::TO_THE_LEFT, 80); x_ = param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_; } break; } case TabeDirection::TO_THE_RIGHT: { if (x_ > max_x) { disable(); } if (x_ < param.game.game_area.rect.x && direction_ == TabeDirection::TO_THE_LEFT) { setRandomFlyPath(TabeDirection::TO_THE_RIGHT, 80); x_ = param.game.game_area.rect.x; } break; } default: break; } if (fly_distance_ <= 0) { if (waiting_counter_ > 0) { accel_ = speed_ = 0.0f; --waiting_counter_; } else { constexpr int CHOICES = 4; const TabeDirection left[CHOICES] = {TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_RIGHT}; const TabeDirection right[CHOICES] = {TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_RIGHT, TabeDirection::TO_THE_RIGHT, TabeDirection::TO_THE_RIGHT}; const TabeDirection direction = destiny_ == TabeDirection::TO_THE_LEFT ? left[rand() % CHOICES] : right[rand() % CHOICES]; setRandomFlyPath(direction, 20 + rand() % 40); } } shiftSprite(); } // Habilita el objeto void Tabe::enable() { if (!enabled_) { enabled_ = true; has_bonus_ = true; hit_counter_ = 0; number_of_hits_ = 0; y_ = param.game.game_area.rect.y + 20.0f; // Establece una dirección aleatoria destiny_ = direction_ = rand() % 2 == 0 ? TabeDirection::TO_THE_LEFT : TabeDirection::TO_THE_RIGHT; // 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_; // Crea una ruta de vuelo setRandomFlyPath(direction_, 60); shiftSprite(); } } // Establece un vuelo aleatorio void Tabe::setRandomFlyPath(TabeDirection direction, int lenght) { direction_ = direction; fly_distance_ = lenght; waiting_counter_ = 5 + rand() % 15; JA_PlaySound(Resource::get()->getSound("tabe.wav")); constexpr float SPEED = 2.0f; switch (direction) { case TabeDirection::TO_THE_LEFT: { speed_ = -1.0f * SPEED; accel_ = -1.0f * (1 + rand() % 10) / 30.0f; sprite_->setFlip(SDL_FLIP_NONE); break; } case TabeDirection::TO_THE_RIGHT: { speed_ = SPEED; accel_ = (1 + rand() % 10) / 30.0f; sprite_->setFlip(SDL_FLIP_HORIZONTAL); break; } default: break; } } // Establece el estado void Tabe::setState(TabeState state) { if (enabled_) { state_ = state; switch (state) { case TabeState::FLY: sprite_->setCurrentAnimation("fly"); break; case TabeState::HIT: sprite_->setCurrentAnimation("hit"); hit_counter_ = 5; ++number_of_hits_; break; default: break; } } } // Actualiza el estado void Tabe::updateState() { if (state_ == TabeState::HIT) { --hit_counter_; if (hit_counter_ == 0) { setState(TabeState::FLY); } } } // Intenta obtener el bonus bool Tabe::tryToGetBonus() { if (has_bonus_ && rand() % std::max(1, 15 - number_of_hits_) == 0) { has_bonus_ = false; return true; } return false; } // Actualiza el temporizador void Tabe::updateTimer() { timer_.current_time = SDL_GetTicks(); timer_.delta_time = timer_.current_time - timer_.last_time; timer_.last_time = timer_.current_time; } // Deshabilita el objeto void Tabe::disable() { enabled_ = false; timer_.reset(); }