#include "game_logo.h" #include // Para SDL_SetTextureScaleMode, SDL_FlipMode, SDL_ScaleMode #include // Para max #include "animated_sprite.h" // Para AnimatedSprite #include "audio.h" // Para Audio #include "color.h" // Para Color #include "param.h" // Para Param, param, ParamGame, ParamTitle #include "resource.h" // Para Resource #include "screen.h" // Para Screen #include "smart_sprite.h" // Para SmartSprite #include "sprite.h" // Para Sprite #include "texture.h" // Para Texture constexpr int ZOOM_FACTOR = 5; constexpr int FLASH_DELAY = 3; constexpr int FLASH_LENGTH = FLASH_DELAY + 3; // Constructor GameLogo::GameLogo(int x, int y) : dust_texture_(Resource::get()->getTexture("title_dust.png")), coffee_texture_(Resource::get()->getTexture("title_coffee.png")), crisis_texture_(Resource::get()->getTexture("title_crisis.png")), arcade_edition_texture_(Resource::get()->getTexture("title_arcade_edition.png")), dust_left_sprite_(std::make_unique(dust_texture_, Resource::get()->getAnimation("title_dust.ani"))), dust_right_sprite_(std::make_unique(dust_texture_, Resource::get()->getAnimation("title_dust.ani"))), coffee_sprite_(std::make_unique(coffee_texture_)), crisis_sprite_(std::make_unique(crisis_texture_)), arcade_edition_sprite_(std::make_unique(arcade_edition_texture_, (param.game.width - arcade_edition_texture_->getWidth()) / 2, param.title.arcade_edition_position, arcade_edition_texture_->getWidth(), arcade_edition_texture_->getHeight())), x_(x), y_(y) {} // Inicializa las variables void GameLogo::init() { const auto XP = x_ - (coffee_texture_->getWidth() / 2); const auto DESP = getInitialVerticalDesp(); // Configura texturas SDL_SetTextureScaleMode(Resource::get()->getTexture("title_arcade_edition.png")->getSDLTexture(), SDL_SCALEMODE_NEAREST); // Variables coffee_crisis_status_ = Status::DISABLED; 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); coffee_sprite_->setPosY(y_ - coffee_texture_->getHeight() - DESP); coffee_sprite_->setWidth(coffee_texture_->getWidth()); coffee_sprite_->setHeight(coffee_texture_->getHeight()); coffee_sprite_->setVelX(0.0F); coffee_sprite_->setVelY(2.5F); coffee_sprite_->setAccelX(0.0F); coffee_sprite_->setAccelY(0.1F); coffee_sprite_->setSpriteClip(0, 0, coffee_texture_->getWidth(), coffee_texture_->getHeight()); coffee_sprite_->setEnabled(true); coffee_sprite_->setFinishedCounter(0); coffee_sprite_->setDestX(XP); coffee_sprite_->setDestY(y_ - coffee_texture_->getHeight()); // Inicializa el bitmap de 'Crisis' crisis_sprite_->setPosX(XP + 15); crisis_sprite_->setPosY(y_ + DESP); crisis_sprite_->setWidth(crisis_texture_->getWidth()); crisis_sprite_->setHeight(crisis_texture_->getHeight()); crisis_sprite_->setVelX(0.0F); crisis_sprite_->setVelY(-2.5F); crisis_sprite_->setAccelX(0.0F); crisis_sprite_->setAccelY(-0.1F); crisis_sprite_->setSpriteClip(0, 0, crisis_texture_->getWidth(), crisis_texture_->getHeight()); crisis_sprite_->setEnabled(true); crisis_sprite_->setFinishedCounter(0); crisis_sprite_->setDestX(XP + 15); crisis_sprite_->setDestY(y_); // Inicializa el bitmap de 'DustRight' dust_right_sprite_->resetAnimation(); dust_right_sprite_->setPosX(coffee_sprite_->getPosX() + coffee_sprite_->getWidth()); dust_right_sprite_->setPosY(y_); dust_right_sprite_->setWidth(16); dust_right_sprite_->setHeight(16); dust_right_sprite_->setFlip(SDL_FLIP_HORIZONTAL); // Inicializa el bitmap de 'DustLeft' dust_left_sprite_->resetAnimation(); dust_left_sprite_->setPosX(coffee_sprite_->getPosX() - 16); dust_left_sprite_->setPosY(y_); dust_left_sprite_->setWidth(16); dust_left_sprite_->setHeight(16); // Inicializa el bitmap de 'Arcade Edition' arcade_edition_sprite_->setZoom(zoom_); } // Pinta la clase en pantalla void GameLogo::render() { // Dibuja el logo coffee_sprite_->render(); crisis_sprite_->render(); if (arcade_edition_status_ != Status::DISABLED) { arcade_edition_sprite_->render(); } // Dibuja el polvillo del logo if (coffee_crisis_status_ != Status::MOVING) { dust_right_sprite_->render(); dust_left_sprite_->render(); } } // 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: handleCoffeeCrisisMoving(); break; case Status::SHAKING: handleCoffeeCrisisShaking(); break; case Status::FINISHED: handleCoffeeCrisisFinished(); break; default: break; } } 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: handleArcadeEditionMoving(); break; case Status::SHAKING: handleArcadeEditionShaking(); break; default: break; } } 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(); if (coffee_sprite_->hasFinished() && crisis_sprite_->hasFinished()) { coffee_crisis_status_ = Status::SHAKING; playTitleEffects(); } } 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()); } else { finishCoffeeCrisisShaking(); } 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_); if (zoom_ <= 1.0F) { finishArcadeEditionMoving(); } } 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(); } else { arcade_edition_sprite_->setX(shake_.origin); arcade_edition_status_ = Status::FINISHED; } } 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--; } else { shake_.counter = shake_.delay; 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::processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite, float deltaTime) { // Convertir delay (frames) a tiempo: delay frames = delay * (1000ms/60fps) float delayTime = static_cast(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--; } else { shake_.counter = shake_.delay; const auto DISPLACEMENT = calculateShakeDisplacement(); arcade_edition_sprite_->setX(shake_.origin + DISPLACEMENT); shake_.remaining--; } } void GameLogo::processArcadeEditionShake(float deltaTime) { // Convertir delay (frames) a tiempo: delay frames = delay * (1000ms/60fps) float delayTime = static_cast(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; } void GameLogo::finishCoffeeCrisisShaking() { coffee_sprite_->setPosX(shake_.origin); crisis_sprite_->setPosX(shake_.origin + 15); coffee_crisis_status_ = Status::FINISHED; arcade_edition_status_ = Status::MOVING; } void GameLogo::finishArcadeEditionMoving() { arcade_edition_status_ = Status::SHAKING; zoom_ = 1.0F; arcade_edition_sprite_->setZoom(zoom_); shake_.init(1, 2, 8, arcade_edition_sprite_->getX()); playTitleEffects(); } void GameLogo::playTitleEffects() { Audio::get()->playSound("title.wav"); Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGTH, FLASH_DELAY); Screen::get()->shake(); } void GameLogo::updateDustSprites() { dust_right_sprite_->update(); 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 && post_finished_counter_ > 0) { --post_finished_counter_; } } 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(); coffee_crisis_status_ = Status::MOVING; } // Indica si ha terminado la animación auto GameLogo::hasFinished() const -> bool { return post_finished_counter_ == 0; } // Calcula el desplazamiento vertical inicial auto GameLogo::getInitialVerticalDesp() const -> int { const float OFFSET_UP = y_; const float OFFSET_DOWN = param.game.height - y_; return std::max(OFFSET_UP, OFFSET_DOWN); }