Compare commits

...

16 Commits

Author SHA1 Message Date
66566913f6 delta-time: game.cpp (funciona pero va un poc massa ràpid) 2025-09-16 22:56:00 +02:00
3e6cc9dfab delta-time: explosions.cpp 2025-09-16 22:43:16 +02:00
a15e29344f delta-time: balloon.cpp
delta-time: balloon_manager.cpp
delta-time: credits.cpp
2025-09-16 22:38:48 +02:00
a96a17e11b delta-time: tabe.cpp 2025-09-16 20:29:35 +02:00
e0f6a424a9 delta-time: bullet.cpp 2025-09-16 20:26:22 +02:00
49e30f947a delta-time: title.cpp 2025-09-16 20:23:10 +02:00
470a07d28c delta-time: player.cpp 2025-09-16 19:21:44 +02:00
65716fce20 delta-time: tiled_bg.cpp 2025-09-16 17:35:03 +02:00
dfa66b0e95 delta-time: game_logo.cpp
delta-time: smart_sprite.cpp
2025-09-16 17:19:05 +02:00
3d9ffe356e Elimina .claude 2025-09-16 17:18:39 +02:00
19768cb72b delta-time: animated_sprite.cpp 2025-09-16 16:51:31 +02:00
26e0fd7247 delta-time: moving_sprite.cpp 2025-09-16 16:37:39 +02:00
e2fd470ad3 migració a delta time 2025-09-16 12:23:02 +02:00
a72ae0a5fc migració a delta time 2025-09-16 12:06:49 +02:00
7579594c22 migració a delta time 2025-09-16 10:48:22 +02:00
6c702e7e23 Logo: convertit per a usar delta time 2025-09-16 08:40:41 +02:00
46 changed files with 1663 additions and 332 deletions

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
.vscode
.claude
build/
data/config/config.txt
*.DS_Store

View File

