#include "card_sprite.hpp" #include // Para std::clamp #include // Para function #include // Para move #include "texture.hpp" // Para Texture #include "utils.hpp" // Para easeOutBounce // Constructor CardSprite::CardSprite(std::shared_ptr texture) : MovingSprite(std::move(texture)), entry_easing_(easeOutBounce) {} // Inicia la animación de entrada (solo si está en IDLE) void CardSprite::enable() { if (state_ != CardState::IDLE) { return; } state_ = CardState::ENTERING; entry_elapsed_ = 0.0F; // Posición fija en el punto de aterrizaje setPos(landing_x_, landing_y_); // Zoom inicial grande (como si estuviera cerca de la cámara) horizontal_zoom_ = start_zoom_; vertical_zoom_ = start_zoom_; // Ángulo inicial rotate_.angle = start_angle_; rotate_.center = {pos_.w / 2.0F, pos_.h / 2.0F}; shadow_visible_ = true; } // Inicia la animación de salida (solo si está en LANDED) void CardSprite::startExit() { if (state_ != CardState::LANDED) { return; } state_ = CardState::EXITING; shadow_visible_ = false; // Velocidad y aceleración de salida vx_ = exit_vx_; vy_ = exit_vy_; ax_ = exit_ax_; ay_ = exit_ay_; // Rotación continua rotate_.enabled = true; rotate_.amount = exit_rotate_amount_; rotate_.center = {pos_.w / 2.0F, pos_.h / 2.0F}; } // Actualiza según el estado void CardSprite::update(float delta_time) { switch (state_) { case CardState::ENTERING: updateEntering(delta_time); break; case CardState::EXITING: updateExiting(delta_time); break; default: break; } } // Animación de entrada: interpola zoom y ángulo con easing void CardSprite::updateEntering(float delta_time) { entry_elapsed_ += delta_time; float progress = std::clamp(entry_elapsed_ / entry_duration_s_, 0.0F, 1.0F); double eased = entry_easing_(static_cast(progress)); // Zoom: de start_zoom_ a 1.0 con rebote auto current_zoom = static_cast(start_zoom_ + (1.0 - start_zoom_) * eased); horizontal_zoom_ = current_zoom; vertical_zoom_ = current_zoom; // Ángulo: de start_angle_ a 0 con rebote rotate_.angle = start_angle_ * (1.0 - eased); // Offset de sombra escalado con el zoom (perspectiva) // (se aplica en renderShadow) // Transición a LANDED cuando termina la animación if (progress >= 1.0F) { horizontal_zoom_ = 1.0F; vertical_zoom_ = 1.0F; rotate_.angle = 0.0; state_ = CardState::LANDED; } } // Animación de salida: movimiento + rotación continua void CardSprite::updateExiting(float delta_time) { move(delta_time); rotate(delta_time); if (isOffScreen()) { state_ = CardState::FINISHED; } } // Renderiza el sprite y su sombra void CardSprite::render() { if (state_ == CardState::IDLE || state_ == CardState::FINISHED) { return; } // Sombra primero (debajo de la tarjeta) if (shadow_visible_ && shadow_texture_) { renderShadow(); } // Tarjeta MovingSprite::render(); } // Renderiza la sombra con el mismo zoom y rotación que la tarjeta void CardSprite::renderShadow() { // Offset de sombra escalado con el zoom para efecto de perspectiva float scaled_offset_x = shadow_offset_x_ * horizontal_zoom_; float scaled_offset_y = shadow_offset_y_ * vertical_zoom_; shadow_texture_->render( pos_.x + scaled_offset_x, pos_.y + scaled_offset_y, &sprite_clip_, horizontal_zoom_, vertical_zoom_, rotate_.angle, &rotate_.center, flip_); } // Comprueba si el sprite está fuera de pantalla auto CardSprite::isOffScreen() const -> bool { // Considerar el zoom: el sprite puede ser más grande de lo que indica pos_ float effective_width = pos_.w * horizontal_zoom_; float effective_height = pos_.h * vertical_zoom_; return (pos_.x + effective_width < -OFF_SCREEN_MARGIN || pos_.x > screen_width_ + OFF_SCREEN_MARGIN || pos_.y + effective_height < -OFF_SCREEN_MARGIN || pos_.y > screen_height_ + OFF_SCREEN_MARGIN); } // --- Consultas de estado --- auto CardSprite::hasLanded() const -> bool { return state_ == CardState::LANDED || state_ == CardState::EXITING || state_ == CardState::FINISHED; } auto CardSprite::hasFinished() const -> bool { return state_ == CardState::FINISHED; } auto CardSprite::isExiting() const -> bool { return state_ == CardState::EXITING; } auto CardSprite::getState() const -> CardState { return state_; } // --- Configuración --- void CardSprite::setEntryParams(float start_zoom, double start_angle, float duration_s, std::function easing) { start_zoom_ = start_zoom; start_angle_ = start_angle; entry_duration_s_ = duration_s; entry_easing_ = std::move(easing); } void CardSprite::setLandingPosition(float x, float y) { landing_x_ = x; landing_y_ = y; } void CardSprite::setExitParams(float vx, float vy, float ax, float ay, double rotate_amount) { exit_vx_ = vx; exit_vy_ = vy; exit_ax_ = ax; exit_ay_ = ay; exit_rotate_amount_ = rotate_amount; } void CardSprite::setShadowTexture(std::shared_ptr texture) { shadow_texture_ = std::move(texture); } void CardSprite::setShadowOffset(float offset_x, float offset_y) { shadow_offset_x_ = offset_x; shadow_offset_y_ = offset_y; } void CardSprite::setScreenBounds(float width, float height) { screen_width_ = width; screen_height_ = height; }