Files
coffee_crisis_arcade_edition/source/tabe.cpp
2025-08-17 10:20:41 +02:00

213 lines
5.6 KiB
C++

// IWYU pragma: no_include <bits/std_abs.h>
#include "tabe.h"
#include <SDL3/SDL.h> // Para SDL_FlipMode, SDL_GetTicks
#include <algorithm> // Para max
#include <array> // Para array
#include <cstdlib> // Para rand, abs
#include "audio.h" // Para Audio
#include "param.h" // Para Param, ParamGame, param
#include "resource.h" // Para Resource
#include "utils.h" // Para Zone
// Constructor
Tabe::Tabe()
: sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("tabe.png"), Resource::get()->getAnimation("tabe.ani"))),
timer_(Timer(param.tabe.min_spawn_time, param.tabe.max_spawn_time)) {}
// Actualiza la lógica
void Tabe::update() {
if (enabled_ && !timer_.is_paused) {
sprite_->update();
move();
updateState();
}
timer_.update();
if (timer_.shouldSpawn()) {
enable();
}
}
// Dibuja el objeto
void Tabe::render() {
if (enabled_) {
sprite_->render();
}
}
// Mueve el objeto
void Tabe::move() {
const int X = static_cast<int>(x_);
speed_ += accel_;
x_ += speed_;
fly_distance_ -= std::abs(X - static_cast<int>(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 Direction::TO_THE_LEFT: {
if (x_ < MIN_X) {
disable();
}
if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH && direction_ == Direction::TO_THE_RIGHT) {
setRandomFlyPath(Direction::TO_THE_LEFT, 80);
x_ = param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH;
}
break;
}
case Direction::TO_THE_RIGHT: {
if (x_ > MAX_X) {
disable();
}
if (x_ < param.game.game_area.rect.x && direction_ == Direction::TO_THE_LEFT) {
setRandomFlyPath(Direction::TO_THE_RIGHT, 80);
x_ = param.game.game_area.rect.x;
}
break;
}
default:
break;
}
if (fly_distance_ <= 0) {
if (waiting_counter_ > 0) {
accel_ = speed_ = 0.0F;
--waiting_counter_;
} else {
constexpr int CHOICES = 4;
const std::array<Direction, CHOICES> LEFT = {
Direction::TO_THE_LEFT,
Direction::TO_THE_LEFT,
Direction::TO_THE_LEFT,
Direction::TO_THE_RIGHT};
const std::array<Direction, CHOICES> RIGHT = {
Direction::TO_THE_LEFT,
Direction::TO_THE_RIGHT,
Direction::TO_THE_RIGHT,
Direction::TO_THE_RIGHT};
const Direction DIRECTION = destiny_ == Direction::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 ? Direction::TO_THE_LEFT : Direction::TO_THE_RIGHT;
// Establece la posición inicial
x_ = (direction_ == Direction::TO_THE_LEFT) ? param.game.game_area.rect.x + param.game.game_area.rect.w : param.game.game_area.rect.x - WIDTH;
// Crea una ruta de vuelo
setRandomFlyPath(direction_, 60);
shiftSprite();
}
}
// Establece un vuelo aleatorio
void Tabe::setRandomFlyPath(Direction direction, int length) {
direction_ = direction;
fly_distance_ = length;
waiting_counter_ = 5 + rand() % 15;
Audio::get()->playSound("tabe.wav");
constexpr float SPEED = 2.0F;
switch (direction) {
case Direction::TO_THE_LEFT: {
speed_ = -1.0F * SPEED;
accel_ = -1.0F * (1 + rand() % 10) / 30.0F;
sprite_->setFlip(SDL_FLIP_NONE);
break;
}
case Direction::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(State state) {
if (enabled_) {
state_ = state;
switch (state) {
case State::FLY:
sprite_->setCurrentAnimation("fly");
break;
case State::HIT:
sprite_->setCurrentAnimation("hit");
hit_counter_ = 5;
++number_of_hits_;
break;
default:
break;
}
}
}
// Actualiza el estado
void Tabe::updateState() {
if (state_ == State::HIT) {
--hit_counter_;
if (hit_counter_ == 0) {
setState(State::FLY);
}
}
}
// Intenta obtener el bonus
auto Tabe::tryToGetBonus() -> bool {
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();
}
// Detiene/activa el timer
void Tabe::pauseTimer(bool value) {
timer_.setPaused(value);
}