@@ -43,6 +43,10 @@ auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffe
std::vector<std::string> buffer;
std::string line;
while (std::getline(input_stream, line)) {
// Eliminar caracteres de retorno de carro (\r) al final de la línea
if (!line.empty() && line.back() == '\r') {
line.pop_back();
}
if (!line.empty()) {
buffer.push_back(line);
}
@@ -82,7 +86,7 @@ auto AnimatedSprite::getAnimationIndex(const std::string& name) -> int {
return -1;
}
// Calcula el frame correspondiente a la animación
// Calcula el frame correspondiente a la animación (frame-based)
void AnimatedSprite::animate() {
if (animations_[current_animation_].speed == 0 || animations_[current_animation_].paused) {
return;
@@ -112,6 +116,39 @@ void AnimatedSprite::animate() {
}
}
// Calcula el frame correspondiente a la animación (time-based)
void AnimatedSprite::animate(float deltaTime) {
if (animations_[current_animation_].speed == 0 || animations_[current_animation_].paused) {
return;
}
// Convertir speed (frames) a tiempo: speed frames = speed * (1000ms/60fps) milisegundos
float frameTime = static_cast<float>(animations_[current_animation_].speed) * (1000.0f / 60.0f);
// Acumular tiempo transcurrido
animations_[current_animation_].time_accumulator += deltaTime;
// Verificar si es momento de cambiar frame
if (animations_[current_animation_].time_accumulator >= frameTime) {
animations_[current_animation_].time_accumulator -= frameTime;
animations_[current_animation_].current_frame++;
// Si alcanza el final de la animación
if (animations_[current_animation_].current_frame >= animations_[current_animation_].frames.size()) {
if (animations_[current_animation_].loop == -1) { // Si no hay loop, deja el último frame
animations_[current_animation_].current_frame = animations_[current_animation_].frames.size() - 1;
animations_[current_animation_].completed = true;
} else { // Si hay loop, vuelve al frame indicado
animations_[current_animation_].time_accumulator = 0.0f;
animations_[current_animation_].current_frame = animations_[current_animation_].loop;
}
}
// Actualizar el sprite clip
updateSpriteClip();
}
}
// Comprueba si ha terminado la animación
auto AnimatedSprite::animationIsCompleted() -> bool {
return animations_[current_animation_].completed;
@@ -126,10 +163,12 @@ void AnimatedSprite::setCurrentAnimation(const std::string& name, bool reset) {
if (reset) {
animations_[current_animation_].current_frame = 0;
animations_[current_animation_].counter = 0;
animations_[current_animation_].time_accumulator = 0.0f;
animations_[current_animation_].completed = false;
} else {
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_].time_accumulator = animations_[OLD_ANIMATION].time_accumulator;
animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed;
}
updateSpriteClip();
@@ -145,26 +184,35 @@ void AnimatedSprite::setCurrentAnimation(int index, bool reset) {
if (reset) {
animations_[current_animation_].current_frame = 0;
animations_[current_animation_].counter = 0;
animations_[current_animation_].time_accumulator = 0.0f;
animations_[current_animation_].completed = false;
} else {
animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size());
animations_[current_animation_].counter = animations_[OLD_ANIMATION].counter;
animations_[current_animation_].time_accumulator = animations_[OLD_ANIMATION].time_accumulator;
animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed;
}
updateSpriteClip();
}
}
// Actualiza las variables del objeto
// Actualiza las variables del objeto (frame-based)
void AnimatedSprite::update() {
animate();
MovingSprite::update();
}
// Actualiza las variables del objeto (time-based)
void AnimatedSprite::update(float deltaTime) {
animate(deltaTime);
MovingSprite::update(deltaTime);
}
// Reinicia la animación
void AnimatedSprite::resetAnimation() {
animations_[current_animation_].current_frame = 0;
animations_[current_animation_].counter = 0;
animations_[current_animation_].time_accumulator = 0.0f;
animations_[current_animation_].completed = false;
animations_[current_animation_].paused = false;
updateSpriteClip();

View File

@@ -21,11 +21,12 @@ struct Animation {
std::string name; // Nombre de la animación
std::vector<SDL_FRect> frames; // Frames que componen la animación
int speed{DEFAULT_SPEED}; // Velocidad de reproducción
int speed{DEFAULT_SPEED}; // Velocidad de reproducción (frame-based)
int loop{0}; // Frame de vuelta al terminar (-1 para no repetir)
bool completed{false}; // Indica si la animación ha finalizado
size_t current_frame{0}; // Frame actual en reproducción
int counter{0}; // Contador para la animación
int counter{0}; // Contador para la animación (frame-based)
float time_accumulator{0.0f}; // Acumulador de tiempo para animaciones time-based
bool paused{false}; // La animación no avanza
Animation() = default;
@@ -55,7 +56,8 @@ class AnimatedSprite : public MovingSprite {
~AnimatedSprite() override = default;
// --- Métodos principales ---
void update() override; // Actualiza la animación
void update() override; // Actualiza la animación (frame-based)
void update(float deltaTime); // Actualiza la animación (time-based)
// --- Control de animaciones ---
void setCurrentAnimation(const std::string& name = "default", bool reset = true); // Establece la animación por nombre
@@ -78,7 +80,8 @@ class AnimatedSprite : public MovingSprite {
int current_animation_ = 0; // Índice de la animación activa
// --- Métodos internos ---
void animate(); // Calcula el frame correspondiente a la animación
void animate(); // Calcula el frame correspondiente a la animación (frame-based)
void animate(float deltaTime); // Calcula el frame correspondiente a la animación (time-based)
void loadFromAnimationsFileBuffer(const AnimationsFileBuffer& source); // Carga la animación desde un vector de cadenas
void processConfigLine(const std::string& line, AnimationConfig& config); // Procesa una línea de configuración
void updateFrameCalculations(AnimationConfig& config); // Actualiza los cálculos basados en las dimensiones del frame

View File

@@ -126,7 +126,14 @@ void Background::initializeTextures() {
}
// Actualiza la lógica del objeto
// Actualiza la lógica del objeto (compatibilidad)
void Background::update() {
constexpr float FRAME_TIME_MS = 1000.0f / 60.0f; // 16.67ms por frame a 60 FPS
update(FRAME_TIME_MS);
}
// Actualiza la lógica del objeto
void Background::update(float delta_time) {
// Actualiza la progresión y calcula transiciones
if (!manual_mode_) {
updateProgression();

View File

@@ -31,7 +31,8 @@ class Background {
~Background(); // Destructor
// --- Métodos principales ---
void update(); // Actualiza la lógica del objeto
void update(); // Actualiza la lógica del objeto (compatibilidad)
void update(float delta_time); // Actualiza la lógica del objeto
void render(); // Dibuja el objeto
void reset(); // Reinicia la progresión

View File

@@ -135,7 +135,7 @@ void Balloon::render() {
}
}
// Actualiza la posición y estados del globo
// Actualiza la posición y estados del globo (frame-based)
void Balloon::move() {
if (isStopped()) {
return;
@@ -146,6 +146,17 @@ void Balloon::move() {
applyGravity();
}
// Actualiza la posición y estados del globo (time-based)
void Balloon::move(float deltaTime) {
if (isStopped()) {
return;
}
handleHorizontalMovement(deltaTime);
handleVerticalMovement(deltaTime);
applyGravity(deltaTime);
}
void Balloon::handleHorizontalMovement() {
x_ += vx_ * speed_;
@@ -158,6 +169,20 @@ void Balloon::handleHorizontalMovement() {
}
}
void Balloon::handleHorizontalMovement(float deltaTime) {
// Convertir deltaTime (milisegundos) a factor de frame (asumiendo 60fps)
float frameFactor = deltaTime / (1000.0f / 60.0f);
x_ += vx_ * speed_ * frameFactor;
const int CLIP = 2;
const float MIN_X = play_area_.x - CLIP;
const float MAX_X = play_area_.x + play_area_.w - w_ + CLIP;
if (isOutOfHorizontalBounds(MIN_X, MAX_X)) {
handleHorizontalBounce(MIN_X, MAX_X);
}
}
void Balloon::handleVerticalMovement() {
y_ += vy_ * speed_;
@@ -168,6 +193,18 @@ void Balloon::handleVerticalMovement() {
handleBottomCollision();
}
void Balloon::handleVerticalMovement(float deltaTime) {
// Convertir deltaTime (milisegundos) a factor de frame (asumiendo 60fps)
float frameFactor = deltaTime / (1000.0f / 60.0f);
y_ += vy_ * speed_ * frameFactor;
if (shouldCheckTopCollision()) {
handleTopCollision();
}
handleBottomCollision();
}
auto Balloon::isOutOfHorizontalBounds(float min_x, float max_x) const -> bool {
return x_ < min_x || x_ > max_x;
}
@@ -230,6 +267,18 @@ void Balloon::applyGravity() {
}
}
void Balloon::applyGravity(float deltaTime) {
// Convertir deltaTime (milisegundos) a factor de frame (asumiendo 60fps)
float frameFactor = deltaTime / (1000.0f / 60.0f);
travel_y_ += speed_ * frameFactor;
if (travel_y_ >= 1.0F) {
travel_y_ -= 1.0F;
vy_ += gravity_;
}
}
void Balloon::playBouncingSound() {
if (sound_.enabled && sound_.bouncing_enabled) {
Audio::get()->playSound(sound_.bouncing_file);
@@ -242,7 +291,7 @@ void Balloon::playPoppingSound() {
}
}
// Actualiza al globo a su posicion, animación y controla los contadores
// Actualiza al globo a su posicion, animación y controla los contadores (frame-based)
void Balloon::update() {
move();
updateState();
@@ -253,7 +302,20 @@ void Balloon::update() {
++counter_;
}
// Actualiza los estados del globo
// Actualiza al globo a su posicion, animación y controla los contadores (time-based)
void Balloon::update(float deltaTime) {
move(deltaTime);
updateState(deltaTime);
updateBounceEffect();
shiftSprite();
shiftColliders();
sprite_->update(deltaTime);
// Convertir deltaTime (milisegundos) a factor de frame (asumiendo 60fps)
float frameFactor = deltaTime / (1000.0f / 60.0f);
counter_ += frameFactor;
}
// Actualiza los estados del globo (frame-based)
void Balloon::updateState() {
// Si se está creando
if (isBeingCreated()) {
@@ -263,7 +325,7 @@ void Balloon::updateState() {
if (creation_counter_ > 0) {
// Desplaza lentamente el globo hacia abajo y hacia un lado
if (creation_counter_ % 10 == 0) {
if (static_cast<int>(creation_counter_) % 10 == 0) {
y_++;
x_ += vx_;
@@ -290,6 +352,51 @@ void Balloon::updateState() {
}
}
// Actualiza los estados del globo (time-based)
void Balloon::updateState(float deltaTime) {
// Si se está creando
if (isBeingCreated()) {
// Actualiza el valor de las variables
stop();
setInvulnerable(true);
if (creation_counter_ > 0) {
// Convertir deltaTime (milisegundos) a factor de frame (asumiendo 60fps)
float frameFactor = deltaTime / (1000.0f / 60.0f);
// Desplaza lentamente el globo hacia abajo y hacia un lado
// Cada 10 frames (aproximadamente cada 166ms a 60fps)
movement_accumulator_ += frameFactor;
if (movement_accumulator_ >= 10.0f) {
movement_accumulator_ -= 10.0f;
y_++;
x_ += vx_;
// Comprueba no se salga por los laterales
const int MIN_X = play_area_.x;
const int MAX_X = play_area_.w - w_;
if (x_ < MIN_X || x_ > MAX_X) {
// Corrige y cambia el sentido de la velocidad
x_ -= vx_;
vx_ = -vx_;
}
}
creation_counter_ -= frameFactor;
if (creation_counter_ < 0) creation_counter_ = 0;
}
else {
// El contador ha llegado a cero
being_created_ = false;
start();
setInvulnerable(false);
setAnimation();
}
}
}
// Establece la animación correspondiente al estado
void Balloon::setAnimation() {
std::string creating_animation;

View File

@@ -87,11 +87,13 @@ class Balloon {
~Balloon() = default;
// --- Métodos principales ---
void alignTo(int x); // Centra el globo en la posición X
void render(); // Pinta el globo en la pantalla
void move(); // Actualiza la posición y estados del globo
void update(); // Actualiza el globo (posición, animación, contadores)
void stop(); // Detiene el globo
void alignTo(int x); // Centra el globo en la posición X
void render(); // Pinta el globo en la pantalla
void move(); // Actualiza la posición y estados del globo (frame-based)
void move(float deltaTime); // Actualiza la posición y estados del globo (time-based)
void update(); // Actualiza el globo (posición, animación, contadores) (frame-based)
void update(float deltaTime); // Actualiza el globo (posición, animación, contadores) (time-based)
void stop(); // Detiene el globo
void start(); // Pone el globo en movimiento
void pop(bool should_sound = false); // Explota el globo
@@ -256,8 +258,8 @@ class Balloon {
bool stopped_; // Si el globo está parado
bool use_reversed_colors_ = false; // Si se usa el color alternativo
Circle collider_; // Círculo de colisión
Uint16 creation_counter_; // Temporizador de creación
Uint16 creation_counter_ini_; // Valor inicial del temporizador de creación
float creation_counter_; // Temporizador de creación
float creation_counter_ini_; // Valor inicial del temporizador de creación
Uint16 score_; // Puntos al destruir el globo
Type type_; // Tipo de globo
Size size_; // Tamaño de globo
@@ -265,6 +267,7 @@ class Balloon {
Uint32 counter_ = 0; // Contador interno
float travel_y_ = 1.0F; // Distancia a recorrer en Y antes de aplicar gravedad
float speed_; // Velocidad del globo
float movement_accumulator_ = 0.0f; // Acumulador para movimiento durante creación (deltaTime)
Uint8 power_; // Poder que alberga el globo
SDL_FRect play_area_; // Zona de movimiento del globo
Sound sound_; // Configuración de sonido del globo
@@ -280,9 +283,12 @@ class Balloon {
void playPoppingSound(); // Reproduce el sonido de reventar
// --- Movimiento y física ---
void handleHorizontalMovement(); // Maneja el movimiento horizontal
void handleVerticalMovement(); // Maneja el movimiento vertical
void applyGravity(); // Aplica la gravedad al objeto
void handleHorizontalMovement(); // Maneja el movimiento horizontal (frame-based)
void handleHorizontalMovement(float deltaTime); // Maneja el movimiento horizontal (time-based)
void handleVerticalMovement(); // Maneja el movimiento vertical (frame-based)
void handleVerticalMovement(float deltaTime); // Maneja el movimiento vertical (time-based)
void applyGravity(); // Aplica la gravedad al objeto (frame-based)
void applyGravity(float deltaTime); // Aplica la gravedad al objeto (time-based)
// --- Rebote ---
void enableBounceEffect(); // Activa el efecto de rebote
@@ -297,5 +303,6 @@ class Balloon {
void handleBottomCollision(); // Maneja la colisión inferior
// --- Lógica de estado ---
void updateState(); // Actualiza los estados del globo
void updateState(); // Actualiza los estados del globo (frame-based)
void updateState(float deltaTime); // Actualiza los estados del globo (time-based)
};

View File

@@ -62,7 +62,7 @@ void BalloonManager::init() {
explosions_->addTexture(3, explosions_textures_.at(3), explosions_animations_.at(3));
}
// Actualiza
// Actualiza (frame-based)
void BalloonManager::update() {
for (const auto &balloon : balloons_) {
balloon->update();
@@ -71,6 +71,15 @@ void BalloonManager::update() {
explosions_->update();
}
// Actualiza (time-based)
void BalloonManager::update(float deltaTime) {
for (const auto &balloon : balloons_) {
balloon->update(deltaTime);
}
updateBalloonDeployCounter(deltaTime);
explosions_->update(deltaTime);
}
// Renderiza los objetos
void BalloonManager::render() {
for (auto &balloon : balloons_) {
@@ -162,13 +171,23 @@ void BalloonManager::freeBalloons() {
balloons_.erase(result.begin(), balloons_.end());
}
// Actualiza la variable enemyDeployCounter
// Actualiza la variable enemyDeployCounter (frame-based)
void BalloonManager::updateBalloonDeployCounter() {
if (balloon_deploy_counter_ > 0) {
--balloon_deploy_counter_;
}
}
// Actualiza la variable enemyDeployCounter (time-based)
void BalloonManager::updateBalloonDeployCounter(float deltaTime) {
if (balloon_deploy_counter_ > 0) {
// Convertir deltaTime (milisegundos) a factor de frame (asumiendo 60fps)
float frameFactor = deltaTime / (1000.0f / 60.0f);
balloon_deploy_counter_ -= frameFactor;
if (balloon_deploy_counter_ < 0) balloon_deploy_counter_ = 0;
}
}
// Indica si se puede crear una powerball
auto BalloonManager::canPowerBallBeCreated() -> bool { return (!power_ball_enabled_) && (calculateScreenPower() > Balloon::POWERBALL_SCREENPOWER_MINIMUM) && (power_ball_counter_ == 0); }

View File

@@ -28,8 +28,9 @@ class BalloonManager {
~BalloonManager() = default;
// --- Métodos principales ---
void update(); // Actualiza el estado de los globos
void render(); // Renderiza los globos en pantalla
void update(); // Actualiza el estado de los globos (frame-based)
void update(float deltaTime); // Actualiza el estado de los globos (time-based)
void render(); // Renderiza los globos en pantalla
// --- Gestión de globos ---
void freeBalloons(); // Libera globos que ya no sirven
@@ -49,7 +50,8 @@ class BalloonManager {
void setBalloonSpeed(float speed); // Ajusta la velocidad de los globos
void setDefaultBalloonSpeed(float speed) { default_balloon_speed_ = speed; }; // Establece la velocidad base
void resetBalloonSpeed() { setBalloonSpeed(default_balloon_speed_); }; // Restablece la velocidad de los globos
void updateBalloonDeployCounter(); // Actualiza el contador de despliegue
void updateBalloonDeployCounter(); // Actualiza el contador de despliegue (frame-based)
void updateBalloonDeployCounter(float deltaTime); // Actualiza el contador de despliegue (time-based)
auto canPowerBallBeCreated() -> bool; // Indica si se puede crear una PowerBall
auto calculateScreenPower() -> int; // Calcula el poder de los globos en pantalla
@@ -98,7 +100,7 @@ class BalloonManager {
SDL_FRect play_area_ = param.game.play_area.rect;
float balloon_speed_ = Balloon::SPEED.at(0);
float default_balloon_speed_ = Balloon::SPEED.at(0);
int balloon_deploy_counter_ = 0;
float balloon_deploy_counter_ = 0;
int power_ball_counter_ = 0;
int last_balloon_deploy_ = 0;
bool power_ball_enabled_ = false;

View File

@@ -60,13 +60,19 @@ void Bullet::render() {
}
}
// Actualiza el estado del objeto
// Actualiza el estado del objeto (frame-based)
auto Bullet::update() -> BulletMoveStatus {
sprite_->update();
return move();
}
// Implementación del movimiento usando BulletMoveStatus
// Actualiza el estado del objeto (time-based)
auto Bullet::update(float deltaTime) -> BulletMoveStatus {
sprite_->update(deltaTime);
return move(deltaTime);
}
// Implementación del movimiento usando BulletMoveStatus (frame-based)
auto Bullet::move() -> BulletMoveStatus {
pos_x_ += vel_x_;
if (pos_x_ < param.game.play_area.rect.x - WIDTH || pos_x_ > param.game.play_area.rect.w) {
@@ -86,6 +92,29 @@ auto Bullet::move() -> BulletMoveStatus {
return BulletMoveStatus::OK;
}
// Implementación del movimiento usando BulletMoveStatus (time-based)
auto Bullet::move(float deltaTime) -> BulletMoveStatus {
// Convertir deltaTime (milisegundos) a factor de frame (asumiendo 60fps)
float frameFactor = deltaTime / (1000.0f / 60.0f);
pos_x_ += vel_x_ * frameFactor;
if (pos_x_ < param.game.play_area.rect.x - WIDTH || pos_x_ > param.game.play_area.rect.w) {
disable();
return BulletMoveStatus::OUT;
}
pos_y_ += VEL_Y * frameFactor;
if (pos_y_ < param.game.play_area.rect.y - HEIGHT) {
disable();
return BulletMoveStatus::OUT;
}
shiftSprite();
shiftColliders();
return BulletMoveStatus::OK;
}
auto Bullet::isEnabled() const -> bool {
return bullet_type_ != BulletType::NONE;
}

View File

@@ -34,9 +34,10 @@ class Bullet {
~Bullet() = default; // Destructor
// --- Métodos principales ---
void render(); // Dibuja la bala en pantalla
auto update() -> BulletMoveStatus; // Actualiza el estado del objeto
void disable(); // Desactiva la bala
void render(); // Dibuja la bala en pantalla
auto update() -> BulletMoveStatus; // Actualiza el estado del objeto (frame-based)
auto update(float deltaTime) -> BulletMoveStatus; // Actualiza el estado del objeto (time-based)
void disable(); // Desactiva la bala
// --- Getters ---
[[nodiscard]] auto isEnabled() const -> bool; // Comprueba si está activa
@@ -64,7 +65,8 @@ class Bullet {
// --- Métodos internos ---
void shiftColliders(); // Ajusta el círculo de colisión
void shiftSprite(); // Ajusta el sprite
auto move() -> BulletMoveStatus; // Mueve la bala y devuelve su estado
auto move() -> BulletMoveStatus; // Mueve la bala y devuelve su estado (frame-based)
auto move(float deltaTime) -> BulletMoveStatus; // Mueve la bala y devuelve su estado (time-based)
static auto calculateVelocity(BulletType bullet_type) -> float; // Calcula la velocidad horizontal de la bala
static auto buildAnimationString(BulletType bullet_type, bool powered) -> std::string; // Construye el string de animación
};

View File

@@ -42,7 +42,7 @@ Director::Director(int argc, std::span<char *> argv) {
Section::name = Section::Name::GAME;
Section::options = Section::Options::GAME_PLAY_1P;
#elif _DEBUG
Section::name = Section::Name::HI_SCORE_TABLE;
Section::name = Section::Name::GAME;
Section::options = Section::Options::GAME_PLAY_1P;
#else // NORMAL GAME
Section::name = Section::Name::LOGO;

View File

@@ -6,7 +6,7 @@
class Texture; // lines 4-4
// Actualiza la lógica de la clase
// Actualiza la lógica de la clase (frame-based)
void Explosions::update() {
for (auto &explosion : explosions_) {
explosion->update();
@@ -16,6 +16,16 @@ void Explosions::update() {
freeExplosions();
}
// Actualiza la lógica de la clase (time-based)
void Explosions::update(float deltaTime) {
for (auto &explosion : explosions_) {
explosion->update(deltaTime);
}
// Vacia el vector de elementos finalizados
freeExplosions();
}
// Dibuja el objeto en pantalla
void Explosions::render() {
for (auto &explosion : explosions_) {

View File

@@ -29,8 +29,9 @@ class Explosions {
~Explosions() = default; // Destructor por defecto
// --- Métodos principales ---
void update(); // Actualiza la lógica de la clase
void render(); // Dibuja el objeto en pantalla
void update(); // Actualiza la lógica de la clase (frame-based)
void update(float deltaTime); // Actualiza la lógica de la clase (time-based)
void render(); // Dibuja el objeto en pantalla
// --- Configuración ---
void addTexture(int size, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation); // Añade texturas al objeto

View File

@@ -82,6 +82,11 @@ void Fade::update() {
}
}
// Compatibilidad delta-time (ignora el parámetro ya que usa SDL_GetTicks)
void Fade::update(float delta_time) {
update(); // Llama al método original
}
void Fade::updatePreState() {
// Sistema basado en tiempo únicamente
Uint32 elapsed_time = SDL_GetTicks() - pre_start_time_;

View File

@@ -37,10 +37,11 @@ class Fade {
~Fade();
// --- Métodos principales ---
void reset(); // Resetea variables para reutilizar el fade
void render(); // Dibuja la transición en pantalla
void update(); // Actualiza el estado interno
void activate(); // Activa el fade
void reset(); // Resetea variables para reutilizar el fade
void render(); // Dibuja la transición en pantalla
void update(); // Actualiza el estado interno (ya usa tiempo real)
void update(float delta_time); // Compatibilidad delta-time (ignora el parámetro)
void activate(); // Activa el fade
// --- Configuración ---
void setColor(Uint8 r, Uint8 g, Uint8 b); // Establece el color RGB del fade

View File

@@ -45,6 +45,7 @@ void GameLogo::init() {
arcade_edition_status_ = Status::DISABLED;
shake_.init(1, 2, 8, XP);
zoom_ = 3.0F * ZOOM_FACTOR;
post_finished_time_accumulator_ = 0.0f;
// Inicializa el bitmap de 'Coffee'
coffee_sprite_->setPosX(XP);
@@ -112,13 +113,20 @@ void GameLogo::render() {
}
}
// Actualiza la lógica de la clase
// Actualiza la lógica de la clase (frame-based)
void GameLogo::update() {
updateCoffeeCrisis();
updateArcadeEdition();
updatePostFinishedCounter();
}
// Actualiza la lógica de la clase (time-based)
void GameLogo::update(float deltaTime) {
updateCoffeeCrisis(deltaTime);
updateArcadeEdition(deltaTime);
updatePostFinishedCounter(deltaTime);
}
void GameLogo::updateCoffeeCrisis() {
switch (coffee_crisis_status_) {
case Status::MOVING:
@@ -135,6 +143,22 @@ void GameLogo::updateCoffeeCrisis() {
}
}
void GameLogo::updateCoffeeCrisis(float deltaTime) {
switch (coffee_crisis_status_) {
case Status::MOVING:
handleCoffeeCrisisMoving(deltaTime);
break;
case Status::SHAKING:
handleCoffeeCrisisShaking(deltaTime);
break;
case Status::FINISHED:
handleCoffeeCrisisFinished(deltaTime);
break;
default:
break;
}
}
void GameLogo::updateArcadeEdition() {
switch (arcade_edition_status_) {
case Status::MOVING:
@@ -148,6 +172,19 @@ void GameLogo::updateArcadeEdition() {
}
}
void GameLogo::updateArcadeEdition(float deltaTime) {
switch (arcade_edition_status_) {
case Status::MOVING:
handleArcadeEditionMoving(deltaTime);
break;
case Status::SHAKING:
handleArcadeEditionShaking(deltaTime);
break;
default:
break;
}
}
void GameLogo::handleCoffeeCrisisMoving() {
coffee_sprite_->update();
crisis_sprite_->update();
@@ -158,6 +195,16 @@ void GameLogo::handleCoffeeCrisisMoving() {
}
}
void GameLogo::handleCoffeeCrisisMoving(float deltaTime) {
coffee_sprite_->update(deltaTime);
crisis_sprite_->update(deltaTime);
if (coffee_sprite_->hasFinished() && crisis_sprite_->hasFinished()) {
coffee_crisis_status_ = Status::SHAKING;
playTitleEffects();
}
}
void GameLogo::handleCoffeeCrisisShaking() {
if (shake_.remaining > 0) {
processShakeEffect(coffee_sprite_.get(), crisis_sprite_.get());
@@ -168,10 +215,24 @@ void GameLogo::handleCoffeeCrisisShaking() {
updateDustSprites();
}
void GameLogo::handleCoffeeCrisisShaking(float deltaTime) {
if (shake_.remaining > 0) {
processShakeEffect(coffee_sprite_.get(), crisis_sprite_.get(), deltaTime);
} else {
finishCoffeeCrisisShaking();
}
updateDustSprites(deltaTime);
}
void GameLogo::handleCoffeeCrisisFinished() {
updateDustSprites();
}
void GameLogo::handleCoffeeCrisisFinished(float deltaTime) {
updateDustSprites(deltaTime);
}
void GameLogo::handleArcadeEditionMoving() {
zoom_ -= 0.1F * ZOOM_FACTOR;
arcade_edition_sprite_->setZoom(zoom_);
@@ -181,6 +242,16 @@ void GameLogo::handleArcadeEditionMoving() {
}
}
void GameLogo::handleArcadeEditionMoving(float deltaTime) {
// Convertir 0.1F * ZOOM_FACTOR por frame a por milisegundo (asumiendo 60fps)
zoom_ -= (0.1F * ZOOM_FACTOR) * deltaTime / (1000.0F / 60.0F);
arcade_edition_sprite_->setZoom(zoom_);
if (zoom_ <= 1.0F) {
finishArcadeEditionMoving();
}
}
void GameLogo::handleArcadeEditionShaking() {
if (shake_.remaining > 0) {
processArcadeEditionShake();
@@ -190,6 +261,15 @@ void GameLogo::handleArcadeEditionShaking() {
}
}
void GameLogo::handleArcadeEditionShaking(float deltaTime) {
if (shake_.remaining > 0) {
processArcadeEditionShake(deltaTime);
} else {
arcade_edition_sprite_->setX(shake_.origin);
arcade_edition_status_ = Status::FINISHED;
}
}
void GameLogo::processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite) {
if (shake_.counter > 0) {
shake_.counter--;
@@ -204,6 +284,23 @@ void GameLogo::processShakeEffect(SmartSprite* primary_sprite, SmartSprite* seco
}
}
void GameLogo::processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite, float deltaTime) {
// Convertir delay (frames) a tiempo: delay frames = delay * (1000ms/60fps)
float delayTime = static_cast<float>(shake_.delay) * (1000.0f / 60.0f);
shake_.time_accumulator += deltaTime;
if (shake_.time_accumulator >= delayTime) {
shake_.time_accumulator -= delayTime;
const auto DISPLACEMENT = calculateShakeDisplacement();
primary_sprite->setPosX(shake_.origin + DISPLACEMENT);
if (secondary_sprite != nullptr) {
secondary_sprite->setPosX(shake_.origin + DISPLACEMENT + 15);
}
shake_.remaining--;
}
}
void GameLogo::processArcadeEditionShake() {
if (shake_.counter > 0) {
shake_.counter--;
@@ -215,6 +312,20 @@ void GameLogo::processArcadeEditionShake() {
}
}
void GameLogo::processArcadeEditionShake(float deltaTime) {
// Convertir delay (frames) a tiempo: delay frames = delay * (1000ms/60fps)
float delayTime = static_cast<float>(shake_.delay) * (1000.0f / 60.0f);
shake_.time_accumulator += deltaTime;
if (shake_.time_accumulator >= delayTime) {
shake_.time_accumulator -= delayTime;
const auto DISPLACEMENT = calculateShakeDisplacement();
arcade_edition_sprite_->setX(shake_.origin + DISPLACEMENT);
shake_.remaining--;
}
}
auto GameLogo::calculateShakeDisplacement() const -> int {
return shake_.remaining % 2 == 0 ? shake_.desp * (-1) : shake_.desp;
}
@@ -245,6 +356,11 @@ void GameLogo::updateDustSprites() {
dust_left_sprite_->update();
}
void GameLogo::updateDustSprites(float deltaTime) {
dust_right_sprite_->update(deltaTime);
dust_left_sprite_->update(deltaTime);
}
void GameLogo::updatePostFinishedCounter() {
if (coffee_crisis_status_ == Status::FINISHED &&
arcade_edition_status_ == Status::FINISHED &&
@@ -253,6 +369,23 @@ void GameLogo::updatePostFinishedCounter() {
}
}
void GameLogo::updatePostFinishedCounter(float deltaTime) {
if (coffee_crisis_status_ == Status::FINISHED &&
arcade_edition_status_ == Status::FINISHED &&
post_finished_counter_ > 0) {
// Convertir 1 frame a tiempo: 1 frame = 1000ms/60fps = 16.67ms
float frameTime = 1000.0f / 60.0f;
post_finished_time_accumulator_ += deltaTime;
if (post_finished_time_accumulator_ >= frameTime) {
post_finished_time_accumulator_ -= frameTime;
--post_finished_counter_;
}
}
}
// Activa la clase
void GameLogo::enable() {
init();

View File

@@ -16,9 +16,10 @@ class GameLogo {
~GameLogo() = default;
// --- Métodos principales ---
void render(); // Pinta la clase en pantalla
void update(); // Actualiza la lógica de la clase
void enable(); // Activa la clase
void render(); // Pinta la clase en pantalla
void update(); // Actualiza la lógica de la clase (frame-based)
void update(float deltaTime); // Actualiza la lógica de la clase (time-based)
void enable(); // Activa la clase
// --- Getters ---
[[nodiscard]] auto hasFinished() const -> bool; // Indica si ha terminado la animación
@@ -34,12 +35,13 @@ class GameLogo {
// --- Estructuras privadas ---
struct Shake {
int desp = 1; // Pixels de desplazamiento para agitar la pantalla en el eje x
int delay = 2; // Retraso entre cada desplazamiento de la pantalla al agitarse
int length = 8; // Cantidad de desplazamientos a realizar
int remaining = length; // Cantidad de desplazamientos pendientes a realizar
int counter = delay; // Contador para el retraso
int origin = 0; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
int desp = 1; // Pixels de desplazamiento para agitar la pantalla en el eje x
int delay = 2; // Retraso entre cada desplazamiento de la pantalla al agitarse (frame-based)
int length = 8; // Cantidad de desplazamientos a realizar
int remaining = length; // Cantidad de desplazamientos pendientes a realizar
int counter = delay; // Contador para el retraso (frame-based)
float time_accumulator = 0.0f; // Acumulador de tiempo para deltaTime
int origin = 0; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
Shake() = default;
Shake(int d, int de, int l, int o)
@@ -56,6 +58,7 @@ class GameLogo {
length = l;
remaining = l;
counter = de;
time_accumulator = 0.0f;
origin = o;
}
};
@@ -79,32 +82,44 @@ class GameLogo {
float x_; // Posición X del logo
float y_; // Posición Y del logo
float zoom_ = 1.0F; // Zoom aplicado al texto "ARCADE EDITION"
int post_finished_counter_ = 1; // Contador final tras animaciones
int post_finished_counter_ = 1; // Contador final tras animaciones (frame-based)
float post_finished_time_accumulator_ = 0.0f; // Acumulador de tiempo para post_finished_counter
// --- Inicialización ---
void init(); // Inicializa las variables
[[nodiscard]] auto getInitialVerticalDesp() const -> int; // Calcula el desplazamiento vertical inicial
// --- Actualización de estados específicos ---
void updateCoffeeCrisis(); // Actualiza el estado de "Coffee Crisis"
void updateArcadeEdition(); // Actualiza el estado de "Arcade Edition"
void updatePostFinishedCounter(); // Actualiza el contador tras finalizar una animación
void updateCoffeeCrisis(); // Actualiza el estado de "Coffee Crisis" (frame-based)
void updateCoffeeCrisis(float deltaTime); // Actualiza el estado de "Coffee Crisis" (time-based)
void updateArcadeEdition(); // Actualiza el estado de "Arcade Edition" (frame-based)
void updateArcadeEdition(float deltaTime); // Actualiza el estado de "Arcade Edition" (time-based)
void updatePostFinishedCounter(); // Actualiza el contador tras finalizar una animación (frame-based)
void updatePostFinishedCounter(float deltaTime); // Actualiza el contador tras finalizar una animación (time-based)
// --- Efectos visuales: movimiento y sacudidas ---
void handleCoffeeCrisisMoving(); // Maneja el movimiento de "Coffee Crisis"
void handleCoffeeCrisisShaking(); // Maneja la sacudida de "Coffee Crisis"
void handleArcadeEditionMoving(); // Maneja el movimiento de "Arcade Edition"
void handleArcadeEditionShaking(); // Maneja la sacudida de "Arcade Edition"
void processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite = nullptr); // Procesa el efecto de sacudida en sprites
void processArcadeEditionShake(); // Procesa la sacudida específica de "Arcade Edition"
[[nodiscard]] auto calculateShakeDisplacement() const -> int; // Calcula el desplazamiento de la sacudida
void handleCoffeeCrisisMoving(); // Maneja el movimiento de "Coffee Crisis" (frame-based)
void handleCoffeeCrisisMoving(float deltaTime); // Maneja el movimiento de "Coffee Crisis" (time-based)
void handleCoffeeCrisisShaking(); // Maneja la sacudida de "Coffee Crisis" (frame-based)
void handleCoffeeCrisisShaking(float deltaTime); // Maneja la sacudida de "Coffee Crisis" (time-based)
void handleArcadeEditionMoving(); // Maneja el movimiento de "Arcade Edition" (frame-based)
void handleArcadeEditionMoving(float deltaTime); // Maneja el movimiento de "Arcade Edition" (time-based)
void handleArcadeEditionShaking(); // Maneja la sacudida de "Arcade Edition" (frame-based)
void handleArcadeEditionShaking(float deltaTime); // Maneja la sacudida de "Arcade Edition" (time-based)
void processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite = nullptr); // Procesa el efecto de sacudida en sprites (frame-based)
void processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite, float deltaTime); // Procesa el efecto de sacudida en sprites (time-based)
void processArcadeEditionShake(); // Procesa la sacudida específica de "Arcade Edition" (frame-based)
void processArcadeEditionShake(float deltaTime); // Procesa la sacudida específica de "Arcade Edition" (time-based)
[[nodiscard]] auto calculateShakeDisplacement() const -> int; // Calcula el desplazamiento de la sacudida
// --- Gestión de finalización de efectos ---
void handleCoffeeCrisisFinished(); // Maneja el final de la animación "Coffee Crisis"
void finishCoffeeCrisisShaking(); // Finaliza la sacudida de "Coffee Crisis"
void finishArcadeEditionMoving(); // Finaliza el movimiento de "Arcade Edition"
void handleCoffeeCrisisFinished(); // Maneja el final de la animación "Coffee Crisis" (frame-based)
void handleCoffeeCrisisFinished(float deltaTime); // Maneja el final de la animación "Coffee Crisis" (time-based)
void finishCoffeeCrisisShaking(); // Finaliza la sacudida de "Coffee Crisis"
void finishArcadeEditionMoving(); // Finaliza el movimiento de "Arcade Edition"
// --- Utilidades ---
static void playTitleEffects(); // Reproduce efectos visuales/sonoros del título
void updateDustSprites(); // Actualiza los sprites de polvo
static void playTitleEffects(); // Reproduce efectos visuales/sonoros del título
void updateDustSprites(); // Actualiza los sprites de polvo (frame-based)
void updateDustSprites(float deltaTime); // Actualiza los sprites de polvo (time-based)
};

View File

@@ -53,7 +53,7 @@ void MovingSprite::stop() {
flip_ = SDL_FLIP_NONE; // Establece como se ha de voltear el sprite
}
// Mueve el sprite
// Mueve el sprite (frame-based)
void MovingSprite::move() {
x_ += vx_;
y_ += vy_;
@@ -65,16 +65,37 @@ void MovingSprite::move() {
pos_.y = static_cast<int>(y_);
}
// Actualiza las variables internas del objeto
// Mueve el sprite (time-based)
void MovingSprite::move(float deltaTime) {
// Convertir deltaTime (milisegundos) a factor de frame (asumiendo 60fps)
float frameFactor = deltaTime / (1000.0f / 60.0f);
x_ += vx_ * frameFactor;
y_ += vy_ * frameFactor;
vx_ += ax_ * frameFactor;
vy_ += ay_ * frameFactor;
pos_.x = static_cast<int>(x_);
pos_.y = static_cast<int>(y_);
}
// Actualiza las variables internas del objeto (frame-based)
void MovingSprite::update() {
move();
rotate();
}
// Actualiza las variables internas del objeto (time-based)
void MovingSprite::update(float deltaTime) {
move(deltaTime);
rotate(deltaTime);
}
// Muestra el sprite por pantalla
void MovingSprite::render() { getTexture()->render(pos_.x, pos_.y, &sprite_clip_, horizontal_zoom_, vertical_zoom_, rotate_.angle, &rotate_.center, flip_); }
// Establece la rotacion
// Establece la rotacion (frame-based)
void MovingSprite::rotate() {
if (rotate_.enabled) {
++rotate_.counter;
@@ -85,6 +106,15 @@ void MovingSprite::rotate() {
}
}
// Establece la rotacion (time-based)
void MovingSprite::rotate(float deltaTime) {
if (rotate_.enabled) {
// Convertir speed (frames) a tiempo: speed frames = speed * (1000ms/60fps) milisegundos
float rotationFrameTime = static_cast<float>(rotate_.speed) * (1000.0f / 60.0f);
rotate_.angle += rotate_.amount * (deltaTime / rotationFrameTime);
}
}
// Activa o desactiva el efecto de rotación
void MovingSprite::setRotate(bool enable) {
rotate_.enabled = enable;

View File

@@ -29,10 +29,11 @@ class MovingSprite : public Sprite {
~MovingSprite() override = default;
// --- Métodos principales ---
virtual void update(); // Actualiza las variables internas del objeto
void clear() override; // Reinicia todas las variables a cero
void stop(); // Elimina el movimiento del sprite
void render() override; // Muestra el sprite por pantalla
virtual void update(); // Actualiza las variables internas del objeto (frame-based)
virtual void update(float deltaTime); // Actualiza las variables internas del objeto (time-based)
void clear() override; // Reinicia todas las variables a cero
void stop(); // Elimina el movimiento del sprite
void render() override; // Muestra el sprite por pantalla
// --- Configuración ---
void setPos(SDL_FRect rect); // Establece la posición y el tamaño del objeto
@@ -79,6 +80,8 @@ class MovingSprite : public Sprite {
// --- Métodos internos ---
void updateAngle() { rotate_.angle += rotate_.amount; } // Incrementa el valor del ángulo
void move(); // Mueve el sprite según velocidad y aceleración
void rotate(); // Rota el sprite según los parámetros de rotación
void move(); // Mueve el sprite según velocidad y aceleración (frame-based)
void move(float deltaTime); // Mueve el sprite según velocidad y aceleración (time-based)
void rotate(); // Rota el sprite según los parámetros de rotación (frame-based)
void rotate(float deltaTime); // Rota el sprite según los parámetros de rotación (time-based)
};

View File

@@ -4,6 +4,13 @@
#include <functional> // Para function
#include <utility> // Para move
// Constructor para paths por puntos (compatibilidad)
Path::Path(const std::vector<SDL_FPoint> &spots_init, int waiting_counter_init)
: spots(spots_init), is_point_path(true) {
constexpr float FRAME_TIME_MS = 1000.0f / 60.0f;
waiting_time_ms = static_cast<float>(waiting_counter_init) * FRAME_TIME_MS;
}
// Devuelve un vector con los puntos que conforman la ruta
auto createPath(float start, float end, PathType type, float fixed_pos, int steps, const std::function<double(double)> &easing_function) -> std::vector<SDL_FPoint> {
std::vector<SDL_FPoint> v;
@@ -32,10 +39,16 @@ auto createPath(float start, float end, PathType type, float fixed_pos, int step
return v;
}
// Actualiza la posición y comprueba si ha llegado a su destino
// Actualiza la posición y comprueba si ha llegado a su destino (compatibilidad)
void PathSprite::update() {
constexpr float FRAME_TIME_MS = 1000.0f / 60.0f; // 16.67ms por frame a 60 FPS
update(FRAME_TIME_MS);
}
// Actualiza la posición y comprueba si ha llegado a su destino
void PathSprite::update(float delta_time) {
if (enabled_ && !has_finished_) {
moveThroughCurrentPath();
moveThroughCurrentPath(delta_time);
goToNextPathOrDie();
}
}
@@ -79,7 +92,13 @@ void PathSprite::addPath(Path path, bool centered) {
// Añade un recorrido
void PathSprite::addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easing_function, int waiting_counter) {
paths_.emplace_back(createPath(start, end, type, fixed_pos, steps, easing_function), waiting_counter);
// Convertir frames a milisegundos
constexpr float FRAME_TIME_MS = 1000.0f / 60.0f;
float duration_ms = static_cast<float>(steps) * FRAME_TIME_MS;
float waiting_ms = static_cast<float>(waiting_counter) * FRAME_TIME_MS;
paths_.emplace_back(static_cast<float>(start), static_cast<float>(end), type, static_cast<float>(fixed_pos),
duration_ms, waiting_ms, easing_function);
}
// Añade un recorrido
@@ -95,35 +114,78 @@ void PathSprite::enable() {
enabled_ = true;
// Establece la posición
// Establece la posición inicial
auto &path = paths_.at(current_path_);
const auto &p = path.spots.at(path.counter);
setPosition(p);
if (path.is_point_path) {
const auto &p = path.spots.at(path.counter);
setPosition(p);
} else {
// Para paths generados, establecer posición inicial
SDL_FPoint initial_pos;
if (path.type == PathType::HORIZONTAL) {
initial_pos = {path.start_pos, path.fixed_pos};
} else {
initial_pos = {path.fixed_pos, path.start_pos};
}
setPosition(initial_pos);
}
}
// Coloca el sprite en los diferentes puntos del recorrido
void PathSprite::moveThroughCurrentPath() {
void PathSprite::moveThroughCurrentPath(float delta_time) {
auto &path = paths_.at(current_path_);
// Establece la posición
const auto &p = path.spots.at(path.counter);
setPosition(p);
if (path.is_point_path) {
// Lógica para paths por puntos (compatibilidad)
const auto &p = path.spots.at(path.counter);
setPosition(p);
// Comprobar si ha terminado el recorrido
if (!path.on_destination) {
++path.counter;
if (path.counter >= static_cast<int>(path.spots.size())) {
path.on_destination = true;
path.counter = static_cast<int>(path.spots.size()) - 1;
if (!path.on_destination) {
++path.counter;
if (path.counter >= static_cast<int>(path.spots.size())) {
path.on_destination = true;
path.counter = static_cast<int>(path.spots.size()) - 1;
}
}
}
// Comprobar si ha terminado la espera
if (path.on_destination) {
if (path.waiting_counter == 0) {
path.finished = true;
if (path.on_destination) {
path.waiting_elapsed += delta_time;
if (path.waiting_elapsed >= path.waiting_time_ms) {
path.finished = true;
}
}
} else {
// Lógica para paths generados en tiempo real
if (!path.on_destination) {
path.elapsed_time += delta_time;
// Calcular progreso (0.0 a 1.0)
float progress = path.elapsed_time / path.duration_ms;
if (progress >= 1.0f) {
progress = 1.0f;
path.on_destination = true;
}
// Aplicar función de easing
double eased_progress = path.easing_function(progress);
// Calcular posición actual
float current_pos = path.start_pos + (path.end_pos - path.start_pos) * static_cast<float>(eased_progress);
// Establecer posición según el tipo
SDL_FPoint position;
if (path.type == PathType::HORIZONTAL) {
position = {current_pos, path.fixed_pos};
} else {
position = {path.fixed_pos, current_pos};
}
setPosition(position);
} else {
--path.waiting_counter;
// Esperar en destino
path.waiting_elapsed += delta_time;
if (path.waiting_elapsed >= path.waiting_time_ms) {
path.finished = true;
}
}
}
}

View File

@@ -24,17 +24,31 @@ enum class PathCentered { // Centrado del recorrido
};
// --- Estructuras ---
struct Path { // Define un recorrido para el sprite
std::vector<SDL_FPoint> spots; // Puntos por los que se desplazará el sprite
int waiting_counter; // Tiempo de espera una vez en el destino
bool on_destination = false; // Indica si ha llegado al destino
bool finished = false; // Indica si ha terminado de esperarse
int counter = 0; // Contador interno
struct Path { // Define un recorrido para el sprite
float start_pos; // Posición inicial
float end_pos; // Posición final
PathType type; // Tipo de movimiento (horizontal/vertical)
float fixed_pos; // Posición fija en el eje contrario
float duration_ms; // Duración de la animación en milisegundos
float waiting_time_ms; // Tiempo de espera una vez en el destino
std::function<double(double)> easing_function; // Función de easing
float elapsed_time = 0.0f; // Tiempo transcurrido
float waiting_elapsed = 0.0f; // Tiempo de espera transcurrido
bool on_destination = false; // Indica si ha llegado al destino
bool finished = false; // Indica si ha terminado de esperarse
// Constructor
Path(const std::vector<SDL_FPoint> &spots_init, int waiting_counter_init)
: spots(spots_init),
waiting_counter(waiting_counter_init) {}
// Constructor para paths generados
Path(float start, float end, PathType path_type, float fixed, float duration, float waiting, std::function<double(double)> easing)
: start_pos(start), end_pos(end), type(path_type), fixed_pos(fixed),
duration_ms(duration), waiting_time_ms(waiting), easing_function(std::move(easing)) {}
// Constructor para paths por puntos (mantenemos compatibilidad)
Path(const std::vector<SDL_FPoint> &spots_init, int waiting_counter_init);
// Variables para paths por puntos
std::vector<SDL_FPoint> spots; // Solo para paths por puntos
int counter = 0; // Solo para paths por puntos
bool is_point_path = false; // Indica si es un path por puntos
};
// --- Funciones ---
@@ -49,7 +63,8 @@ class PathSprite : public Sprite {
~PathSprite() override = default;
// --- Métodos principales ---
void update(); // Actualiza la posición del sprite según el recorrido
void update(); // Actualiza la posición del sprite según el recorrido (compatibilidad)
void update(float delta_time); // Actualiza la posición del sprite según el recorrido
void render() override; // Muestra el sprite por pantalla
// --- Gestión de recorridos ---
@@ -72,6 +87,6 @@ class PathSprite : public Sprite {
std::vector<Path> paths_; // Caminos a recorrer por el sprite
// --- Métodos internos ---
void moveThroughCurrentPath(); // Coloca el sprite en los diferentes puntos del recorrido
void moveThroughCurrentPath(float delta_time); // Coloca el sprite en los diferentes puntos del recorrido
void goToNextPathOrDie(); // Cambia de recorrido o finaliza
};

View File

@@ -3,6 +3,7 @@
#include <SDL3/SDL.h> // Para SDL_GetTicks, SDL_FlipMode
#include <algorithm> // Para clamp, max, min
#include <cmath> // Para fmod
#include <cstdlib> // Para rand
#include "animated_sprite.h" // Para AnimatedSprite
@@ -186,6 +187,41 @@ void Player::move() {
}
}
// Fase 1: Sistema de movimiento time-based
void Player::move(float deltaTime) {
switch (playing_state_) {
case State::PLAYING:
handlePlayingMovement(deltaTime);
break;
case State::ROLLING:
handleRollingMovement(); // Usa MovingSprite que ya soporta deltaTime
break;
case State::TITLE_ANIMATION:
handleTitleAnimation(); // Sin cambios - usa solo animaciones
break;
case State::CONTINUE_TIME_OUT:
handleContinueTimeOut(); // Sin cambios - usa MovingSprite que ya soporta deltaTime
break;
case State::LEAVING_SCREEN:
handleLeavingScreen(); // Sin cambios - usa MovingSprite que ya soporta deltaTime
break;
case State::ENTERING_SCREEN:
handleEnteringScreen(); // Sin cambios - usa MovingSprite que ya soporta deltaTime
break;
case State::CREDITS:
handleCreditsMovement(deltaTime); // Fase 4: Sistema de créditos time-based
break;
case State::WAITING:
handleWaitingMovement(deltaTime); // Fase 4: Sistema de waiting time-based
break;
case State::RECOVER:
handleRecoverMovement(); // Sin cambios - usa AnimatedSprite que ya soporta deltaTime
break;
default:
break;
}
}
void Player::handlePlayingMovement() {
// Mueve el jugador a derecha o izquierda
pos_x_ += vel_x_;
@@ -198,6 +234,19 @@ void Player::handlePlayingMovement() {
shiftSprite();
}
// Fase 1: Movimiento time-based durante el juego
void Player::handlePlayingMovement(float deltaTime) {
// Mueve el jugador a derecha o izquierda (time-based)
pos_x_ += vel_x_ * deltaTime / (1000.0f / 60.0f);
// Si el jugador abandona el area de juego por los laterales, restaura su posición
const float MIN_X = play_area_.x - 5;
const float MAX_X = play_area_.w + 5 - WIDTH;
pos_x_ = std::clamp(pos_x_, MIN_X, MAX_X);
shiftSprite();
}
void Player::handleRecoverMovement() {
if (player_sprite_->getCurrentAnimationFrame() == 10) { playSound("voice_recover.wav"); }
if (player_sprite_->animationIsCompleted()) { setPlayingState(State::RESPAWNING); }
@@ -337,6 +386,20 @@ void Player::handleCreditsMovement() {
shiftSprite();
}
// Fase 4: Movimiento general en la pantalla de créditos (time-based)
void Player::handleCreditsMovement(float deltaTime) {
pos_x_ += (vel_x_ / 2.0F) * deltaTime / (1000.0f / 60.0f); // Convert frame-based movement to time-based
if (vel_x_ > 0) {
handleCreditsRightMovement();
} else {
handleCreditsLeftMovement();
}
updateWalkingStateForCredits();
shiftSprite();
}
void Player::handleCreditsRightMovement() {
if (pos_x_ > param.game.game_area.rect.w - WIDTH) {
pos_x_ = param.game.game_area.rect.w - WIDTH;
@@ -359,6 +422,16 @@ void Player::handleWaitingMovement() {
}
}
// Fase 4: Controla la animación del jugador saludando (time-based)
void Player::handleWaitingMovement(float deltaTime) {
waiting_time_accumulator_ += deltaTime;
float waiting_duration = static_cast<float>(WAITING_COUNTER) * (1000.0f / 60.0f); // Convert frames to milliseconds
if (waiting_time_accumulator_ >= waiting_duration) {
waiting_time_accumulator_ = 0.0f;
player_sprite_->resetAnimation();
}
}
void Player::updateWalkingStateForCredits() {
if (pos_x_ > param.game.game_area.center_x - WIDTH / 2) {
setWalkingState(State::WALKING_LEFT);
@@ -387,6 +460,16 @@ void Player::updateStepCounter() {
}
}
// Fase 4: Incrementa o ajusta el contador de pasos (time-based)
void Player::updateStepCounter(float deltaTime) {
step_time_accumulator_ += deltaTime;
float step_interval = 10.0f / 60.0f; // 10 frames converted to seconds
if (step_time_accumulator_ >= step_interval) {
step_time_accumulator_ = 0.0f;
playSound("walk.wav");
}
}
// Pinta el jugador en pantalla
void Player::render() {
if (power_up_ && isPlaying()) {
@@ -454,7 +537,7 @@ auto Player::computeAnimation() const -> std::pair<std::string, SDL_FlipMode> {
return {anim_name, flip_mode};
}
// Establece la animación correspondiente al estado
// Establece la animación correspondiente al estado (frame-based)
void Player::setAnimation() {
switch (playing_state_) {
case State::PLAYING:
@@ -495,7 +578,49 @@ void Player::setAnimation() {
power_sprite_->update();
}
// Actualiza el valor de la variable
// Fase 1: Establece la animación correspondiente al estado (time-based)
void Player::setAnimation(float deltaTime) {
switch (playing_state_) {
case State::PLAYING:
case State::ENTERING_NAME_GAME_COMPLETED:
case State::ENTERING_SCREEN:
case State::LEAVING_SCREEN:
case State::TITLE_ANIMATION:
case State::CREDITS: {
auto [animName, flipMode] = computeAnimation();
player_sprite_->setCurrentAnimation(animName, false);
player_sprite_->setFlip(flipMode);
break;
}
case State::RECOVER:
player_sprite_->setCurrentAnimation("recover");
break;
case State::WAITING:
case State::GAME_OVER:
player_sprite_->setCurrentAnimation("hello");
break;
case State::ROLLING:
case State::CONTINUE_TIME_OUT:
player_sprite_->setCurrentAnimation("rolling");
break;
case State::LYING_ON_THE_FLOOR_FOREVER:
case State::ENTERING_NAME:
case State::CONTINUE:
player_sprite_->setCurrentAnimation("dizzy");
break;
case State::CELEBRATING:
player_sprite_->setCurrentAnimation("celebration");
break;
default:
break;
}
// La diferencia clave: usa deltaTime para las animaciones
player_sprite_->update(deltaTime);
power_sprite_->update(deltaTime);
}
// Actualiza el valor de la variable (frame-based)
void Player::updateCooldown() {
if (playing_state_ != State::PLAYING) {
return;
@@ -508,6 +633,19 @@ void Player::updateCooldown() {
}
}
// Fase 2: Actualiza el cooldown de disparo (time-based)
void Player::updateCooldown(float deltaTime) {
if (playing_state_ != State::PLAYING) {
return;
}
if (cant_fire_time_accumulator_ > 0) {
handleFiringCooldown(deltaTime);
} else {
handleRecoilAndCooling(deltaTime);
}
}
void Player::handleFiringCooldown() {
cooling_state_counter_ = COOLING_DURATION;
@@ -522,6 +660,28 @@ void Player::handleFiringCooldown() {
}
}
// Fase 2: Manejo de cooldown de disparo (time-based)
void Player::handleFiringCooldown(float deltaTime) {
cooling_time_accumulator_ = static_cast<float>(COOLING_DURATION) / 60.0f;
// Convertir frames a tiempo: 1 frame = 1/60 segundos
float frameTime = 1.0f / 60.0f;
float halfwayTime = static_cast<float>(recoiling_state_duration_) / 2.0f / 60.0f;
// Reducir tiempo acumulado
cant_fire_time_accumulator_ -= deltaTime;
// Transition to recoiling state at halfway point
if (cant_fire_time_accumulator_ <= halfwayTime && cant_fire_time_accumulator_ > halfwayTime - frameTime) {
transitionToRecoiling();
}
if (cant_fire_time_accumulator_ <= 0) {
cant_fire_time_accumulator_ = 0;
recoiling_time_accumulator_ = static_cast<float>(recoiling_state_duration_) / 60.0f;
}
}
void Player::handleRecoilAndCooling() {
if (recoiling_state_counter_ > 0) {
--recoiling_state_counter_;
@@ -531,6 +691,16 @@ void Player::handleRecoilAndCooling() {
handleCoolingState();
}
// Fase 2: Manejo de retroceso y enfriamiento (time-based)
void Player::handleRecoilAndCooling(float deltaTime) {
if (recoiling_time_accumulator_ > 0) {
recoiling_time_accumulator_ -= deltaTime;
return;
}
handleCoolingState(deltaTime);
}
void Player::handleCoolingState() {
if (cooling_state_counter_ > COOLING_COMPLETE) {
if (cooling_state_counter_ == COOLING_DURATION) {
@@ -544,6 +714,26 @@ void Player::handleCoolingState() {
}
}
// Fase 2: Manejo del estado de enfriamiento (time-based)
void Player::handleCoolingState(float deltaTime) {
float coolingCompleteTime = static_cast<float>(COOLING_COMPLETE) / 60.0f;
float coolingDurationTime = static_cast<float>(COOLING_DURATION) / 60.0f;
float frameTime = 1.0f / 60.0f;
if (cooling_time_accumulator_ > coolingCompleteTime) {
// Transición a cooling cuando empezamos (equivalente a == COOLING_DURATION)
if (cooling_time_accumulator_ <= coolingDurationTime && cooling_time_accumulator_ > coolingDurationTime - frameTime) {
transitionToCooling();
}
cooling_time_accumulator_ -= deltaTime;
}
if (cooling_time_accumulator_ <= coolingCompleteTime) {
cooling_time_accumulator_ = coolingCompleteTime;
completeCooling();
}
}
void Player::transitionToRecoiling() {
switch (firing_state_) {
case State::FIRING_LEFT:
@@ -595,6 +785,20 @@ void Player::update() {
updateShowingName();
}
// Fase 1-4: Método deltaTime completo
void Player::update(float deltaTime) {
move(deltaTime); // Sistema de movimiento time-based
setAnimation(deltaTime); // Animaciones time-based
shiftColliders(); // Sin cambios (posicional)
updateCooldown(deltaTime); // Fase 2: Sistema de disparo time-based
updatePowerUp(deltaTime); // Fase 3: Sistema de power-up time-based
updateInvulnerable(deltaTime); // Fase 3: Sistema de invulnerabilidad time-based
updateScoreboard(); // Sin cambios (no temporal)
updateContinueCounter(deltaTime); // Fase 4: Sistema de continue time-based
updateEnterNameCounter(deltaTime); // Fase 4: Sistema de name entry time-based
updateShowingName(); // Sin cambios (no temporal)
}
void Player::passShowingName() {
if (game_completed_) {
setPlayingState(State::LEAVING_SCREEN);
@@ -664,6 +868,7 @@ void Player::setPlayingState(State state) {
// Inicializa el contador de continuar
continue_ticks_ = SDL_GetTicks();
continue_counter_ = 9;
continue_time_accumulator_ = 0.0f; // Initialize time accumulator
playSound("continue_clock.wav");
setScoreboardMode(Scoreboard::Mode::CONTINUE);
break;
@@ -682,6 +887,7 @@ void Player::setPlayingState(State state) {
}
pos_y_ = default_pos_y_;
waiting_counter_ = 0;
waiting_time_accumulator_ = 0.0f; // Initialize time accumulator
shiftSprite();
player_sprite_->setCurrentAnimation("hello");
player_sprite_->animtionPause();
@@ -749,12 +955,14 @@ void Player::setPlayingState(State state) {
}
case State::LEAVING_SCREEN: {
step_counter_ = 0;
step_time_accumulator_ = 0.0f; // Initialize time accumulator
setScoreboardMode(Scoreboard::Mode::GAME_COMPLETED);
break;
}
case State::ENTERING_SCREEN: {
init();
step_counter_ = 0;
step_time_accumulator_ = 0.0f; // Initialize time accumulator
setScoreboardMode(Scoreboard::Mode::SCORE);
switch (id_) {
case Id::PLAYER1:
@@ -795,9 +1003,10 @@ void Player::decScoreMultiplier() {
void Player::setInvulnerable(bool value) {
invulnerable_ = value;
invulnerable_counter_ = invulnerable_ ? INVULNERABLE_COUNTER : 0;
invulnerable_time_accumulator_ = invulnerable_ ? static_cast<float>(INVULNERABLE_COUNTER) / 60.0f : 0.0f; // Initialize time accumulator
}
// Monitoriza el estado
// Monitoriza el estado (frame-based)
void Player::updateInvulnerable() {
if (playing_state_ == State::PLAYING && invulnerable_) {
if (invulnerable_counter_ > 0) {
@@ -827,13 +1036,46 @@ void Player::updateInvulnerable() {
}
}
// Fase 3: Monitoriza el estado (time-based)
void Player::updateInvulnerable(float deltaTime) {
if (playing_state_ == State::PLAYING && invulnerable_) {
if (invulnerable_time_accumulator_ > 0) {
invulnerable_time_accumulator_ -= deltaTime;
// Frecuencia fija de parpadeo adaptada a deltaTime
constexpr float blink_period = 8.0f / 60.0f; // 8 frames convertidos a segundos
// Calcula proporción decreciente basada en tiempo restante
float total_invulnerable_time = static_cast<float>(INVULNERABLE_COUNTER) / 60.0f;
float progress = 1.0f - (invulnerable_time_accumulator_ / total_invulnerable_time);
float white_proportion = 0.5f - progress * 0.2f; // Menos blanco hacia el final
// Calcula si debe mostrar textura de invulnerabilidad basado en el ciclo temporal
float cycle_position = fmod(invulnerable_time_accumulator_, blink_period) / blink_period;
bool should_show_invulnerable = cycle_position < white_proportion;
size_t target_texture = should_show_invulnerable ? INVULNERABLE_TEXTURE : coffees_;
// Solo cambia textura si es diferente (optimización)
if (player_sprite_->getActiveTexture() != target_texture) {
player_sprite_->setActiveTexture(target_texture);
}
} else {
// Fin de invulnerabilidad
invulnerable_time_accumulator_ = 0;
setInvulnerable(false);
player_sprite_->setActiveTexture(coffees_);
}
}
}
// Establece el valor de la variable
void Player::setPowerUp() {
power_up_ = true;
power_up_counter_ = POWERUP_COUNTER;
power_up_time_accumulator_ = static_cast<float>(POWERUP_COUNTER) / 60.0f; // Initialize time accumulator
}
// Actualiza el valor de la variable
// Actualiza el valor de la variable (frame-based)
void Player::updatePowerUp() {
if (playing_state_ == State::PLAYING) {
if (power_up_) {
@@ -843,6 +1085,19 @@ void Player::updatePowerUp() {
}
}
// Fase 3: Actualiza el valor de la variable (time-based)
void Player::updatePowerUp(float deltaTime) {
if (playing_state_ == State::PLAYING) {
if (power_up_) {
power_up_time_accumulator_ -= deltaTime;
power_up_ = power_up_time_accumulator_ > 0;
if (!power_up_) {
power_up_time_accumulator_ = 0;
}
}
}
}
// Concede un toque extra al jugador
void Player::giveExtraHit() {
extra_hit_ = true;
@@ -875,7 +1130,7 @@ void Player::setPlayerTextures(const std::vector<std::shared_ptr<Texture>> &text
power_sprite_->setTexture(texture[1]);
}
// Actualiza el contador de continue
// Actualiza el contador de continue (frame-based)
void Player::updateContinueCounter() {
if (playing_state_ == State::CONTINUE) {
constexpr int TICKS_SPEED = 1000;
@@ -885,7 +1140,19 @@ void Player::updateContinueCounter() {
}
}
// Actualiza el contador de entrar nombre
// Fase 4: Actualiza el contador de continue (time-based)
void Player::updateContinueCounter(float deltaTime) {
if (playing_state_ == State::CONTINUE) {
continue_time_accumulator_ += deltaTime;
constexpr float CONTINUE_INTERVAL = 1.0f; // 1 segundo
if (continue_time_accumulator_ >= CONTINUE_INTERVAL) {
continue_time_accumulator_ -= CONTINUE_INTERVAL;
decContinueCounter();
}
}
}
// Actualiza el contador de entrar nombre (frame-based)
void Player::updateEnterNameCounter() {
if (playing_state_ == State::ENTERING_NAME || playing_state_ == State::ENTERING_NAME_GAME_COMPLETED) {
constexpr int TICKS_SPEED = 1000;
@@ -895,6 +1162,18 @@ void Player::updateEnterNameCounter() {
}
}
// Fase 4: Actualiza el contador de entrar nombre (time-based)
void Player::updateEnterNameCounter(float deltaTime) {
if (playing_state_ == State::ENTERING_NAME || playing_state_ == State::ENTERING_NAME_GAME_COMPLETED) {
name_entry_time_accumulator_ += deltaTime;
constexpr float NAME_ENTRY_INTERVAL = 1.0f; // 1 segundo
if (name_entry_time_accumulator_ >= NAME_ENTRY_INTERVAL) {
name_entry_time_accumulator_ -= NAME_ENTRY_INTERVAL;
decNameEntryCounter();
}
}
}
// Actualiza el estado de SHOWING_NAME
void Player::updateShowingName() {
if (playing_state_ == State::SHOWING_NAME) {
@@ -919,6 +1198,7 @@ void Player::decContinueCounter() {
// Decrementa el contador de entrar nombre
void Player::decNameEntryCounter() {
name_entry_ticks_ = SDL_GetTicks();
name_entry_time_accumulator_ = 0.0f; // Reset time accumulator
// Actualiza contadores
++name_entry_idle_counter_;

View File

@@ -94,9 +94,10 @@ class Player {
~Player() = default;
// --- Inicialización y ciclo de vida ---
void init(); // Inicializa el jugador
void update(); // Actualiza estado, animación y contadores
void render(); // Dibuja el jugador en pantalla
void init(); // Inicializa el jugador
void update(); // Actualiza estado, animación y contadores (frame-based)
void update(float deltaTime); // Actualiza estado, animación y contadores (time-based)
void render(); // Dibuja el jugador en pantalla
// --- Entrada y control ---
void setInput(Input::Action action); // Procesa entrada general
@@ -104,14 +105,17 @@ class Player {
void setInputEnteringName(Input::Action action); // Procesa entrada al introducir nombre
// --- Movimiento y animación ---
void move(); // Mueve el jugador
void setAnimation(); // Establece la animación según el estado
void move(); // Mueve el jugador (frame-based)
void move(float deltaTime); // Mueve el jugador (time-based)
void setAnimation(); // Establece la animación según el estado (frame-based)
void setAnimation(float deltaTime); // Establece la animación según el estado (time-based)
// --- Texturas y animaciones ---
void setPlayerTextures(const std::vector<std::shared_ptr<Texture>> &texture); // Cambia las texturas del jugador
// --- Estados y contadores ---
void updateCooldown(); // Actualiza el cooldown de disparo
void updateCooldown(); // Actualiza el cooldown de disparo (frame-based)
void updateCooldown(float deltaTime); // Actualiza el cooldown de disparo (time-based)
// --- Puntuación y marcador ---
void addScore(int score, int lowest_hi_score_entry); // Añade puntos
@@ -122,7 +126,8 @@ class Player {
void setPlayingState(State state); // Cambia el estado de juego
void setInvulnerable(bool value); // Establece el valor del estado de invulnerabilidad
void setPowerUp(); // Activa el modo PowerUp
void updatePowerUp(); // Actualiza el valor de PowerUp
void updatePowerUp(); // Actualiza el valor de PowerUp (frame-based)
void updatePowerUp(float deltaTime); // Actualiza el valor de PowerUp (time-based)
void giveExtraHit(); // Concede un toque extra al jugador
void removeExtraHit(); // Quita el toque extra al jugador
void decContinueCounter(); // Decrementa el contador de continuar
@@ -232,10 +237,19 @@ class Player {
int pos_y_ = 0; // Posición en el eje Y
int default_pos_y_; // Posición inicial para el jugador
int vel_y_ = 0; // Cantidad de píxeles a desplazarse en el eje Y
int cant_fire_counter_ = 0; // Contador durante el cual no puede disparar
int recoiling_state_counter_ = 0; // Contador para la animación del estado de retroceso
int cant_fire_counter_ = 0; // Contador durante el cual no puede disparar (frame-based)
int recoiling_state_counter_ = 0; // Contador para la animación del estado de retroceso (frame-based)
int recoiling_state_duration_ = 0; // Número 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 (frame-based)
float cant_fire_time_accumulator_ = 0.0f; // Acumulador de tiempo para cooldown de disparo (time-based)
float recoiling_time_accumulator_ = 0.0f; // Acumulador de tiempo para retroceso (time-based)
float cooling_time_accumulator_ = 0.0f; // Acumulador de tiempo para enfriamiento (time-based)
float invulnerable_time_accumulator_ = 0.0f; // Acumulador de tiempo para invulnerabilidad (time-based)
float power_up_time_accumulator_ = 0.0f; // Acumulador de tiempo para power-up (time-based)
float continue_time_accumulator_ = 0.0f; // Acumulador de tiempo para continue counter (time-based)
float name_entry_time_accumulator_ = 0.0f; // Acumulador de tiempo para name entry counter (time-based)
float waiting_time_accumulator_ = 0.0f; // Acumulador de tiempo para waiting movement (time-based)
float step_time_accumulator_ = 0.0f; // Acumulador de tiempo para step counter (time-based)
int invulnerable_counter_ = INVULNERABLE_COUNTER; // Contador para la invulnerabilidad
int score_ = 0; // Puntos del jugador
int coffees_ = 0; // Indica cuántos cafés lleva acumulados
@@ -259,9 +273,12 @@ class Player {
// --- Métodos internos ---
void shiftColliders(); // Actualiza el círculo de colisión a la posición del jugador
void shiftSprite(); // Recoloca el sprite
void updateInvulnerable(); // Monitoriza el estado de invulnerabilidad
void updateContinueCounter(); // Actualiza el contador de continue
void updateEnterNameCounter(); // Actualiza el contador de entrar nombre
void updateInvulnerable(); // Monitoriza el estado de invulnerabilidad (frame-based)
void updateInvulnerable(float deltaTime); // Monitoriza el estado de invulnerabilidad (time-based)
void updateContinueCounter(); // Actualiza el contador de continue (frame-based)
void updateContinueCounter(float deltaTime); // Actualiza el contador de continue (time-based)
void updateEnterNameCounter(); // Actualiza el contador de entrar nombre (frame-based)
void updateEnterNameCounter(float deltaTime); // Actualiza el contador de entrar nombre (time-based)
void updateShowingName(); // Actualiza el estado SHOWING_NAME
void decNameEntryCounter(); // Decrementa el contador de entrar nombre
void updateScoreboard(); // Actualiza el panel del marcador
@@ -269,13 +286,17 @@ class Player {
void playSound(const std::string &name) const; // Hace sonar un sonido
[[nodiscard]] auto isRenderable() const -> bool; // Indica si se puede dibujar el objeto
void addScoreToScoreBoard() const; // Añade una puntuación a la tabla de records
void handleFiringCooldown(); // Gestiona el tiempo de espera después de disparar antes de permitir otro disparo
void handleRecoilAndCooling(); // Procesa simultáneamente el retroceso del arma y la transición al estado de enfriamiento si aplica
void handleCoolingState(); // Actualiza la lógica interna mientras el sistema está en estado de enfriamiento
void handleFiringCooldown(); // Gestiona el tiempo de espera después de disparar antes de permitir otro disparo (frame-based)
void handleFiringCooldown(float deltaTime); // Gestiona el tiempo de espera después de disparar antes de permitir otro disparo (time-based)
void handleRecoilAndCooling(); // Procesa simultáneamente el retroceso del arma y la transición al estado de enfriamiento si aplica (frame-based)
void handleRecoilAndCooling(float deltaTime); // Procesa simultáneamente el retroceso del arma y la transición al estado de enfriamiento si aplica (time-based)
void handleCoolingState(); // Actualiza la lógica interna mientras el sistema está en estado de enfriamiento (frame-based)
void handleCoolingState(float deltaTime); // Actualiza la lógica interna mientras el sistema está en estado de enfriamiento (time-based)
void transitionToRecoiling(); // Cambia el estado actual al de retroceso después de disparar
void transitionToCooling(); // Cambia el estado actual al de enfriamiento (por ejemplo, tras una ráfaga o sobrecalentamiento)
void completeCooling(); // Finaliza el proceso de enfriamiento y restablece el estado listo para disparar
void handlePlayingMovement(); // Gestiona el movimiento del personaje u objeto durante el estado de juego activo
void handlePlayingMovement(); // Gestiona el movimiento del personaje u objeto durante el estado de juego activo (frame-based)
void handlePlayingMovement(float deltaTime); // Gestiona el movimiento del personaje u objeto durante el estado de juego activo (time-based)
void handleRecoverMovement(); // Comprueba si ha acabado la animación
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
@@ -288,12 +309,15 @@ class Player {
void handleEnteringScreen(); // Lógica para entrar en una nueva pantalla, posiblemente con animación o retraso
void handlePlayer1Entering(); // Controla la animación o posición de entrada del Jugador 1 en pantalla
void handlePlayer2Entering(); // Controla la animación o posición de entrada del Jugador 2 en pantalla
void handleCreditsMovement(); // Movimiento general en la pantalla de créditos (desplazamiento vertical u horizontal)
void handleCreditsMovement(); // Movimiento general en la pantalla de créditos (frame-based)
void handleCreditsMovement(float deltaTime); // Movimiento general en la pantalla de créditos (time-based)
void handleCreditsRightMovement(); // Lógica específica para mover los créditos hacia la derecha
void handleCreditsLeftMovement(); // Lógica específica para mover los créditos hacia la izquierda
void handleWaitingMovement(); // Controla la animación del jugador saludando
void handleWaitingMovement(); // Controla la animación del jugador saludando (frame-based)
void handleWaitingMovement(float deltaTime); // Controla la animación del jugador saludando (time-based)
void updateWalkingStateForCredits(); // Actualiza el estado de caminata de algún personaje u elemento animado en los créditos
void setInputBasedOnPlayerId(); // Asocia las entradas de control en función del identificador del jugador (teclas, mando, etc.)
void updateStepCounter(); // Incrementa o ajusta el contador de pasos para animaciones o mecánicas relacionadas con movimiento
void updateStepCounter(); // Incrementa o ajusta el contador de pasos (frame-based)
void updateStepCounter(float deltaTime); // Incrementa o ajusta el contador de pasos (time-based)
[[nodiscard]] auto computeAnimation() const -> std::pair<std::string, SDL_FlipMode>; // Calcula la animacion de moverse y disparar del jugador
};

View File

@@ -78,20 +78,31 @@ Credits::~Credits() {
Options::gamepad_manager.clearPlayers();
}
// Calcula el deltatime
auto Credits::calculateDeltaTime() -> float {
const Uint64 current_time = SDL_GetTicks();
const float delta_time = static_cast<float>(current_time - last_time_);
last_time_ = current_time;
return delta_time;
}
// Bucle principal
void Credits::run() {
last_time_ = SDL_GetTicks();
while (Section::name == Section::Name::CREDITS) {
checkInput();
update();
const float delta_time = calculateDeltaTime();
update(delta_time);
checkEvents(); // Tiene que ir antes del render
render();
}
}
// Actualiza las variables
// Actualiza las variables (frame-based)
void Credits::update() {
if (SDL_GetTicks() - ticks_ > param.game.speed) {
ticks_ = SDL_GetTicks();
if (SDL_GetTicks() - last_time_ > param.game.speed) {
last_time_ = SDL_GetTicks();
const int REPEAT = want_to_pass_ ? 4 : 1;
for (int i = 0; i < REPEAT; ++i) {
tiled_bg_->update();
@@ -111,6 +122,28 @@ void Credits::update() {
Audio::update();
}
// Actualiza las variables (time-based)
void Credits::update(float deltaTime) {
const float multiplier = want_to_pass_ ? 4.0f : 1.0f;
const float adjusted_delta_time = deltaTime * multiplier;
tiled_bg_->update(adjusted_delta_time);
cycleColors();
balloon_manager_->update(adjusted_delta_time);
updateTextureDstRects(adjusted_delta_time);
throwBalloons(adjusted_delta_time);
updatePlayers(adjusted_delta_time);
updateAllFades(adjusted_delta_time);
// Convertir deltaTime a factor de frame (asumiendo 60fps)
const float frameFactor = adjusted_delta_time / (1000.0f / 60.0f);
counter_ += frameFactor;
Screen::get()->update();
fillCanvas();
Audio::update();
}
// Dibuja Credits::en patalla
void Credits::render() {
static auto *const SCREEN = Screen::get();
@@ -277,9 +310,9 @@ void Credits::fillCanvas() {
SDL_SetRenderTarget(Screen::get()->getRenderer(), temp);
}
// Actualiza el destino de los rectangulos de las texturas
// Actualiza el destino de los rectangulos de las texturas (frame-based)
void Credits::updateTextureDstRects() {
if (counter_ % 10 == 0) {
if (static_cast<int>(counter_) % 10 == 0) {
// Comprueba la posición de la textura con los titulos de credito
if (credits_rect_dst_.y + credits_rect_dst_.h > play_area_.y) {
--credits_rect_dst_.y;
@@ -306,7 +339,42 @@ void Credits::updateTextureDstRects() {
}
}
// Tira globos al escenario
// Actualiza el destino de los rectangulos de las texturas (time-based)
void Credits::updateTextureDstRects(float deltaTime) {
constexpr float TEXTURE_UPDATE_INTERVAL = 10 * (1000.0f / 60.0f); // 166.67ms (cada 10 frames)
static float texture_accumulator = 0.0f;
texture_accumulator += deltaTime;
if (texture_accumulator >= TEXTURE_UPDATE_INTERVAL) {
texture_accumulator -= TEXTURE_UPDATE_INTERVAL;
// Comprueba la posición de la textura con los titulos de credito
if (credits_rect_dst_.y + credits_rect_dst_.h > play_area_.y) {
--credits_rect_dst_.y;
}
// Comprueba la posición de la textura con el mini_logo
if (mini_logo_rect_dst_.y == mini_logo_final_pos_) {
mini_logo_on_position_ = true;
// Si el jugador quiere pasar los titulos de credito, el fade se inicia solo
if (want_to_pass_) {
fading_ = true;
}
// Se activa el contador para evitar que la sección sea infinita
if (counter_prevent_endless_ == 1000) {
fading_ = true;
} else {
++counter_prevent_endless_;
}
} else {
--mini_logo_rect_dst_.y;
}
}
}
// Tira globos al escenario (frame-based)
void Credits::throwBalloons() {
constexpr int SPEED = 200;
const std::vector<int> SETS = {0, 63, 25, 67, 17, 75, 13, 50};
@@ -315,12 +383,41 @@ void Credits::throwBalloons() {
return;
}
if (counter_ % SPEED == 0) {
const int INDEX = (counter_ / SPEED) % SETS.size();
if (static_cast<int>(counter_) % SPEED == 0) {
const int INDEX = (static_cast<int>(counter_) / SPEED) % SETS.size();
balloon_manager_->deployFormation(SETS.at(INDEX), -60);
}
if (counter_ % (SPEED * 4) == 0 && counter_ > 0) {
if (static_cast<int>(counter_) % (SPEED * 4) == 0 && counter_ > 0) {
balloon_manager_->createPowerBall();
}
}
// Tira globos al escenario (time-based)
void Credits::throwBalloons(float deltaTime) {
constexpr int SPEED = 200;
const std::vector<int> SETS = {0, 63, 25, 67, 17, 75, 13, 50};
constexpr float BALLOON_INTERVAL = SPEED * (1000.0f / 60.0f); // 3333.33ms (cada 200 frames)
constexpr float POWERBALL_INTERVAL = (SPEED * 4) * (1000.0f / 60.0f); // 13333.33ms (cada 800 frames)
if (counter_ > ((SETS.size() - 1) * SPEED) * 3) {
return;
}
static float balloon_accumulator = 0.0f;
static float powerball_accumulator = 0.0f;
balloon_accumulator += deltaTime;
powerball_accumulator += deltaTime;
if (balloon_accumulator >= BALLOON_INTERVAL) {
balloon_accumulator -= BALLOON_INTERVAL;
const int INDEX = (static_cast<int>(counter_ / SPEED)) % SETS.size();
balloon_manager_->deployFormation(SETS.at(INDEX), -60);
}
if (powerball_accumulator >= POWERBALL_INTERVAL && counter_ > 0) {
powerball_accumulator -= POWERBALL_INTERVAL;
balloon_manager_->createPowerBall();
}
}
@@ -392,12 +489,12 @@ void Credits::initPlayers() {
}
}
// Actualiza los rectangulos negros
// Actualiza los rectangulos negros (frame-based)
void Credits::updateBlackRects() {
static int current_step_ = steps_;
if (top_black_rect_.h != param.game.game_area.center_y - 1 && bottom_black_rect_.y != param.game.game_area.center_y + 1) {
// Si los rectangulos superior e inferior no han llegado al centro
if (counter_ % 4 == 0) {
if (static_cast<int>(counter_) % 4 == 0) {
// Incrementa la altura del rectangulo superior
top_black_rect_.h = std::min(top_black_rect_.h + 1, param.game.game_area.center_y - 1);
@@ -435,6 +532,57 @@ void Credits::updateBlackRects() {
}
}
// Actualiza los rectangulos negros (time-based)
void Credits::updateBlackRects(float deltaTime) {
static float current_step_ = static_cast<float>(steps_);
constexpr float BLACK_RECT_INTERVAL = 4 * (1000.0f / 60.0f); // 66.67ms (cada 4 frames)
static float black_rect_accumulator = 0.0f;
if (top_black_rect_.h != param.game.game_area.center_y - 1 && bottom_black_rect_.y != param.game.game_area.center_y + 1) {
// Si los rectangulos superior e inferior no han llegado al centro
black_rect_accumulator += deltaTime;
if (black_rect_accumulator >= BLACK_RECT_INTERVAL) {
black_rect_accumulator -= BLACK_RECT_INTERVAL;
// Incrementa la altura del rectangulo superior
top_black_rect_.h = std::min(top_black_rect_.h + 1, param.game.game_area.center_y - 1);
// Incrementa la altura y modifica la posición del rectangulo inferior
++bottom_black_rect_.h;
bottom_black_rect_.y = std::max(bottom_black_rect_.y - 1, param.game.game_area.center_y + 1);
--current_step_;
setVolume(static_cast<int>(initial_volume_ * current_step_ / steps_));
}
} else {
// Si los rectangulos superior e inferior han llegado al centro
if (left_black_rect_.w != param.game.game_area.center_x && right_black_rect_.x != param.game.game_area.center_x) {
constexpr int SPEED = 2;
// Si los rectangulos izquierdo y derecho no han llegado al centro
// Incrementa la anchura del rectangulo situado a la izquierda
left_black_rect_.w = std::min(left_black_rect_.w + SPEED, param.game.game_area.center_x);
// Incrementa la anchura y modifica la posición del rectangulo situado a la derecha
right_black_rect_.w += SPEED;
right_black_rect_.x = std::max(right_black_rect_.x - SPEED, param.game.game_area.center_x);
--current_step_;
setVolume(static_cast<int>(initial_volume_ * current_step_ / steps_));
} else {
// Si los rectangulos izquierdo y derecho han llegado al centro
setVolume(0);
Audio::get()->stopMusic();
if (counter_pre_fade_ == 400) {
fade_out_->activate();
} else {
// Convertir deltaTime a factor de frame
const float frameFactor = deltaTime / (1000.0f / 60.0f);
counter_pre_fade_ += frameFactor;
}
}
}
}
// Actualiza el rectangulo rojo
void Credits::updateRedRect() {
border_rect_.x = left_black_rect_.x + left_black_rect_.w;
@@ -443,7 +591,7 @@ void Credits::updateRedRect() {
border_rect_.h = bottom_black_rect_.y - border_rect_.y + 1;
}
// Actualiza el estado de fade
// Actualiza el estado de fade (frame-based)
void Credits::updateAllFades() {
if (fading_) {
updateBlackRects();
@@ -461,6 +609,24 @@ void Credits::updateAllFades() {
}
}
// Actualiza el estado de fade (time-based)
void Credits::updateAllFades(float deltaTime) {
if (fading_) {
updateBlackRects(deltaTime);
updateRedRect();
}
fade_in_->update(); // Fade ya usa tiempo interno
if (fade_in_->hasEnded()) {
Audio::get()->playMusic("credits.ogg");
}
fade_out_->update(); // Fade ya usa tiempo interno
if (fade_out_->hasEnded()) {
Section::name = Section::Name::HI_SCORE_TABLE;
}
}
// Establece el nivel de volumen
void Credits::setVolume(int amount) {
Options::audio.music.volume = std::clamp(amount, 0, 100);
@@ -508,13 +674,20 @@ void Credits::cycleColors() {
tiled_bg_->setColor(color_);
}
// Actualza los jugadores
// Actualza los jugadores (frame-based)
void Credits::updatePlayers() {
for (auto &player : players_) {
player->update();
}
}
// Actualza los jugadores (time-based)
void Credits::updatePlayers(float deltaTime) {
for (auto &player : players_) {
player->update(deltaTime);
}
}
// Renderiza los jugadores
void Credits::renderPlayers() {
for (auto const &player : players_) {

View File

@@ -25,6 +25,12 @@ class Credits {
// --- Bucle principal ---
void run();
private:
// --- Métodos del bucle principal ---
void update(); // Actualización principal de la lógica (frame-based)
void update(float deltaTime); // Actualización principal de la lógica (time-based)
auto calculateDeltaTime() -> float; // Calcula el deltatime
private:
// --- Constantes de clase ---
static constexpr int PLAY_AREA_HEIGHT = 200;
@@ -41,10 +47,10 @@ class Credits {
SDL_Texture *canvas_; // Textura donde se dibuja todo
// --- Temporización y contadores ---
Uint64 ticks_ = 0; // Control de velocidad del programa
Uint32 counter_ = 0; // Contador principal de lógica
Uint32 counter_pre_fade_ = 0; // Activación del fundido final
Uint32 counter_prevent_endless_ = 0; // Prevención de bucle infinito
Uint64 last_time_ = 0; // Último tiempo registrado para deltaTime
float counter_ = 0; // Contador principal de lógica
float counter_pre_fade_ = 0; // Activación del fundido final
float counter_prevent_endless_ = 0; // Prevención de bucle infinito
// --- Variables de estado ---
bool fading_ = false; // Estado del fade final
@@ -101,8 +107,6 @@ class Credits {
// Borde para la ventana
SDL_FRect border_rect_ = play_area_; // Delimitador de ventana
// --- Métodos del bucle principal ---
void update(); // Actualización principal de la lógica
void render(); // Renderizado de la escena
static void checkEvents(); // Manejo de eventos
void checkInput(); // Procesamiento de entrada
@@ -110,19 +114,24 @@ class Credits {
// --- Métodos de renderizado ---
void fillTextTexture(); // Crear textura de texto de créditos
void fillCanvas(); // Renderizar todos los sprites y fondos
void updateTextureDstRects(); // Actualizar destinos de texturas
void renderPlayers(); // Renderiza los jugadores
// --- Métodos de lógica del juego ---
void throwBalloons(); // Lanzar globos al escenario
void initPlayers(); // Inicializar jugadores
void updateAllFades(); // Actualizar estados de fade
void cycleColors(); // Cambiar colores de fondo
void updatePlayers(); // Actualza los jugadores
void throwBalloons(); // Lanzar globos al escenario (frame-based)
void throwBalloons(float deltaTime); // Lanzar globos al escenario (time-based)
void initPlayers(); // Inicializar jugadores
void updateAllFades(); // Actualizar estados de fade (frame-based)
void updateAllFades(float deltaTime); // Actualizar estados de fade (time-based)
void cycleColors(); // Cambiar colores de fondo
void updatePlayers(); // Actualza los jugadores (frame-based)
void updatePlayers(float deltaTime); // Actualza los jugadores (time-based)
// --- Métodos de interfaz ---
void updateBlackRects(); // Actualizar rectángulos negros (letterbox)
void updateRedRect(); // Actualizar rectángulo rojo (borde)
void updateBlackRects(); // Actualizar rectángulos negros (letterbox) (frame-based)
void updateBlackRects(float deltaTime); // Actualizar rectángulos negros (letterbox) (time-based)
void updateRedRect(); // Actualizar rectángulo rojo (borde)
void updateTextureDstRects(); // Actualizar destinos de texturas (frame-based)
void updateTextureDstRects(float deltaTime); // Actualizar destinos de texturas (time-based)
// --- Métodos de audio ---
static void setVolume(int amount); // Establecer volumen

View File

@@ -210,7 +210,7 @@ void Game::updateHiScore() {
}
}
// Actualiza las variables del jugador
// Actualiza las variables del jugador (frame-based)
void Game::updatePlayers() {
for (auto &player : players_) {
player->update();
@@ -246,6 +246,42 @@ void Game::updatePlayers() {
sortPlayersByZOrder();
}
// Actualiza las variables del jugador (time-based)
void Game::updatePlayers(float deltaTime) {
for (auto &player : players_) {
player->update(deltaTime);
if (player->isPlaying()) {
// Comprueba la colisión entre el jugador y los globos
auto balloon = checkPlayerBalloonCollision(player);
// Si hay colisión
if (balloon) {
// Si el globo está parado y el temporizador activo, lo explota
if (balloon->isStopped() && time_stopped_counter_ > 0) {
balloon_manager_->popBalloon(balloon);
}
// En caso contrario, el jugador ha sido golpeado por un globo activo
else {
handlePlayerCollision(player, balloon);
if (demo_.enabled && allPlayersAreNotPlaying()) {
fade_out_->setType(Fade::Type::RANDOM_SQUARE2);
fade_out_->setPostDuration(500);
fade_out_->activate();
}
}
}
// Comprueba las colisiones entre el jugador y los items
checkPlayerItemCollision(player);
}
}
// Organiza la lista de jugadores
sortPlayersByZOrder();
}
// Dibuja a los jugadores
void Game::renderPlayers() {
for (auto &player : players_) {
@@ -892,14 +928,14 @@ void Game::updateTimeStopped() {
if (time_stopped_counter_ > 0) {
time_stopped_counter_--;
if (time_stopped_counter_ > 120) {
if (time_stopped_counter_ % 30 == 0) {
if (static_cast<int>(time_stopped_counter_) % 30 == 0) {
playSound("clock.wav");
}
} else {
if (time_stopped_counter_ % 30 == 0) {
if (static_cast<int>(time_stopped_counter_) % 30 == 0) {
balloon_manager_->normalColorsToAllBalloons();
playSound("clock.wav");
} else if (time_stopped_counter_ % 30 == 15) {
} else if (static_cast<int>(time_stopped_counter_) % 30 == 15) {
balloon_manager_->reverseColorsToAllBalloons();
playSound("clock.wav");
}
@@ -909,9 +945,10 @@ void Game::updateTimeStopped() {
}
}
// Actualiza toda la lógica del juego (frame-based)
void Game::update() {
if (SDL_GetTicks() - ticks_ > param.game.speed) {
ticks_ = SDL_GetTicks();
if (SDL_GetTicks() - last_time_ > param.game.speed) {
last_time_ = SDL_GetTicks();
screen_->update();
updateDemo();
@@ -925,6 +962,20 @@ void Game::update() {
Audio::update();
}
// Actualiza toda la lógica del juego (time-based)
void Game::update(float deltaTime) {
screen_->update();
updateDemo();
#ifdef RECORDING
updateRecording();
#endif
updateGameStates();
fillCanvas();
Audio::update();
}
// Dibuja el juego
void Game::render() {
screen_->start(); // Prepara para empezar a dibujar en la textura de juego
@@ -1006,13 +1057,24 @@ void Game::disableTimeStopItem() {
balloon_manager_->normalColorsToAllBalloons();
}
// Calcula el deltatime
auto Game::calculateDeltaTime() -> float {
const Uint64 current_time = SDL_GetTicks();
const float delta_time = static_cast<float>(current_time - last_time_);
last_time_ = current_time;
return delta_time;
}
// Bucle para el juego
void Game::run() {
last_time_ = SDL_GetTicks();
while (Section::name == Section::Name::GAME) {
#ifndef RECORDING
checkInput();
#endif
update();
const float delta_time = calculateDeltaTime();
update(delta_time);
handleEvents(); // Tiene que ir antes del render
render();
}

View File

@@ -77,7 +77,7 @@ class Game {
bool need_coffee{false}; // Indica si se necesitan cafes
bool need_coffee_machine{false}; // Indica si se necesita PowerUp
bool need_power_ball{false}; // Indica si se necesita una PowerBall
int counter; // Contador para no dar ayudas consecutivas
float counter; // Contador para no dar ayudas consecutivas
int item_disk_odds; // Probabilidad de aparición del objeto
int item_gavina_odds; // Probabilidad de aparición del objeto
int item_pacmar_odds; // Probabilidad de aparición del objeto
@@ -134,14 +134,14 @@ class Game {
Demo demo_; // Variable con todas las variables relacionadas con el modo demo
Difficulty::Code difficulty_ = Options::settings.difficulty; // Dificultad del juego
Helper helper_; // Variable para gestionar las ayudas
Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
Uint64 last_time_ = 0; // Último tiempo registrado para deltaTime
bool coffee_machine_enabled_ = false; // Indica si hay una máquina de café en el terreno de juego
bool hi_score_achieved_ = false; // Indica si se ha superado la puntuación máxima
float difficulty_score_multiplier_; // Multiplicador de puntos en función de la dificultad
int counter_ = 0; // Contador para el juego
int game_completed_counter_ = 0; // Contador para el tramo final, cuando se ha completado la partida y ya no aparecen más globos
int game_over_counter_ = GAME_OVER_COUNTER; // Contador para el estado de fin de partida
int time_stopped_counter_ = 0; // Temporizador para llevar la cuenta del tiempo detenido
float counter_ = 0; // Contador para el juego
float game_completed_counter_ = 0; // Contador para el tramo final, cuando se ha completado la partida y ya no aparecen más globos
float game_over_counter_ = GAME_OVER_COUNTER; // Contador para el estado de fin de partida
float time_stopped_counter_ = 0; // Temporizador para llevar la cuenta del tiempo detenido
int menace_ = 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
State state_ = State::FADE_IN; // Estado
@@ -154,25 +154,28 @@ class Game {
#endif
// --- Ciclo principal del juego ---
void update(); // Actualiza la lógica principal del juego
void render(); // Renderiza todos los elementos del juego
void update(); // Actualiza la lógica principal del juego (frame-based)
void update(float deltaTime); // Actualiza la lógica principal del juego (time-based)
auto calculateDeltaTime() -> float; // Calcula el deltatime
void render(); // Renderiza todos los elementos del juego
void handleEvents(); // Procesa los eventos del sistema en cola
void checkState(); // Verifica y actualiza el estado actual del juego
void setState(State state); // Cambia el estado del juego
void cleanVectors(); // Limpia vectores de elementos deshabilitados
// --- Gestión de estados del juego ---
void updateGameStates(); // Actualiza todos los estados del juego
void updateGameStateFadeIn(); // Gestiona el estado de transición de entrada
void updateGameStateEnteringPlayer(); // Gestiona el estado de entrada de jugador
void updateGameStateShowingGetReadyMessage(); // Gestiona el estado de mensaje "preparado"
void updateGameStatePlaying(); // Gestiona el estado de juego activo
void updateGameStateCompleted(); // Gestiona el estado de juego completado
void updateGameStateGameOver(); // Gestiona el estado de fin de partida
void updateGameStates(); // Actualiza todos los estados del juego (usa deltaTime interno)
void updateGameStateFadeIn(); // Gestiona el estado de transición de entrada
void updateGameStateEnteringPlayer(); // Gestiona el estado de entrada de jugador
void updateGameStateShowingGetReadyMessage(); // Gestiona el estado de mensaje "preparado"
void updateGameStatePlaying(); // Gestiona el estado de juego activo
void updateGameStateCompleted(); // Gestiona el estado de juego completado
void updateGameStateGameOver(); // Gestiona el estado de fin de partida
// --- Gestión de jugadores ---
void initPlayers(Player::Id player_id); // Inicializa los datos de los jugadores
void updatePlayers(); // Actualiza las variables y estados de los jugadores
void updatePlayers(); // Actualiza las variables y estados de los jugadores (frame-based)
void updatePlayers(float deltaTime); // Actualiza las variables y estados de los jugadores (time-based)
void renderPlayers(); // Renderiza todos los jugadores en pantalla
void sortPlayersByZOrder(); // Reorganiza el orden de dibujado de jugadores
auto getPlayer(Player::Id id) -> std::shared_ptr<Player>; // Obtiene un jugador por su identificador
@@ -229,9 +232,10 @@ class Game {
void destroyAllItems(); // Elimina todos los ítems activos de la pantalla
// --- ítems especiales ---
void enableTimeStopItem(); // Activa el efecto de detener el tiempo
void disableTimeStopItem(); // Desactiva el efecto de detener el tiempo
void updateTimeStopped(); // Actualiza el estado del tiempo detenido
void enableTimeStopItem(); // Activa el efecto de detener el tiempo
void disableTimeStopItem(); // Desactiva el efecto de detener el tiempo
void updateTimeStopped(); // Actualiza el estado del tiempo detenido (frame-based)
void updateTimeStopped(float deltaTime); // Actualiza el estado del tiempo detenido (time-based)
void throwCoffee(int x, int y); // Crea efecto de café arrojado al ser golpeado
// --- Gestión de caída de ítems ---

View File

@@ -33,7 +33,7 @@ HiScoreTable::HiScoreTable()
backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
fade_(std::make_unique<Fade>()),
background_(std::make_unique<Background>()),
ticks_(0),
last_time_(0),
view_area_(SDL_FRect{0, 0, param.game.width, param.game.height}),
fade_mode_(Fade::Mode::IN),
background_fade_color_(Color(0, 0, 0)) {
@@ -53,17 +53,14 @@ HiScoreTable::~HiScoreTable() {
}
// Actualiza las variables
void HiScoreTable::update() {
if (SDL_GetTicks() - ticks_ > param.game.speed) {
ticks_ = SDL_GetTicks(); // Actualiza el contador de ticks
Screen::get()->update(); // Actualiza el objeto screen
void HiScoreTable::update(float delta_time) {
Screen::get()->update(); // Actualiza el objeto screen
updateSprites(); // Actualiza las posiciones de los sprites de texto
background_->update(); // Actualiza el fondo
updateFade(); // Gestiona el fade
updateCounter(); // Gestiona el contador y sus eventos
fillTexture(); // Dibuja los sprites en la textura
}
updateSprites(delta_time); // Actualiza las posiciones de los sprites de texto
background_->update(delta_time); // Actualiza el fondo
updateFade(delta_time); // Gestiona el fade
updateCounter(); // Gestiona el contador y sus eventos
fillTexture(); // Dibuja los sprites en la textura
Audio::update();
}
@@ -117,20 +114,32 @@ void HiScoreTable::checkInput() {
GlobalInputs::check();
}
// Calcula el tiempo transcurrido desde el último frame
float HiScoreTable::calculateDeltaTime() {
const Uint64 current_time = SDL_GetTicks();
const float delta_time = static_cast<float>(current_time - last_time_);
last_time_ = current_time;
return delta_time;
}
// Bucle para la pantalla de instrucciones
void HiScoreTable::run() {
last_time_ = SDL_GetTicks();
Audio::get()->playMusic("title.ogg");
while (Section::name == Section::Name::HI_SCORE_TABLE) {
const float delta_time = calculateDeltaTime();
checkInput();
update();
update(delta_time);
checkEvents(); // Tiene que ir antes del render
render();
}
}
// Gestiona el fade
void HiScoreTable::updateFade() {
fade_->update();
void HiScoreTable::updateFade(float delta_time) {
fade_->update(delta_time);
if (fade_->hasEnded() && fade_mode_ == Fade::Mode::IN) {
fade_->reset();
@@ -249,7 +258,7 @@ void HiScoreTable::createSprites() {
}
// Actualiza las posiciones de los sprites de texto
void HiScoreTable::updateSprites() {
void HiScoreTable::updateSprites(float delta_time) {
constexpr int INIT_COUNTER = 190;
const int COUNTER_BETWEEN_ENTRIES = 16;
if (counter_ >= INIT_COUNTER) {
@@ -262,7 +271,7 @@ void HiScoreTable::updateSprites() {
}
}
for (auto const &entry : entry_names_) {
entry->update();
entry->update(delta_time);
}
glowEntryNames();

View File

@@ -45,26 +45,27 @@ class HiScoreTable {
// --- Variables ---
Uint16 counter_ = 0; // Contador
Uint64 ticks_; // Contador de ticks para ajustar la velocidad del programa
Uint64 last_time_ = 0; // Último timestamp para calcular delta-time
SDL_FRect view_area_; // Parte de la textura que se muestra en pantalla
Fade::Mode fade_mode_; // Modo de fade a utilizar
Color background_fade_color_; // Color de atenuación del fondo
std::vector<Color> entry_colors_; // Colores para destacar las entradas en la tabla
// --- Métodos internos ---
void update(); // Actualiza las variables
void update(float delta_time); // Actualiza las variables
void render(); // Pinta en pantalla
static void checkEvents(); // Comprueba los eventos
static void checkInput(); // Comprueba las entradas
static auto format(int number) -> std::string; // Convierte un entero a un string con separadores de miles
void fillTexture(); // Dibuja los sprites en la textura
void updateFade(); // Gestiona el fade
void updateFade(float delta_time); // Gestiona el fade
void createSprites(); // Crea los sprites con los textos
void updateSprites(); // Actualiza las posiciones de los sprites de texto
void updateSprites(float delta_time); // Actualiza las posiciones de los sprites de texto
void initFade(); // Inicializa el fade
void initBackground(); // Inicializa el fondo
auto getEntryColor(int counter) -> Color; // Obtiene un color del vector de colores de entradas
void iniEntryColors(); // Inicializa los colores de las entradas
void glowEntryNames(); // Hace brillar los nombres de la tabla de records
void updateCounter(); // Gestiona el contador
float calculateDeltaTime(); // Calcula el tiempo transcurrido desde el último frame
};

View File

@@ -204,18 +204,15 @@ void Instructions::fillBackbuffer() {
}
// Actualiza las variables
void Instructions::update() {
if (SDL_GetTicks() - ticks_ > param.game.speed) {
ticks_ = SDL_GetTicks(); // Actualiza el contador de ticks
Screen::get()->update(); // Actualiza el objeto screen
void Instructions::update(float delta_time) {
Screen::get()->update(); // Actualiza el objeto screen
counter_++; // Incrementa el contador
updateSprites(); // Actualiza los sprites
updateBackbuffer(); // Gestiona la textura con los graficos
tiled_bg_->update(); // Actualiza el mosaico de fondo
fade_->update(); // Actualiza el objeto "fade"
fillBackbuffer(); // Rellena el backbuffer
}
counter_++; // Incrementa el contador
updateSprites(); // Actualiza los sprites
updateBackbuffer(); // Gestiona la textura con los graficos
tiled_bg_->update(delta_time); // Actualiza el mosaico de fondo
fade_->update(delta_time); // Actualiza el objeto "fade"
fillBackbuffer(); // Rellena el backbuffer
Audio::update();
}
@@ -255,12 +252,24 @@ void Instructions::checkInput() {
GlobalInputs::check();
}
// Calcula el tiempo transcurrido desde el último frame
float Instructions::calculateDeltaTime() {
const Uint64 current_time = SDL_GetTicks();
const float delta_time = static_cast<float>(current_time - last_time_);
last_time_ = current_time;
return delta_time;
}
// Bucle para la pantalla de instrucciones
void Instructions::run() {
last_time_ = SDL_GetTicks();
Audio::get()->playMusic("title.ogg");
while (Section::name == Section::Name::INSTRUCTIONS) {
const float delta_time = calculateDeltaTime();
checkInput();
update();
update(delta_time);
checkEvents(); // Tiene que ir antes del render
render();
}

View File

@@ -63,7 +63,7 @@ class Instructions {
// --- Variables ---
int counter_ = 0; // Contador para manejar el progreso en la pantalla de instrucciones
Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
Uint64 last_time_ = 0; // Último timestamp para calcular delta-time
SDL_FRect view_; // Vista del backbuffer que se va a mostrar por pantalla
SDL_FPoint sprite_pos_ = {0, 0}; // Posición del primer sprite en la lista
float item_space_ = 2.0; // Espacio entre los items en pantalla
@@ -73,7 +73,7 @@ class Instructions {
bool start_delay_triggered_ = false; // Bandera para determinar si el retraso ha comenzado
// --- Métodos internos ---
void update(); // Actualiza las variables
void update(float delta_time); // Actualiza las variables
void render(); // Pinta en pantalla
static void checkEvents(); // Comprueba los eventos
static void checkInput(); // Comprueba las entradas
@@ -82,7 +82,8 @@ class Instructions {
void iniSprites(); // Inicializa los sprites de los items
void updateSprites(); // Actualiza los sprites
static auto initializeLines(int height) -> std::vector<Line>; // Inicializa las líneas animadas
static auto moveLines(std::vector<Line> &lines, int width, float duration, Uint32 start_delay) -> bool; // Mueve las líneas
static auto moveLines(std::vector<Line> &lines, int width, float duration, Uint32 start_delay) -> bool; // Mueve las líneas (ya usa tiempo real)
static void renderLines(SDL_Renderer *renderer, SDL_Texture *texture, const std::vector<Line> &lines); // Renderiza las líneas
void updateBackbuffer(); // Gestiona la textura con los gráficos
float calculateDeltaTime(); // Calcula el tiempo transcurrido desde el último frame
};

View File

@@ -207,24 +207,21 @@ void Intro::switchText(int from_index, int to_index) {
}
// Actualiza las variables del objeto
void Intro::update() {
if (SDL_GetTicks() - ticks_ > param.game.speed) {
ticks_ = SDL_GetTicks(); // Actualiza el contador de ticks
Screen::get()->update(); // Actualiza el objeto screen
void Intro::update(float delta_time) {
Screen::get()->update(); // Actualiza el objeto screen
tiled_bg_->update(); // Actualiza el fondo
tiled_bg_->update(delta_time); // Actualiza el fondo
switch (state_) {
case State::SCENES:
updateSprites();
updateTexts();
updateScenes();
break;
switch (state_) {
case State::SCENES:
updateSprites(delta_time);
updateTexts(delta_time);
updateScenes();
break;
case State::POST:
updatePostState();
break;
}
case State::POST:
updatePostState();
break;
}
Audio::update();
@@ -253,12 +250,24 @@ void Intro::render() {
SCREEN->render(); // Vuelca el contenido del renderizador en pantalla
}
// Calcula el tiempo transcurrido desde el último frame
float Intro::calculateDeltaTime() {
const Uint64 current_time = SDL_GetTicks();
const float delta_time = static_cast<float>(current_time - last_time_);
last_time_ = current_time;
return delta_time;
}
// Bucle principal
void Intro::run() {
last_time_ = SDL_GetTicks();
Audio::get()->playMusic("intro.ogg", 0);
while (Section::name == Section::Name::INTRO) {
const float delta_time = calculateDeltaTime();
checkInput();
update();
update(delta_time);
checkEvents(); // Tiene que ir antes del render
render();
}
@@ -444,20 +453,20 @@ void Intro::initTexts() {
}
// Actualiza los sprites
void Intro::updateSprites() {
void Intro::updateSprites(float delta_time) {
for (auto &sprite : card_sprites_) {
sprite->update();
sprite->update(delta_time);
}
for (auto &sprite : shadow_sprites_) {
sprite->update();
sprite->update(delta_time);
}
}
// Actualiza los textos
void Intro::updateTexts() {
void Intro::updateTexts(float delta_time) {
for (auto &text : texts_) {
text->update();
text->update(delta_time);
}
}

View File

@@ -42,7 +42,7 @@ class Intro {
std::unique_ptr<TiledBG> tiled_bg_; // Fondo en mosaico
// --- Variables ---
Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
Uint64 last_time_ = 0; // Último timestamp para calcular delta-time
int scene_ = 0; // Indica qué escena está activa
State state_ = State::SCENES; // Estado principal de la intro
PostState post_state_ = PostState::STOP_BG; // Estado POST
@@ -50,19 +50,20 @@ class Intro {
Color bg_color_ = param.intro.bg_color; // Color de fondo
// --- Métodos internos ---
void update(); // Actualiza las variables del objeto
void update(float delta_time); // Actualiza las variables del objeto
void render(); // Dibuja el objeto en pantalla
static void checkInput(); // Comprueba las entradas
static void checkEvents(); // Comprueba los eventos
void updateScenes(); // Actualiza las escenas de la intro
void initSprites(); // Inicializa las imágenes
void initTexts(); // Inicializa los textos
void updateSprites(); // Actualiza los sprites
void updateTexts(); // Actualiza los textos
void updateSprites(float delta_time); // Actualiza los sprites
void updateTexts(float delta_time); // Actualiza los textos
void renderSprites(); // Dibuja los sprites
void renderTexts(); // Dibuja los textos
static void renderTextRect(); // Dibuja el rectangulo de fondo del texto;
void updatePostState(); // Actualiza el estado POST
float calculateDeltaTime(); // Calcula el tiempo transcurrido desde el último frame
// --- Métodos para manejar cada escena individualmente ---
void updateScene0();

View File

@@ -79,21 +79,23 @@ void Logo::checkInput() {
}
// Gestiona el logo de JAILGAMES
void Logo::updateJAILGAMES() {
void Logo::updateJAILGAMES(float delta_time) {
if (counter_ == 30) {
Audio::get()->playSound("logo.wav");
}
if (counter_ > 30) {
const float pixels_to_move = SPEED * delta_time;
for (int i = 0; i < (int)jail_sprite_.size(); ++i) {
if (jail_sprite_[i]->getX() != dest_.x) {
if (i % 2 == 0) {
jail_sprite_[i]->incX(-SPEED);
jail_sprite_[i]->incX(-pixels_to_move);
if (jail_sprite_[i]->getX() < dest_.x) {
jail_sprite_[i]->setX(dest_.x);
}
} else {
jail_sprite_[i]->incX(SPEED);
jail_sprite_[i]->incX(pixels_to_move);
if (jail_sprite_[i]->getX() > dest_.x) {
jail_sprite_[i]->setX(dest_.x);
}
@@ -129,16 +131,21 @@ void Logo::updateTextureColors() {
}
// Actualiza las variables
void Logo::update() {
if (SDL_GetTicks() - ticks_ > param.game.speed) {
ticks_ = SDL_GetTicks(); // Actualiza el contador de ticks
Screen::get()->update(); // Actualiza el objeto screen
void Logo::update(float delta_time) {
static float logic_accumulator = 0.0f;
logic_accumulator += delta_time;
updateJAILGAMES(); // Actualiza el logo de JAILGAMES
// Ejecutar lógica a 60 FPS (cada 16.67ms) para mantener consistencia en counter_ y colores
constexpr float LOGIC_FRAME_TIME = 1000.0f / 60.0f;
if (logic_accumulator >= LOGIC_FRAME_TIME) {
Screen::get()->update(); // Actualiza el objeto screen
updateTextureColors(); // Actualiza los colores de las texturas
++counter_; // Gestiona el contador
logic_accumulator -= LOGIC_FRAME_TIME;
}
updateJAILGAMES(delta_time); // Actualiza el logo de JAILGAMES con delta-time real
Audio::update();
}
@@ -154,11 +161,23 @@ void Logo::render() {
SCREEN->render();
}
// Calcula el tiempo transcurrido desde el último frame
float Logo::calculateDeltaTime() {
const Uint64 current_time = SDL_GetTicks();
const float delta_time = static_cast<float>(current_time - last_time_);
last_time_ = current_time;
return delta_time;
}
// Bucle para el logo del juego
void Logo::run() {
last_time_ = SDL_GetTicks();
while (Section::name == Section::Name::LOGO) {
const float delta_time = calculateDeltaTime();
checkInput();
update();
update(delta_time);
checkEvents(); // Tiene que ir antes del render
render();
}

View File

@@ -31,7 +31,7 @@ class Logo {
static constexpr int INIT_FADE_COUNTER_MARK = 300; // Tiempo del contador cuando inicia el fade a negro
static constexpr int END_LOGO_COUNTER_MARK = 400; // Tiempo del contador para terminar el logo
static constexpr int POST_LOGO_DURATION = 20; // Tiempo que dura el logo con el fade al máximo
static constexpr int SPEED = 8; // Velocidad de desplazamiento de cada línea
static constexpr float SPEED = 8.0f / 15.0f; // Velocidad de desplazamiento de cada línea (píxeles por ms)
// --- Objetos y punteros ---
std::shared_ptr<Texture> since_texture_; // Textura con los gráficos "Since 1998"
@@ -42,15 +42,16 @@ class Logo {
// --- Variables ---
std::vector<Color> color_; // Vector con los colores para el fade
int counter_ = 0; // Contador
Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
Uint64 last_time_ = 0; // Último timestamp para calcular delta-time
SDL_FPoint dest_; // Posición donde dibujar el logo
// --- Métodos internos ---
void update(); // Actualiza las variables
void update(float delta_time); // Actualiza las variables
void render(); // Dibuja en pantalla
static void checkEvents(); // Comprueba el manejador de eventos
static void checkInput(); // Comprueba las entradas
void updateJAILGAMES(); // Gestiona el logo de JAILGAMES
void updateJAILGAMES(float delta_time); // Gestiona el logo de JAILGAMES
void renderJAILGAMES(); // Renderiza el logo de JAILGAMES
void updateTextureColors(); // Gestiona el color de las texturas
float calculateDeltaTime(); // Calcula el tiempo transcurrido desde el último frame
};

View File

@@ -77,10 +77,10 @@ Title::~Title() {
Options::gamepad_manager.clearPlayers();
}
// Actualiza las variables del objeto
// Actualiza las variables del objeto (frame-based)
void Title::update() {
if (SDL_GetTicks() - ticks_ > param.game.speed) {
ticks_ = SDL_GetTicks();
if (SDL_GetTicks() - last_time_ > param.game.speed) {
last_time_ = SDL_GetTicks();
Screen::get()->update();
updateFade();
@@ -92,6 +92,28 @@ void Title::update() {
Audio::update();
}
// Actualiza las variables del objeto (time-based)
void Title::update(float deltaTime) {
Screen::get()->update();
updateFade();
updateState(deltaTime);
updateStartPrompt();
for (auto& player : players_) {
player->update(deltaTime); // deltaTime ya está en segundos
}
Audio::update();
}
// Calcula el tiempo transcurrido desde el último frame
float Title::calculateDeltaTime() {
const Uint64 current_time = SDL_GetTicks();
const float delta_time = static_cast<float>(current_time - last_time_);
last_time_ = current_time;
return delta_time;
}
// Dibuja el objeto en pantalla
void Title::render() {
static auto* const SCREEN = Screen::get();
@@ -136,7 +158,7 @@ void Title::handleDebugColorKeys(SDL_Keycode key) {
adjustColorComponent(key, color_);
counter_ = 0;
counter_time_ = 0.0f;
tiled_bg_->setColor(color_);
printColorValue(color_);
}
@@ -290,21 +312,25 @@ void Title::processPlayer2Start() {
void Title::activatePlayerAndSetState(Player::Id player_id) {
getPlayer(player_id)->setPlayingState(Player::State::TITLE_ANIMATION);
setState(TitleState::START_HAS_BEEN_PRESSED);
counter_ = 0;
counter_time_ = 0.0f;
}
// Bucle para el titulo del juego
void Title::run() {
last_time_ = SDL_GetTicks();
while (Section::name == Section::Name::TITLE) {
const float delta_time = calculateDeltaTime();
checkInput();
update();
update(delta_time);
checkEvents(); // Tiene que ir antes del render
render();
}
}
// Reinicia el contador interno
void Title::resetCounter() { counter_ = 0; }
void Title::resetCounter() { counter_time_ = 0.0f; }
// Intercambia la asignación de mandos a los jugadores
void Title::swapControllers() {
@@ -370,18 +396,55 @@ void Title::updateState() {
// Establece la lógica según el estado
switch (state_) {
case TitleState::LOGO_ANIMATING: {
game_logo_->update();
game_logo_->update(); // Mantener frame-based para consistencia del estado
if (game_logo_->hasFinished()) {
setState(TitleState::LOGO_FINISHED);
}
break;
}
case TitleState::LOGO_FINISHED: {
++counter_; // Incrementa el contador
game_logo_->update(); // Actualiza el logo con el título del juego
tiled_bg_->update(); // Actualiza el mosaico de fondo
// Ya no se usa counter_ aquí, se usa updateState(deltaTime)
game_logo_->update();
tiled_bg_->update();
if (counter_ == param.title.title_duration) {
// Esta lógica se movió a updateState(deltaTime)
break;
}
case TitleState::START_HAS_BEEN_PRESSED: {
// Ya no se usa counter_ aquí, se usa updateState(deltaTime)
game_logo_->update();
tiled_bg_->update();
// Esta lógica se movió a updateState(deltaTime)
break;
}
default:
break;
}
}
// Actualiza el estado (time-based)
void Title::updateState(float deltaTime) {
// deltaTime ya está en segundos desde calculateDeltaTime()
game_logo_->update(deltaTime);
tiled_bg_->update(deltaTime);
// Establece la lógica según el estado
switch (state_) {
case TitleState::LOGO_ANIMATING: {
if (game_logo_->hasFinished()) {
setState(TitleState::LOGO_FINISHED);
}
break;
}
case TitleState::LOGO_FINISHED: {
counter_time_ += deltaTime; // deltaTime está en milisegundos
// param.title.title_duration está en frames (60fps), convertir a ms: frames * (1000ms/60fps)
float duration_ms = static_cast<float>(param.title.title_duration) * (1000.0f / 60.0f);
if (counter_time_ >= duration_ms) {
// El menu ha hecho time out
fade_->setPostDuration(0);
fade_->activate();
@@ -390,11 +453,10 @@ void Title::updateState() {
break;
}
case TitleState::START_HAS_BEEN_PRESSED: {
++counter_; // Incrementa el contador
game_logo_->update(); // Actualiza el logo con el título del juego
tiled_bg_->update(); // Actualiza el mosaico de fondo
if (counter_ == 100) {
counter_time_ += deltaTime; // deltaTime está en milisegundos
// 100 frames a 60fps convertir a ms: 100 * (1000/60) = 1666.67 ms
if (counter_time_ >= (100.0f * 1000.0f / 60.0f)) {
fade_->activate();
}
break;
@@ -544,7 +606,7 @@ void Title::initPlayers() {
}
}
// Actualza los jugadores
// Actualiza los jugadores
void Title::updatePlayers() {
for (auto& player : players_) {
player->update();

View File

@@ -60,16 +60,19 @@ class Title {
Section::Name next_section_; // Siguiente sección a cargar
Section::Options selection_ = Section::Options::TITLE_TIME_OUT; // Opción elegida en el título
TitleState state_; // Estado actual de la sección
Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad
int counter_ = 0; // Temporizador para la pantalla de título
Uint64 last_time_ = 0; // Último timestamp para calcular delta-time
float counter_time_ = 0.0f; // Temporizador para la pantalla de título (en milisegundos)
int num_controllers_; // Número de mandos conectados
bool should_render_start_prompt_ = false; // Indica si se muestra el texto de PRESS START BUTTON TO PLAY
bool player1_start_pressed_ = false; // Indica si se ha pulsado el botón de empezar para el jugador 1
bool player2_start_pressed_ = false; // Indica si se ha pulsado el botón de empezar para el jugador 2
// --- Ciclo de vida del título ---
void update(); // Actualiza las variables del objeto
void updateState(); // Actualiza el estado actual del título
void update(); // Actualiza las variables del objeto (frame-based)
void update(float deltaTime); // Actualiza las variables del objeto (time-based)
float calculateDeltaTime(); // Calcula el tiempo transcurrido desde el último frame
void updateState(); // Actualiza el estado actual del título (frame-based)
void updateState(float deltaTime); // Actualiza el estado actual del título (time-based)
void setState(TitleState state); // Cambia el estado del título
void resetCounter(); // Reinicia el contador interno

View File

@@ -2,7 +2,7 @@
#include "moving_sprite.h" // Para MovingSprite
// Actualiza la posición y comprueba si ha llegado a su destino
// Actualiza la posición y comprueba si ha llegado a su destino (frame-based)
void SmartSprite::update() {
if (enabled_) {
MovingSprite::update();
@@ -11,6 +11,15 @@ void SmartSprite::update() {
}
}
// Actualiza la posición y comprueba si ha llegado a su destino (time-based)
void SmartSprite::update(float deltaTime) {
if (enabled_) {
MovingSprite::update(deltaTime);
checkMove();
checkFinished();
}
}
// Dibuja el sprite
void SmartSprite::render() {
if (enabled_) {

View File

@@ -16,8 +16,9 @@ class SmartSprite : public AnimatedSprite {
~SmartSprite() override = default;
// --- Métodos principales ---
void update() override; // Actualiza la posición y comprueba si ha llegado a su destino
void render() override; // Dibuja el sprite
void update() override; // Actualiza la posición y comprueba si ha llegado a su destino (frame-based)
void update(float deltaTime) override; // Actualiza la posición y comprueba si ha llegado a su destino (time-based)
void render() override; // Dibuja el sprite
// --- Getters ---
auto getDestX() const -> int { return dest_x_; } // Obtiene la posición de destino en X

View File

@@ -17,7 +17,7 @@ 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
// Actualiza la lógica (frame-based)
void Tabe::update() {
if (enabled_ && !timer_.is_paused) {
sprite_->update();
@@ -31,6 +31,20 @@ void Tabe::update() {
}
}
// Actualiza la lógica (time-based)
void Tabe::update(float deltaTime) {
if (enabled_ && !timer_.is_paused) {
sprite_->update(deltaTime);
move(deltaTime);
updateState(deltaTime);
}
timer_.update();
if (timer_.shouldSpawn()) {
enable();
}
}
// Dibuja el objeto
void Tabe::render() {
if (enabled_) {
@@ -38,7 +52,7 @@ void Tabe::render() {
}
}
// Mueve el objeto
// Mueve el objeto (frame-based)
void Tabe::move() {
const int X = static_cast<int>(x_);
speed_ += accel_;
@@ -103,6 +117,75 @@ void Tabe::move() {
shiftSprite();
}
// Mueve el objeto (time-based)
void Tabe::move(float deltaTime) {
// Convertir deltaTime (milisegundos) a factor de frame (asumiendo 60fps)
float frameFactor = deltaTime / (1000.0f / 60.0f);
const int X = static_cast<int>(x_);
speed_ += accel_ * frameFactor;
x_ += speed_ * frameFactor;
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_ -= frameFactor;
if (waiting_counter_ < 0) waiting_counter_ = 0;
} 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_) {
@@ -175,11 +258,23 @@ void Tabe::setState(State state) {
}
}
// Actualiza el estado
// Actualiza el estado (frame-based)
void Tabe::updateState() {
if (state_ == State::HIT) {
--hit_counter_;
if (hit_counter_ == 0) {
if (hit_counter_ <= 0) {
setState(State::FLY);
}
}
}
// Actualiza el estado (time-based)
void Tabe::updateState(float deltaTime) {
if (state_ == State::HIT) {
// Convertir deltaTime (milisegundos) a factor de frame (asumiendo 60fps)
float frameFactor = deltaTime / (1000.0f / 60.0f);
hit_counter_ -= frameFactor;
if (hit_counter_ <= 0) {
setState(State::FLY);
}
}

View File

@@ -26,8 +26,9 @@ class Tabe {
~Tabe() = default;
// --- Métodos principales ---
void update(); // Actualiza la lógica
void render(); // Dibuja el objeto
void update(); // Actualiza la lógica (frame-based)
void update(float deltaTime); // Actualiza la lógica (time-based)
void render(); // Dibuja el objeto
void enable(); // Habilita el objeto
void setState(State state); // Establece el estado
auto tryToGetBonus() -> bool; // Intenta obtener el bonus
@@ -130,21 +131,23 @@ class Tabe {
float speed_ = 0.0F; // Velocidad de movimiento
float accel_ = 0.0F; // Aceleración
int fly_distance_ = 0; // Distancia de vuelo
int waiting_counter_ = 0; // Tiempo que pasa quieto
float waiting_counter_ = 0; // Tiempo que pasa quieto
bool enabled_ = false; // Indica si el objeto está activo
Direction direction_ = Direction::TO_THE_LEFT; // Dirección actual
Direction destiny_ = Direction::TO_THE_LEFT; // Destino
State state_ = State::FLY; // Estado actual
int hit_counter_ = 0; // Contador para el estado HIT
float hit_counter_ = 0; // Contador para el estado HIT
int number_of_hits_ = 0; // Cantidad de disparos recibidos
bool has_bonus_ = true; // Indica si aún tiene el bonus para soltar
Timer timer_; // Temporizador para gestionar la aparición
// --- Métodos internos ---
void move(); // Mueve el objeto
void move(); // Mueve el objeto (frame-based)
void move(float deltaTime); // Mueve el objeto (time-based)
void shiftSprite() { sprite_->setPos(x_, y_); } // Actualiza la posición del sprite
void setRandomFlyPath(Direction direction, int length); // Establece un vuelo aleatorio
void updateState(); // Actualiza el estado
void updateState(); // Actualiza el estado (frame-based)
void updateState(float deltaTime); // Actualiza el estado (time-based)
void updateTimer(); // Actualiza el temporizador
void disable(); // Deshabilita el objeto
};

View File

@@ -3,7 +3,7 @@
#include <SDL3/SDL.h> // Para SDL_SetRenderTarget, SDL_CreateTexture, SDL_DestroyTexture, SDL_FRect, SDL_GetRenderTarget, SDL_RenderTexture, SDL_PixelFormat, SDL_TextureAccess
#include <algorithm>
#include <cmath> // Para sin
#include <cmath> // Para sin, pow
#include <cstdlib> // Para rand
#include <memory> // Para allocator, unique_ptr, make_unique
#include <numbers> // Para pi
@@ -81,7 +81,7 @@ void TiledBG::render() {
SDL_RenderTexture(renderer_, canvas_, &window_, &pos_);
}
// Actualiza la lógica de la clase
// Actualiza la lógica de la clase (frame-based)
void TiledBG::update() {
updateDesp();
updateStop();
@@ -107,7 +107,33 @@ void TiledBG::update() {
}
}
// Detiene el desplazamiento de forma ordenada
// Actualiza la lógica de la clase (time-based)
void TiledBG::update(float delta_time) {
updateDesp(delta_time);
updateStop(delta_time);
switch (mode_) {
case TiledBGMode::DIAGONAL: {
// El tileado de fondo se desplaza en diagonal
window_.x = static_cast<int>(desp_) % TILE_WIDTH;
window_.y = static_cast<int>(desp_) % TILE_HEIGHT;
break;
}
case TiledBGMode::CIRCLE: {
// El tileado de fondo se desplaza en circulo
const int INDEX = static_cast<int>(desp_) % 360;
window_.x = 128 + (static_cast<int>(sin_[(INDEX + 270) % 360] * 128));
window_.y = 128 + (static_cast<int>(sin_[(360 - INDEX) % 360] * 96));
break;
}
default:
break;
}
}
// Detiene el desplazamiento de forma ordenada (frame-based)
void TiledBG::updateStop() {
if (stopping_) {
const int UMBRAL = 20 * speed_; // Ajusta este valor según la precisión deseada
@@ -120,6 +146,29 @@ void TiledBG::updateStop() {
speed_ = std::max(speed_, 0.1F);
}
// Si estamos en 0, detener
if (window_.x == 0) {
speed_ = 0.0F;
stopping_ = false; // Desactivamos el estado de "stopping"
}
}
}
// Detiene el desplazamiento de forma ordenada (time-based)
void TiledBG::updateStop(float delta_time) {
if (stopping_) {
const int UMBRAL = 20 * speed_; // Ajusta este valor según la precisión deseada
// Desacelerar si estamos cerca de completar el ciclo (ventana a punto de regresar a 0)
if (window_.x >= TILE_WIDTH - UMBRAL) {
// Convertir 1.05F por frame a por milisegundo: (1.05^(60*delta_time/1000))
float deceleration_factor = std::pow(1.05F, 60.0F * delta_time / 1000.0F);
speed_ /= deceleration_factor;
// Asegura que no baje demasiado
speed_ = std::max(speed_, 0.1F);
}
// Si estamos en 0, detener
if (window_.x == 0) {
speed_ = 0.0F;

View File

@@ -24,8 +24,9 @@ class TiledBG {
~TiledBG();
// --- Métodos principales ---
void render(); // Pinta la clase en pantalla
void update(); // Actualiza la lógica de la clase
void render(); // Pinta la clase en pantalla
void update(); // Actualiza la lógica de la clase (compatibilidad)
void update(float delta_time); // Actualiza la lógica de la clase
// --- Configuración ---
void setSpeed(float speed) { speed_ = speed; } // Establece la velocidad
@@ -54,7 +55,9 @@ class TiledBG {
bool stopping_ = false; // Indica si se está deteniendo
// --- Métodos internos ---
void fillTexture(); // Rellena la textura con el contenido
void updateDesp() { desp_ += speed_; } // Actualiza el desplazamiento
void updateStop(); // Detiene el desplazamiento de forma ordenada
void fillTexture(); // Rellena la textura con el contenido
void updateDesp() { desp_ += speed_; } // Actualiza el desplazamiento (frame-based)
void updateDesp(float delta_time) { desp_ += speed_ * delta_time / (1000.0f / 60.0f); } // Actualiza el desplazamiento (time-based)
void updateStop(); // Detiene el desplazamiento de forma ordenada (frame-based)
void updateStop(float delta_time); // Detiene el desplazamiento de forma ordenada (time-based)
};

View File

@@ -3,15 +3,14 @@
#include "text.h" // Para Text
// Actualiza el objeto
void Writer::update() {
void Writer::update(float delta_time) {
if (enabled_) {
if (!completed_) {
// No completado
if (writing_counter_ > 0) {
writing_counter_--;
} else {
writing_timer_ += delta_time;
if (writing_timer_ >= speed_ms_) {
index_++;
writing_counter_ = speed_;
writing_timer_ = 0.0f;
}
if (index_ == length_) {
@@ -19,10 +18,8 @@ void Writer::update() {
}
} else {
// Completado
finished_ = enabled_counter_ <= 0;
if (!finished_) {
enabled_counter_--;
}
enabled_timer_ += delta_time;
finished_ = enabled_timer_ >= enabled_timer_target_;
}
}
}
@@ -57,8 +54,10 @@ void Writer::setCaption(const std::string &text) {
// Establece el valor de la variable
void Writer::setSpeed(int value) {
speed_ = value;
writing_counter_ = value;
// Convierte frames a milisegundos (frames * 16.67ms)
constexpr float FRAME_TIME_MS = 1000.0f / 60.0f;
speed_ms_ = static_cast<float>(value) * FRAME_TIME_MS;
writing_timer_ = 0.0f;
}
// Establece el valor de la variable
@@ -73,7 +72,10 @@ auto Writer::isEnabled() const -> bool {
// Establece el valor de la variable
void Writer::setFinishedCounter(int time) {
enabled_counter_ = time;
// Convierte frames a milisegundos (frames * 16.67ms)
constexpr float FRAME_TIME_MS = 1000.0f / 60.0f;
enabled_timer_target_ = static_cast<float>(time) * FRAME_TIME_MS;
enabled_timer_ = 0.0f;
}
// Centra la cadena de texto a un punto X

View File

@@ -15,7 +15,7 @@ class Writer {
~Writer() = default;
// --- Métodos principales ---
void update(); // Actualiza el objeto
void update(float delta_time); // Actualiza el objeto
void render() const; // Dibuja el objeto en pantalla
// --- Setters ---
@@ -38,16 +38,17 @@ class Writer {
std::shared_ptr<Text> text_; // Objeto encargado de escribir el texto
// --- Variables de estado ---
std::string caption_; // El texto para escribir
int pos_x_ = 0; // Posición en el eje X donde empezar a escribir el texto
int pos_y_ = 0; // Posición en el eje Y donde empezar a escribir el texto
int kerning_ = 0; // Kerning del texto, es decir, espaciado entre caracteres
int speed_ = 0; // Velocidad de escritura
int writing_counter_ = 0; // Temporizador de escritura para cada caracter
int index_ = 0; // Posición del texto que se está escribiendo
int length_ = 0; // Longitud de la cadena a escribir
int enabled_counter_ = 0; // Temporizador para deshabilitar el objeto
bool completed_ = false; // Indica si se ha escrito todo el texto
bool enabled_ = false; // Indica si el objeto está habilitado
bool finished_ = false; // Indica si ya ha terminado
std::string caption_; // El texto para escribir
int pos_x_ = 0; // Posición en el eje X donde empezar a escribir el texto
int pos_y_ = 0; // Posición en el eje Y donde empezar a escribir el texto
int kerning_ = 0; // Kerning del texto, es decir, espaciado entre caracteres
float speed_ms_ = 0.0f; // Velocidad de escritura en milisegundos
float writing_timer_ = 0.0f; // Temporizador de escritura para cada caracter
int index_ = 0; // Posición del texto que se está escribiendo
int length_ = 0; // Longitud de la cadena a escribir
float enabled_timer_ = 0.0f; // Temporizador para deshabilitar el objeto
float enabled_timer_target_ = 0.0f; // Tiempo objetivo para deshabilitar el objeto
bool completed_ = false; // Indica si se ha escrito todo el texto
bool enabled_ = false; // Indica si el objeto está habilitado
bool finished_ = false; // Indica si ya ha terminado
};