From 91c5b9d2b243e0874695610fa191f34314915f82 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Tue, 19 May 2026 17:17:56 +0200 Subject: [PATCH] time-based: Balloon amb dual-API update/move/state/animation/bounce(dt_s), vels/gravetat en px/s i px/s2 --- source/game/entities/balloon.cpp | 286 ++++++++++++++++++++++++++----- source/game/entities/balloon.h | 98 +++++++---- 2 files changed, 300 insertions(+), 84 deletions(-) diff --git a/source/game/entities/balloon.cpp b/source/game/entities/balloon.cpp index 364fd95..99b3453 100644 --- a/source/game/entities/balloon.cpp +++ b/source/game/entities/balloon.cpp @@ -1,6 +1,7 @@ #include "game/entities/balloon.h" -#include // for std::fabs +#include // for std::max +#include // for std::fabs #include "core/rendering/animatedsprite.h" // for AnimatedSprite #include "core/rendering/movingsprite.h" // for MovingSprite @@ -23,13 +24,20 @@ Balloon::Balloon(float x, float y, Uint8 kind, float velx, float speed, Uint16 c size_ = SIZE_1; power_ = 1; - // Inicializa los valores de velocidad y gravedad + // Inicializa los valores de velocidad y gravedad (frame-based) this->vel_x_ = velx; vel_y_ = 0; max_vel_y_ = 3.0F; gravity_ = 0.09F; default_vel_y_ = 2.6F; + // Time-based equivalents (x60 per vel, x3600 per gravetat) + vel_x_s_ = velx * 60.0F; + vel_y_s_ = 0.0F; + max_vel_y_s_ = 180.0F; + gravity_s_ = 324.0F; + default_vel_y_s_ = 156.0F; + // Puntos que da el globo al ser destruido score_ = SCORE_1; @@ -39,173 +47,177 @@ Balloon::Balloon(float x, float y, Uint8 kind, float velx, float speed, Uint16 c break; case BALLOON_2: - // Alto y ancho del objeto width_ = WIDTH_2; height_ = WIDTH_2; size_ = SIZE_2; power_ = 3; - // Inicializa los valores de velocidad y gravedad this->vel_x_ = velx; vel_y_ = 0; max_vel_y_ = 3.0F; gravity_ = 0.10F; default_vel_y_ = 3.5F; - // Puntos que da el globo al ser destruido + vel_x_s_ = velx * 60.0F; + vel_y_s_ = 0.0F; + max_vel_y_s_ = 180.0F; + gravity_s_ = 360.0F; + default_vel_y_s_ = 210.0F; + score_ = SCORE_2; - - // Amenaza que genera el globo menace_ = 2; - break; case BALLOON_3: - // Alto y ancho del objeto width_ = WIDTH_3; height_ = WIDTH_3; size_ = SIZE_3; power_ = 7; - // Inicializa los valores de velocidad y gravedad this->vel_x_ = velx; vel_y_ = 0; max_vel_y_ = 3.0F; gravity_ = 0.10F; default_vel_y_ = 4.50F; - // Puntos que da el globo al ser destruido + vel_x_s_ = velx * 60.0F; + vel_y_s_ = 0.0F; + max_vel_y_s_ = 180.0F; + gravity_s_ = 360.0F; + default_vel_y_s_ = 270.0F; + score_ = SCORE_3; - - // Amenaza que genera el globo menace_ = 4; - break; case BALLOON_4: - // Alto y ancho del objeto width_ = WIDTH_4; height_ = WIDTH_4; size_ = SIZE_4; power_ = 15; - // Inicializa los valores de velocidad y gravedad this->vel_x_ = velx; vel_y_ = 0; max_vel_y_ = 3.0F; gravity_ = 0.10F; default_vel_y_ = 4.95F; - // Puntos que da el globo al ser destruido + vel_x_s_ = velx * 60.0F; + vel_y_s_ = 0.0F; + max_vel_y_s_ = 180.0F; + gravity_s_ = 360.0F; + default_vel_y_s_ = 297.0F; + score_ = SCORE_4; - - // Amenaza que genera el globo menace_ = 8; - break; case HEXAGON_1: - // Alto y ancho del objeto width_ = WIDTH_1; height_ = WIDTH_1; size_ = SIZE_1; power_ = 1; - // Inicializa los valores de velocidad y gravedad this->vel_x_ = velx; vel_y_ = std::fabs(velx) * 2; max_vel_y_ = std::fabs(velx) * 2; gravity_ = 0.00F; default_vel_y_ = std::fabs(velx) * 2; - // Puntos que da el globo al ser destruido + vel_x_s_ = velx * 60.0F; + vel_y_s_ = std::fabs(velx) * 2.0F * 60.0F; + max_vel_y_s_ = std::fabs(velx) * 2.0F * 60.0F; + gravity_s_ = 0.0F; + default_vel_y_s_ = std::fabs(velx) * 2.0F * 60.0F; + score_ = SCORE_1; - - // Amenaza que genera el globo menace_ = 1; - break; case HEXAGON_2: - // Alto y ancho del objeto width_ = WIDTH_2; height_ = WIDTH_2; size_ = SIZE_2; power_ = 3; - // Inicializa los valores de velocidad y gravedad this->vel_x_ = velx; vel_y_ = std::fabs(velx) * 2; max_vel_y_ = std::fabs(velx) * 2; gravity_ = 0.00F; default_vel_y_ = std::fabs(velx) * 2; - // Puntos que da el globo al ser destruido + vel_x_s_ = velx * 60.0F; + vel_y_s_ = std::fabs(velx) * 2.0F * 60.0F; + max_vel_y_s_ = std::fabs(velx) * 2.0F * 60.0F; + gravity_s_ = 0.0F; + default_vel_y_s_ = std::fabs(velx) * 2.0F * 60.0F; + score_ = SCORE_2; - - // Amenaza que genera el globo menace_ = 2; - break; case HEXAGON_3: - // Alto y ancho del objeto width_ = WIDTH_3; height_ = WIDTH_3; size_ = SIZE_3; power_ = 7; - // Inicializa los valores de velocidad y gravedad this->vel_x_ = velx; vel_y_ = std::fabs(velx) * 2; max_vel_y_ = std::fabs(velx) * 2; gravity_ = 0.00F; default_vel_y_ = std::fabs(velx) * 2; - // Puntos que da el globo al ser destruido + vel_x_s_ = velx * 60.0F; + vel_y_s_ = std::fabs(velx) * 2.0F * 60.0F; + max_vel_y_s_ = std::fabs(velx) * 2.0F * 60.0F; + gravity_s_ = 0.0F; + default_vel_y_s_ = std::fabs(velx) * 2.0F * 60.0F; + score_ = SCORE_3; - - // Amenaza que genera el globo menace_ = 4; - break; case HEXAGON_4: - // Alto y ancho del objeto width_ = WIDTH_4; height_ = WIDTH_4; size_ = SIZE_4; power_ = 15; - // Inicializa los valores de velocidad y gravedad this->vel_x_ = velx; vel_y_ = std::fabs(velx) * 2; max_vel_y_ = std::fabs(velx) * 2; gravity_ = 0.00F; default_vel_y_ = std::fabs(velx) * 2; - // Puntos que da el globo al ser destruido + vel_x_s_ = velx * 60.0F; + vel_y_s_ = std::fabs(velx) * 2.0F * 60.0F; + max_vel_y_s_ = std::fabs(velx) * 2.0F * 60.0F; + gravity_s_ = 0.0F; + default_vel_y_s_ = std::fabs(velx) * 2.0F * 60.0F; + score_ = SCORE_4; - - // Amenaza que genera el globo menace_ = 8; - break; case POWER_BALL: - // Alto y ancho del objeto width_ = WIDTH_4; height_ = WIDTH_4; size_ = 4; power_ = 0; - // Inicializa los valores de velocidad y gravedad this->vel_x_ = velx; vel_y_ = 0; max_vel_y_ = 3.0F; gravity_ = 0.10F; default_vel_y_ = 4.95F; + vel_x_s_ = velx * 60.0F; + vel_y_s_ = 0.0F; + max_vel_y_s_ = 180.0F; + gravity_s_ = 360.0F; + default_vel_y_s_ = 297.0F; + // Puntos que da el globo al ser destruido score_ = 0; @@ -257,10 +269,15 @@ Balloon::Balloon(float x, float y, Uint8 kind, float velx, float speed, Uint16 c // Inicializa variables stopped_ = true; stopped_counter_ = 0; + stopped_counter_s_ = 0.0F; blinking_ = false; visible_ = true; creation_counter_ = creationtimer; creation_counter_ini_ = creationtimer; + creation_counter_s_ = static_cast(creationtimer) / 60.0F; + creation_counter_ini_s_ = creation_counter_s_; + creation_phase_s_ = 0.0F; + bounce_phase_s_ = 0.0F; popping_ = false; // Valores iniciales dependentes del timer @@ -420,6 +437,49 @@ void Balloon::move() { } } +// Actualiza la posición y estados del globo (time-based). +// Reemplaça l'acumulador `travel_y_` per integració contínua: gravetat i +// posició s'apliquen escalades per `speed_` (tempo del joc) cada tick, +// equivalent en mitjana a l'original però sense l'efecte chunky. +void Balloon::move(float dt_s) { + if (!isStopped()) { + // Eix X + pos_x_ += vel_x_s_ * speed_ * dt_s; + + if ((pos_x_ < PLAY_AREA_LEFT) || (pos_x_ + width_ > PLAY_AREA_RIGHT)) { + pos_x_ -= vel_x_s_ * speed_ * dt_s; + vel_x_s_ = -vel_x_s_; + vel_x_ = -vel_x_; // mantenir frame-based sincronitzat (UB-free per a sprite->switchRotate) + sprite_->switchRotate(); + if (kind_ != POWER_BALL) { bounceStart(); } + } + + // Eix Y + pos_y_ += vel_y_s_ * speed_ * dt_s; + + if (pos_y_ < PLAY_AREA_TOP) { + pos_y_ = PLAY_AREA_TOP; + vel_y_s_ = -vel_y_s_; + vel_y_ = -vel_y_; + if (kind_ != POWER_BALL) { bounceStart(); } + } + + if (pos_y_ + height_ > PLAY_AREA_BOTTOM) { + pos_y_ = PLAY_AREA_BOTTOM - height_; + vel_y_s_ = -default_vel_y_s_; + vel_y_ = -default_vel_y_; + if (kind_ != POWER_BALL) { bounceStart(); } + } + + // Gravetat contínua (el tempo `speed_` escala també la gravetat per + // mantenir el mateix patró de rebot que la versió frame-based). + vel_y_s_ += gravity_s_ * speed_ * dt_s; + + sprite_->setPosX(getPosX()); + sprite_->setPosY(getPosY()); + } +} + // Deshabilita el globo y pone a cero todos los valores void Balloon::disable() { being_created_ = false; @@ -430,13 +490,20 @@ void Balloon::disable() { counter_ = 0; creation_counter_ = 0; creation_counter_ini_ = 0; + creation_counter_s_ = 0.0F; + creation_counter_ini_s_ = 0.0F; + creation_phase_s_ = 0.0F; + bounce_phase_s_ = 0.0F; default_vel_y_ = 0.0F; + default_vel_y_s_ = 0.0F; enabled_ = false; gravity_ = 0.0F; + gravity_s_ = 0.0F; height_ = 0; invulnerable_ = false; kind_ = 0; max_vel_y_ = 0.0F; + max_vel_y_s_ = 0.0F; menace_ = 0; popping_ = false; pos_x_ = 0.0F; @@ -447,9 +514,12 @@ void Balloon::disable() { speed_ = 0; stopped_ = false; stopped_counter_ = 0; + stopped_counter_s_ = 0.0F; travel_y_ = 0; vel_x_ = 0.0F; vel_y_ = 0.0F; + vel_x_s_ = 0.0F; + vel_y_s_ = 0.0F; visible_ = false; width_ = 0; sprite_->clear(); @@ -478,6 +548,20 @@ void Balloon::update() { } } +// Actualiza al globo (time-based) +void Balloon::update(float dt_s) { + if (enabled_) { + // MovingSprite::update(dt_s) avança la rotació (entre altres). La posició + // del sprite la posa move(dt_s) directament des de pos_x_/pos_y_. + sprite_->MovingSprite::update(dt_s); + move(dt_s); + updateAnimation(dt_s); + updateColliders(); + updateState(dt_s); + updateBounce(dt_s); + } +} + // Actualiza los estados del globo void Balloon::updateState() { if (isPopping()) { @@ -493,6 +577,19 @@ void Balloon::updateState() { } } +// Actualiza los estados del globo (time-based) +void Balloon::updateState(float dt_s) { + if (isPopping()) { + updateStatePopping(); + } + + if (isBeingCreated()) { + updateStateBeingCreated(dt_s); + } else if (isStopped()) { + updateStateStopped(dt_s); + } +} + // Rama de updateState: globo explotando void Balloon::updateStatePopping() { setInvulnerable(true); @@ -540,6 +637,40 @@ void Balloon::updateStateBeingCreated() { } } +// Rama de updateState: globo creándose (time-based). Manté el chunk pattern +// original: cada CREATION_STEP_S s'aplica un step de drift. +void Balloon::updateStateBeingCreated(float dt_s) { + setStop(true); + setInvulnerable(true); + + if (creation_counter_s_ > 0.0F) { + creation_phase_s_ += dt_s; + while (creation_phase_s_ >= CREATION_STEP_S) { + creation_phase_s_ -= CREATION_STEP_S; + pos_y_ += 1.0F; + pos_x_ += vel_x_; // drift idèntic a l'original (vel_x_ en px/frame) + + if ((pos_x_ < PLAY_AREA_LEFT) || (pos_x_ > (PLAY_AREA_RIGHT - width_))) { + pos_x_ -= vel_x_; + vel_x_ = -vel_x_; + vel_x_s_ = -vel_x_s_; + } + + sprite_->setPosX(getPosX()); + sprite_->setPosY(getPosY()); + updateColliders(); + } + + creation_counter_s_ = std::max(0.0F, creation_counter_s_ - dt_s); + creation_counter_ = static_cast(creation_counter_s_ * 60.0F); + } else { + setBeingCreated(false); + setStop(false); + setVisible(true); + setInvulnerable(false); + } +} + // Rama de updateState: globo detenido (no creándose) void Balloon::updateStateStopped() { // Reduce el contador @@ -552,6 +683,16 @@ void Balloon::updateStateStopped() { } } +// Rama de updateState: globo detenido (time-based) +void Balloon::updateStateStopped(float dt_s) { + if (stopped_counter_s_ > 0.0F) { + stopped_counter_s_ = std::max(0.0F, stopped_counter_s_ - dt_s); + stopped_counter_ = static_cast(stopped_counter_s_ * 60.0F); + } else if (!isPopping()) { + setStop(false); + } +} + // Establece la animación correspondiente al estado void Balloon::updateAnimation() { std::string creating_animation = "blue"; @@ -577,6 +718,30 @@ void Balloon::updateAnimation() { sprite_->animate(); } +// Establece la animación correspondiente (time-based) +void Balloon::updateAnimation(float dt_s) { + std::string creating_animation = "blue"; + std::string normal_animation = "orange"; + + if (kind_ == POWER_BALL) { + creating_animation = "powerball"; + normal_animation = "powerball"; + } else if (getClass() == HEXAGON_CLASS) { + creating_animation = "red"; + normal_animation = "green"; + } + + if (isPopping()) { + sprite_->setCurrentAnimation("pop"); + } else if (isBeingCreated()) { + sprite_->setCurrentAnimation(creating_animation); + } else { + sprite_->setCurrentAnimation(normal_animation); + } + + sprite_->animate(dt_s); +} + // Comprueba si el globo está habilitado auto Balloon::isEnabled() const -> bool { return enabled_; @@ -610,6 +775,7 @@ auto Balloon::getHeight() const -> int { // Establece el valor de la variable void Balloon::setVelY(float vel_y) { this->vel_y_ = vel_y; + this->vel_y_s_ = vel_y * 60.0F; } // Establece el valor de la variable @@ -709,6 +875,7 @@ auto Balloon::isPopping() const -> bool { // Establece el valor de la variable void Balloon::setStoppedTimer(Uint16 time) { stopped_counter_ = time; + stopped_counter_s_ = static_cast(time) / 60.0F; } // Obtiene del valor de la variable @@ -779,4 +946,31 @@ void Balloon::updateBounce() { bounceStop(); } } +} + +// Aplica l'efecte de rebote (time-based). Manté la mateixa cadència: cada +// `bouncing_.speed` "frames" (a 60Hz) avança un slot del vector w/h. +void Balloon::updateBounce(float dt_s) { + if (!bouncing_.enabled) { return; } + + bounce_phase_s_ += dt_s; + const float STEP_S = static_cast(bouncing_.speed) * BOUNCE_STEP_S; + while (bounce_phase_s_ >= STEP_S) { + bounce_phase_s_ -= STEP_S; + bouncing_.counter++; + } + + const int IDX = bouncing_.counter / bouncing_.speed; + if (IDX > (MAX_BOUNCE - 1)) { + bounceStop(); + bounce_phase_s_ = 0.0F; + return; + } + + bouncing_.zoom_width = bouncing_.w[IDX]; + bouncing_.zoom_height = bouncing_.h[IDX]; + sprite_->setZoomW(bouncing_.zoom_width); + sprite_->setZoomH(bouncing_.zoom_height); + bouncing_.desp_x = (sprite_->getSpriteClip().w - (sprite_->getSpriteClip().w * bouncing_.zoom_width)); + bouncing_.desp_y = (sprite_->getSpriteClip().h - (sprite_->getSpriteClip().h * bouncing_.zoom_height)); } \ No newline at end of file diff --git a/source/game/entities/balloon.h b/source/game/entities/balloon.h index 6a1e658..e3782fc 100644 --- a/source/game/entities/balloon.h +++ b/source/game/entities/balloon.h @@ -66,12 +66,14 @@ class Balloon { Balloon(const Balloon &) = delete; auto operator=(const Balloon &) -> Balloon & = delete; - void allignTo(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 disable(); // Deshabilita el globo y pone a cero todos los valores - void pop(); // Explosiona el globo - void update(); // Actualiza al globo a su posicion, animación y controla los contadores + void allignTo(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 dt_s); // Actualiza la posición y estados del globo (time-based) + void disable(); // Deshabilita el globo y pone a cero todos los valores + void pop(); // Explosiona el globo + void update(); // Actualiza al globo (frame-based) + void update(float dt_s); // Actualiza al globo (time-based) [[nodiscard]] auto isEnabled() const -> bool; // Comprueba si el globo está habilitado [[nodiscard]] auto isStopped() const -> bool; // Obtiene del valor de la variable @@ -109,6 +111,11 @@ class Balloon { // Cantidad de elementos del vector con los valores de la deformación del globo al rebotar static constexpr int MAX_BOUNCE = 10; + // Time-based: la creació "desplaça" el globus cada 10 frames a 60Hz ⇒ 1/6 s. + static constexpr float CREATION_STEP_S = 10.0F / 60.0F; + // Time-based: el bounce avança w/h cada `speed_` frames a 60Hz; mantenim el mateix temps per pas. + static constexpr float BOUNCE_STEP_S = 1.0F / 60.0F; // 1 frame + // Estructura para las variables para el efecto de los rebotes struct Bouncing { bool enabled; // Si el efecto está activo @@ -126,47 +133,62 @@ class Balloon { AnimatedSprite *sprite_; // Sprite del objeto globo // Variables - float pos_x_; // Posición en el eje X - float pos_y_; // Posición en el eje Y - Uint8 width_; // Ancho - Uint8 height_; // Alto - float vel_x_; // Velocidad en el eje X. Cantidad de pixeles a desplazarse - float vel_y_; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse - float gravity_; // Aceleración en el eje Y. Modifica la velocidad - float default_vel_y_; // Velocidad inicial que tienen al rebotar contra el suelo - float max_vel_y_; // Máxima velocidad que puede alcanzar el objeto en el eje Y - bool being_created_; // Indica si el globo se está creando - bool blinking_; // Indica si el globo está intermitente - bool enabled_; // Indica si el globo esta activo - bool invulnerable_; // Indica si el globo es invulnerable - bool popping_; // Indica si el globo está explotando - bool stopped_; // Indica si el globo está parado - bool visible_; // Indica si el globo es visible - Circle collider_; // Circulo de colisión del objeto - Uint16 creation_counter_; // Temporizador para controlar el estado "creandose" - Uint16 creation_counter_ini_; // Valor inicial para el temporizador para controlar el estado "creandose" - Uint16 score_; // Puntos que da el globo al ser destruido - Uint16 stopped_counter_; // Contador para controlar el estado "parado" - Uint8 kind_; // Tipo de globo - Uint8 menace_; // Cantidad de amenaza que genera el globo - Uint32 counter_; // Contador interno - float travel_y_; // Distancia que ha de recorrer el globo en el eje Y antes de que se le aplique la gravedad - float speed_; // Velocidad a la que se mueven los globos - Uint8 size_; // Tamaño del globo - Uint8 power_; // Cantidad de poder que alberga el globo - Bouncing bouncing_; // Contiene las variables para el efecto de rebote + float pos_x_; // Posición en el eje X + float pos_y_; // Posición en el eje Y + Uint8 width_; // Ancho + Uint8 height_; // Alto + float vel_x_; // Velocidad en X (frame-based: px/frame) + float vel_y_; // Velocidad en Y (frame-based: px/frame) + float gravity_; // Aceleración Y (frame-based: px/frame²) + float default_vel_y_; // Velocitat inicial al rebotar contra el terra (frame-based) + float max_vel_y_; // Velocitat màxima en Y (frame-based) + float vel_x_s_{0.0F}; // Velocidad en X (time-based: px/s) + float vel_y_s_{0.0F}; // Velocidad en Y (time-based: px/s) + float gravity_s_{0.0F}; // Aceleración Y (time-based: px/s²) + float default_vel_y_s_{0.0F}; // Velocitat inicial al rebotar (time-based) + float max_vel_y_s_{0.0F}; // Velocitat màxima en Y (time-based) + bool being_created_; // Indica si el globo se está creando + bool blinking_; // Indica si el globo está intermitente + bool enabled_; // Indica si el globo esta activo + bool invulnerable_; // Indica si el globo es invulnerable + bool popping_; // Indica si el globo está explotando + bool stopped_; // Indica si el globo está parado + bool visible_; // Indica si el globo es visible + Circle collider_; // Circulo de colisión del objeto + Uint16 creation_counter_; // Temporizador (frame-based) + Uint16 creation_counter_ini_; // Valor inicial del temporizador (frames) + float creation_counter_s_{0.0F}; // Temporizador (time-based) + float creation_counter_ini_s_{0.0F}; // Valor inicial del temporizador (segons) + float creation_phase_s_{0.0F}; // Acumulador de fase per als steps de creació (time-based) + Uint16 score_; // Puntos que da el globo al ser destruido + Uint16 stopped_counter_; // Contador (frame-based) + float stopped_counter_s_{0.0F}; // Contador (time-based) + Uint8 kind_; // Tipo de globo + Uint8 menace_; // Cantidad de amenaza que genera el globo + Uint32 counter_; // Contador interno (legacy, no usat per cap lector) + float travel_y_; // Acumulador per a aplicar la gravetat (frame-based) + float speed_; // Tempo del joc (multiplicador adimensional, frame i time-based) + Uint8 size_; // Tamaño del globo + Uint8 power_; // Cantidad de poder que alberga el globo + Bouncing bouncing_; // Contiene las variables para el efecto de rebote + float bounce_phase_s_{0.0F}; // Fase del bounce (time-based) void updateColliders(); // Alinea el circulo de colisión con la posición del objeto globo void bounceStart(); // Activa el efecto void bounceStop(); // Detiene el efecto - void updateBounce(); // Aplica el efecto - void updateAnimation(); // Establece la animación correspondiente + void updateBounce(); // Aplica el efecto (frame-based) + void updateBounce(float dt_s); // Aplica el efecto (time-based) + void updateAnimation(); // Establece la animación correspondiente (frame-based) + void updateAnimation(float dt_s); // Establece la animación correspondiente (time-based) void setBeingCreated(bool value); // Establece el valor de la variable - void updateState(); // Actualiza los estados del globo + void updateState(); // Actualiza los estados del globo (frame-based) + void updateState(float dt_s); // Actualiza los estados del globo (time-based) // Helpers de updateState, uno por cada rama de estado void updateStatePopping(); void updateStateBeingCreated(); + void updateStateBeingCreated(float dt_s); void updateStateStopped(); + void updateStateStopped(float dt_s); };