227 lines
5.4 KiB
C++
227 lines
5.4 KiB
C++
// IWYU pragma: no_include <bits/std_abs.h>
|
|
#include "tabe.h"
|
|
|
|
#include <SDL3/SDL.h> // Para SDL_FlipMode, SDL_GetTicks
|
|
#include <stdlib.h> // Para rand, abs
|
|
#include <algorithm> // Para max
|
|
#include <cmath> // Para abs
|
|
#include <string> // Para basic_string
|
|
|
|
#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_(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<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 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;
|
|
Audio::get()->playSound("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();
|
|
} |