afegit surface_dissolve_sprite

ending2 amb els fades correctes
This commit is contained in:
2026-03-19 11:19:38 +01:00
parent a7d04d2bbc
commit d9ada12ee0
6 changed files with 124 additions and 21 deletions

View File

@@ -214,6 +214,15 @@ SurfaceAnimatedSprite::SurfaceAnimatedSprite(const AnimationResource& cached_dat
}
}
// Constructor per a subclasses amb surface directa (sense YAML)
SurfaceAnimatedSprite::SurfaceAnimatedSprite(std::shared_ptr<Surface> surface, SDL_FRect pos)
: SurfaceMovingSprite(std::move(surface), pos) {
// animations_ queda buit (protegit per el guard de animate())
if (surface_) {
clip_ = {0, 0, static_cast<float>(surface_->getWidth()), static_cast<float>(surface_->getHeight())};
}
}
// Obtiene el indice de la animación a partir del nombre
auto SurfaceAnimatedSprite::getIndex(const std::string& name) -> int {
auto index = -1;
@@ -230,6 +239,7 @@ auto SurfaceAnimatedSprite::getIndex(const std::string& name) -> int {
// Calcula el frame correspondiente a la animación (time-based)
void SurfaceAnimatedSprite::animate(float delta_time) {
if (animations_.empty()) return;
if (animations_[current_animation_].speed <= 0.0F) {
return;
}

View File

@@ -49,6 +49,9 @@ class SurfaceAnimatedSprite : public SurfaceMovingSprite {
void setCurrentAnimationFrame(int num); // Establece el frame actual de la animación
protected:
// Constructor per a ús de subclasses que gestionen la surface directament (sense YAML)
SurfaceAnimatedSprite(std::shared_ptr<Surface> surface, SDL_FRect pos);
// Métodos protegidos
void animate(float delta_time); // Calcula el frame correspondiente a la animación actual (time-based)

View File

@@ -32,6 +32,18 @@ auto SurfaceDissolveSprite::computePixelRank(int col, int row, int frame_h,
return y_factor * 0.7F + RANDOM * 0.3F;
}
// Constructor per a surface directa (sense AnimationResource)
SurfaceDissolveSprite::SurfaceDissolveSprite(std::shared_ptr<Surface> surface, SDL_FRect pos)
: SurfaceAnimatedSprite(std::move(surface), pos) {
if (surface_) {
const int W = static_cast<int>(surface_->getWidth());
const int H = static_cast<int>(surface_->getHeight());
surface_display_ = std::make_shared<Surface>(W, H);
surface_display_->setTransparentColor(surface_->getTransparentColor());
surface_display_->clear(surface_->getTransparentColor());
}
}
// Constructor
SurfaceDissolveSprite::SurfaceDissolveSprite(const AnimationResource& data)
: SurfaceAnimatedSprite(data) {
@@ -87,7 +99,8 @@ void SurfaceDissolveSprite::rebuildDisplaySurface() {
}
const float RANK = computePixelRank(col, row, SH, direction_);
if (RANK >= progress_) {
dst_data->data[(SY + row) * DST_W + (SX + col)] = COLOR;
const Uint8 OUT = (COLOR == source_color_) ? target_color_ : COLOR;
dst_data->data[(SY + row) * DST_W + (SX + col)] = OUT;
}
}
}
@@ -123,9 +136,9 @@ void SurfaceDissolveSprite::update(float delta_time) {
}
}
// Renderitza: usa surface_display_ si hi ha dissolució activa
// Renderitza: usa surface_display_ (amb color replace) si disponible
void SurfaceDissolveSprite::render() {
if (progress_ <= 0.0F || !surface_display_) {
if (!surface_display_) {
SurfaceAnimatedSprite::render();
return;
}
@@ -167,3 +180,10 @@ void SurfaceDissolveSprite::stopTransition() {
auto SurfaceDissolveSprite::isTransitionDone() const -> bool {
return transition_mode_ == TransitionMode::NONE;
}
// Configura substitució de color per a la reconstrucció
void SurfaceDissolveSprite::setColorReplace(Uint8 source, Uint8 target) {
source_color_ = source;
target_color_ = target;
needs_rebuild_ = true;
}

View File

@@ -16,6 +16,7 @@ enum class DissolveDirection { NONE, DOWN, UP };
class SurfaceDissolveSprite : public SurfaceAnimatedSprite {
public:
explicit SurfaceDissolveSprite(const AnimationResource& data);
SurfaceDissolveSprite(std::shared_ptr<Surface> surface, SDL_FRect pos);
~SurfaceDissolveSprite() override = default;
void update(float delta_time) override;
@@ -34,6 +35,9 @@ class SurfaceDissolveSprite : public SurfaceAnimatedSprite {
void stopTransition();
[[nodiscard]] auto isTransitionDone() const -> bool;
// Substitució de color: en reconstruir, substitueix source per target
void setColorReplace(Uint8 source, Uint8 target);
private:
enum class TransitionMode { NONE, DISSOLVING, GENERATING };
@@ -46,6 +50,8 @@ class SurfaceDissolveSprite : public SurfaceAnimatedSprite {
float transition_elapsed_{0.0F};
SDL_FRect prev_clip_{0, 0, 0, 0};
bool needs_rebuild_{false};
Uint8 source_color_{255}; // 255 = transparent = sense replace per defecte
Uint8 target_color_{0};
void rebuildDisplaySurface();
[[nodiscard]] static auto computePixelRank(int col, int row, int frame_h,

View File

@@ -9,7 +9,7 @@
#include "core/input/input.hpp" // Para Input
#include "core/rendering/screen.hpp" // Para Screen
#include "core/rendering/surface.hpp" // Para Surface
#include "core/rendering/surface_animated_sprite.hpp" // Para SAnimatedSprite
#include "core/rendering/surface_dissolve_sprite.hpp" // Para SurfaceDissolveSprite
#include "core/rendering/surface_moving_sprite.hpp" // Para SMovingSprite
#include "core/rendering/text.hpp" // Para Text
#include "core/resources/resource_cache.hpp" // Para Resource
@@ -267,16 +267,40 @@ void Ending2::loadSprites() {
// Carga los sprites
for (const auto& file : sprite_list_) {
const auto& animation_data = Resource::Cache::get()->getAnimationData(file + ".yaml");
sprites_.emplace_back(std::make_shared<SurfaceAnimatedSprite>(animation_data));
sprites_.emplace_back(std::make_shared<SurfaceDissolveSprite>(animation_data));
sprites_.back()->setColorReplace(1, static_cast<Uint8>(PaletteColor::RED));
sprites_.back()->setProgress(1.0F); // comença invisible
sprite_max_width_ = std::max(sprites_.back()->getWidth(), sprite_max_width_);
sprite_max_height_ = std::max(sprites_.back()->getHeight(), sprite_max_height_);
}
// El último sprite (player) va en blanco, no en rojo
sprites_.back()->setColorReplace(1, static_cast<Uint8>(PaletteColor::WHITE));
}
// Actualiza los sprites
void Ending2::updateSprites(float delta) {
for (const auto& sprite : sprites_) {
sprite->update(delta);
const float Y = sprite->getPosY();
const float H = sprite->getHeight();
const float CANVAS_H = static_cast<float>(Options::game.height);
// Checkpoint inferior: sprite entra per baix → generar de dalt a baix
if (Y > static_cast<float>(ENTRY_EXIT_PADDING)
&& Y <= CANVAS_H - H - ENTRY_EXIT_PADDING
&& sprite->getProgress() >= 1.0F
&& sprite->isTransitionDone()) {
sprite->startGenerate(TRANSITION_DURATION_MS, DissolveDirection::UP);
}
// Checkpoint superior: sprite surt per dalt → dissoldre de dalt a baix
if (Y <= static_cast<float>(ENTRY_EXIT_PADDING)
&& sprite->getProgress() <= 0.0F
&& sprite->isTransitionDone()) {
sprite->startDissolve(TRANSITION_DURATION_MS, DissolveDirection::DOWN);
}
}
}
@@ -284,6 +308,23 @@ void Ending2::updateSprites(float delta) {
void Ending2::updateTextSprites(float delta) {
for (const auto& sprite : sprite_texts_) {
sprite->update(delta);
const float Y = sprite->getPosY();
const float H = sprite->getHeight();
const float CANVAS_H = static_cast<float>(Options::game.height);
if (Y > static_cast<float>(ENTRY_EXIT_PADDING)
&& Y <= CANVAS_H - H - ENTRY_EXIT_PADDING
&& sprite->getProgress() >= 1.0F
&& sprite->isTransitionDone()) {
sprite->startGenerate(TRANSITION_DURATION_MS, DissolveDirection::UP);
}
if (Y <= static_cast<float>(ENTRY_EXIT_PADDING)
&& sprite->getProgress() <= 0.0F
&& sprite->isTransitionDone()) {
sprite->startDissolve(TRANSITION_DURATION_MS, DissolveDirection::DOWN);
}
}
}
@@ -291,31 +332,46 @@ void Ending2::updateTextSprites(float delta) {
void Ending2::updateTexts(float delta) {
for (const auto& sprite : texts_) {
sprite->update(delta);
const float Y = sprite->getPosY();
const float H = sprite->getHeight();
const float CANVAS_H = static_cast<float>(Options::game.height);
// Checkpoint inferior: text entra per baix → generar de dalt a baix
if (Y > static_cast<float>(ENTRY_EXIT_PADDING)
&& Y <= CANVAS_H - H - ENTRY_EXIT_PADDING
&& sprite->getProgress() >= 1.0F
&& sprite->isTransitionDone()) {
sprite->startGenerate(TRANSITION_DURATION_MS, DissolveDirection::UP);
}
// Checkpoint superior: text surt per dalt → dissoldre de dalt a baix
if (Y <= static_cast<float>(ENTRY_EXIT_PADDING)
&& sprite->getProgress() <= 0.0F
&& sprite->isTransitionDone()) {
sprite->startDissolve(TRANSITION_DURATION_MS, DissolveDirection::DOWN);
}
}
}
// Dibuja los sprites
void Ending2::renderSprites() {
for (size_t i = 0; i < sprites_.size(); ++i) {
const auto& sprite = sprites_[i];
for (const auto& sprite : sprites_) {
const bool A = sprite->getRect().y + sprite->getRect().h > 0;
const bool B = sprite->getRect().y < Options::game.height;
if (A && B) {
const Uint8 COLOR = colors_[i % colors_.size()];
sprite->renderWithVerticalFade(FADE_H, Options::game.height, 1, COLOR);
sprite->render();
}
}
}
// Dibuja los sprites con el texto
void Ending2::renderSpriteTexts() {
for (size_t i = 0; i < sprite_texts_.size(); ++i) {
const auto& sprite = sprite_texts_[i];
for (const auto& sprite : sprite_texts_) {
const bool A = sprite->getRect().y + sprite->getRect().h > 0;
const bool B = sprite->getRect().y < Options::game.height;
if (A && B) {
const Uint8 COLOR = colors_[i % colors_.size()];
sprite->renderWithVerticalFade(FADE_H, Options::game.height, 1, COLOR);
sprite->render();
}
}
}
@@ -385,7 +441,9 @@ void Ending2::createSpriteTexts() {
// Crea el sprite
SDL_FRect pos = {X, Y, W, H};
sprite_texts_.emplace_back(std::make_shared<SurfaceMovingSprite>(surface, pos));
sprite_texts_.emplace_back(std::make_shared<SurfaceDissolveSprite>(surface, pos));
sprite_texts_.back()->setColorReplace(1, static_cast<Uint8>(PaletteColor::WHITE));
sprite_texts_.back()->setProgress(1.0F); // comença invisible
sprite_texts_.back()->setVelY(SPRITE_DESP_SPEED);
Screen::get()->setRendererSurface(previuos_renderer);
}
@@ -416,7 +474,8 @@ void Ending2::createTexts() {
// Crea el sprite
SDL_FRect pos = {X + DX, Y, W, H};
texts_.emplace_back(std::make_shared<SurfaceMovingSprite>(surface, pos));
texts_.emplace_back(std::make_shared<SurfaceDissolveSprite>(surface, pos));
texts_.back()->setProgress(1.0F); // comença invisible
texts_.back()->setVelY(SPRITE_DESP_SPEED);
Screen::get()->setRendererSurface(previuos_renderer);
}
@@ -445,7 +504,8 @@ void Ending2::createTexts() {
// Crea el sprite
SDL_FRect pos = {X + DX, Y, W, H};
texts_.emplace_back(std::make_shared<SurfaceMovingSprite>(surface, pos));
texts_.emplace_back(std::make_shared<SurfaceDissolveSprite>(surface, pos));
texts_.back()->setProgress(1.0F); // comença invisible
texts_.back()->setVelY(SPRITE_DESP_SPEED);
Screen::get()->setRendererSurface(previuos_renderer);
}

View File

@@ -7,8 +7,10 @@
#include <vector> // Para vector
#include "utils/defines.hpp" // Para GameCanvas::WIDTH, GameCanvas::FIRST_QUAR...
class SurfaceAnimatedSprite; // lines 9-9
class SurfaceMovingSprite; // lines 10-10
#include "core/rendering/surface_dissolve_sprite.hpp" // Para SurfaceDissolveSprite
class SurfaceMovingSprite;
class DeltaTimer;
class Ending2 {
@@ -43,6 +45,8 @@ class Ending2 {
static constexpr int INITIAL_Y_OFFSET = 40; // Offset inicial en Y para posicionar sprites
static constexpr int SCREEN_MESH_HEIGHT = 8; // Altura de la malla superior/inferior de la pantalla
static constexpr int FADE_H = 24; // Alçada de la zona de dissolució als cantons (files)
static constexpr float TRANSITION_DURATION_MS = 500.0F; // ms per canviar d'estat (generar o dissoldre)
static constexpr int ENTRY_EXIT_PADDING = 2; // px de padding als bordes per activar dissolució/generació
static constexpr int TEXT_SPACING_MULTIPLIER = 2; // Multiplicador para espaciado entre líneas de texto
// Constantes de tiempo (basadas en tiempo real, no en frames)
@@ -74,9 +78,9 @@ class Ending2 {
// --- Variables miembro ---
// Objetos y punteros a recursos
std::vector<std::shared_ptr<SurfaceAnimatedSprite>> sprites_; // Vector con todos los sprites a dibujar
std::vector<std::shared_ptr<SurfaceMovingSprite>> sprite_texts_; // Vector con los sprites de texto de los sprites
std::vector<std::shared_ptr<SurfaceMovingSprite>> texts_; // Vector con los sprites de texto
std::vector<std::shared_ptr<SurfaceDissolveSprite>> sprites_; // Vector con todos los sprites a dibujar
std::vector<std::shared_ptr<SurfaceDissolveSprite>> sprite_texts_; // Vector con los sprites de texto de los sprites
std::vector<std::shared_ptr<SurfaceDissolveSprite>> texts_; // Vector con los sprites de texto
std::unique_ptr<DeltaTimer> delta_timer_; // Timer para time-based update
// Variables de estado