3 Commits

Author SHA1 Message Date
4e2393f4d5 fix: al acabar el segon ending, la transicio es a logo_to_title, no a logo_to_loading_screen 2026-03-19 11:21:38 +01:00
d9ada12ee0 afegit surface_dissolve_sprite
ending2 amb els fades correctes
2026-03-19 11:19:38 +01:00
a7d04d2bbc treballant en ending2 2026-03-19 09:53:42 +01:00
12 changed files with 464 additions and 41 deletions

View File

@@ -51,6 +51,7 @@ set(APP_SOURCES
source/core/rendering/screen.cpp
source/core/rendering/surface.cpp
source/core/rendering/surface_animated_sprite.cpp
source/core/rendering/surface_dissolve_sprite.cpp
source/core/rendering/surface_moving_sprite.cpp
source/core/rendering/surface_sprite.cpp
source/core/rendering/text.cpp

View File

@@ -428,6 +428,102 @@ void Surface::renderWithColorReplace(int x, int y, Uint8 source_color, Uint8 tar
}
}
// Hash 2D estable per a dithering sense flickering
static auto pixelThreshold(int col, int row) -> float {
auto h = static_cast<uint32_t>(col) * 2246822519U ^ static_cast<uint32_t>(row) * 2654435761U;
h ^= (h >> 13);
h *= 1274126177U;
h ^= (h >> 16);
return static_cast<float>(h & 0xFFFFU) / 65536.0F;
}
// Render amb dissolució als cantons superior/inferior (hash 2D, sense parpelleig)
void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, SDL_FRect* src_rect) {
const int SX = src_rect ? static_cast<int>(src_rect->x) : 0;
const int SY = src_rect ? static_cast<int>(src_rect->y) : 0;
const int SW = src_rect ? static_cast<int>(src_rect->w) : static_cast<int>(surface_data_->width);
const int SH = src_rect ? static_cast<int>(src_rect->h) : static_cast<int>(surface_data_->height);
auto surface_data_dest = Screen::get()->getRendererSurface()->getSurfaceData();
for (int row = 0; row < SH; row++) {
const int SCREEN_Y = y + row;
if (SCREEN_Y < 0 || SCREEN_Y >= static_cast<int>(surface_data_dest->height)) {
continue;
}
float density = 0.0F;
if (SCREEN_Y < fade_h) {
density = static_cast<float>(fade_h - SCREEN_Y) / static_cast<float>(fade_h);
} else if (SCREEN_Y >= canvas_height - fade_h) {
density = static_cast<float>(SCREEN_Y - (canvas_height - fade_h)) / static_cast<float>(fade_h);
}
for (int col = 0; col < SW; col++) {
const int SCREEN_X = x + col;
if (SCREEN_X < 0 || SCREEN_X >= static_cast<int>(surface_data_dest->width)) {
continue;
}
const Uint8 COLOR = surface_data_->data[(SY + row) * static_cast<int>(surface_data_->width) + (SX + col)];
if (static_cast<int>(COLOR) == transparent_color_) {
continue;
}
if (pixelThreshold(col, row) < density) {
continue; // Pixel tapat per la zona de fade
}
surface_data_dest->data[SCREEN_X + (SCREEN_Y * static_cast<int>(surface_data_dest->width))] = sub_palette_[COLOR];
}
}
}
// Idem però reemplaçant un color índex
void Surface::renderWithVerticalFade(int x, int y, int fade_h, int canvas_height,
Uint8 source_color, Uint8 target_color,
SDL_FRect* src_rect) {
const int SX = src_rect ? static_cast<int>(src_rect->x) : 0;
const int SY = src_rect ? static_cast<int>(src_rect->y) : 0;
const int SW = src_rect ? static_cast<int>(src_rect->w) : static_cast<int>(surface_data_->width);
const int SH = src_rect ? static_cast<int>(src_rect->h) : static_cast<int>(surface_data_->height);
auto surface_data_dest = Screen::get()->getRendererSurface()->getSurfaceData();
for (int row = 0; row < SH; row++) {
const int SCREEN_Y = y + row;
if (SCREEN_Y < 0 || SCREEN_Y >= static_cast<int>(surface_data_dest->height)) {
continue;
}
float density = 0.0F;
if (SCREEN_Y < fade_h) {
density = static_cast<float>(fade_h - SCREEN_Y) / static_cast<float>(fade_h);
} else if (SCREEN_Y >= canvas_height - fade_h) {
density = static_cast<float>(SCREEN_Y - (canvas_height - fade_h)) / static_cast<float>(fade_h);
}
for (int col = 0; col < SW; col++) {
const int SCREEN_X = x + col;
if (SCREEN_X < 0 || SCREEN_X >= static_cast<int>(surface_data_dest->width)) {
continue;
}
const Uint8 COLOR = surface_data_->data[(SY + row) * static_cast<int>(surface_data_->width) + (SX + col)];
if (static_cast<int>(COLOR) == transparent_color_) {
continue;
}
if (pixelThreshold(col, row) < density) {
continue; // Pixel tapat per la zona de fade
}
const Uint8 OUT_COLOR = (COLOR == source_color) ? target_color : sub_palette_[COLOR];
surface_data_dest->data[SCREEN_X + (SCREEN_Y * static_cast<int>(surface_data_dest->width))] = OUT_COLOR;
}
}
}
// Vuelca la superficie a una textura
void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture) {
if ((renderer == nullptr) || (texture == nullptr) || !surface_data_) {

View File

@@ -84,6 +84,14 @@ class Surface {
// Copia una región de la SurfaceData de origen a la SurfaceData de destino reemplazando un color por otro
void renderWithColorReplace(int x, int y, Uint8 source_color = 0, Uint8 target_color = 0, SDL_FRect* src_rect = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE);
// Render amb dissolució als cantons superior/inferior (hash 2D, sense parpelleig)
void renderWithVerticalFade(int x, int y, int fade_h, int canvas_height, SDL_FRect* src_rect = nullptr);
// Idem però reemplaçant un color índex (per a sprites sobre fons del mateix color)
void renderWithVerticalFade(int x, int y, int fade_h, int canvas_height,
Uint8 source_color, Uint8 target_color,
SDL_FRect* src_rect = nullptr);
// Establece un color en la paleta
void setColor(int index, Uint32 color);

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

@@ -0,0 +1,189 @@
#include "core/rendering/surface_dissolve_sprite.hpp"
#include <algorithm> // Para min
#include <cstdint> // Para uint32_t
#include "core/rendering/surface.hpp" // Para Surface
// Hash 2D estable per a dithering (rank aleatori per posició de píxel)
static auto pixelRank(int col, int row) -> float {
auto h = static_cast<uint32_t>(col) * 2246822519U ^ static_cast<uint32_t>(row) * 2654435761U;
h ^= (h >> 13);
h *= 1274126177U;
h ^= (h >> 16);
return static_cast<float>(h & 0xFFFFU) / 65536.0F;
}
// Rang per a un píxel tenint en compte direcció (70% direccional + 30% aleatori)
auto SurfaceDissolveSprite::computePixelRank(int col, int row, int frame_h,
DissolveDirection dir) -> float {
const float RANDOM = pixelRank(col, row);
if (dir == DissolveDirection::NONE || frame_h <= 0) {
return RANDOM;
}
float y_factor = 0.0F;
if (dir == DissolveDirection::DOWN) {
y_factor = static_cast<float>(row) / static_cast<float>(frame_h);
} else {
y_factor = static_cast<float>(frame_h - 1 - row) / static_cast<float>(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) {
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());
// Inicialitza tots els píxels com a transparents
surface_display_->clear(surface_->getTransparentColor());
}
}
// Reconstrueix la surface_display_ filtrant píxels per progress_
void SurfaceDissolveSprite::rebuildDisplaySurface() {
if (!surface_ || !surface_display_) {
return;
}
const SDL_FRect CLIP = clip_;
const int SX = static_cast<int>(CLIP.x);
const int SY = static_cast<int>(CLIP.y);
const int SW = static_cast<int>(CLIP.w);
const int SH = static_cast<int>(CLIP.h);
if (SW <= 0 || SH <= 0) {
return;
}
auto src_data = surface_->getSurfaceData();
auto dst_data = surface_display_->getSurfaceData();
const int SRC_W = static_cast<int>(src_data->width);
const int DST_W = static_cast<int>(dst_data->width);
const Uint8 TRANSPARENT = surface_->getTransparentColor();
// Esborra frame anterior si ha canviat
if (prev_clip_.w > 0 && prev_clip_.h > 0 &&
(prev_clip_.x != CLIP.x || prev_clip_.y != CLIP.y ||
prev_clip_.w != CLIP.w || prev_clip_.h != CLIP.h)) {
surface_display_->fillRect(&prev_clip_, TRANSPARENT);
}
// Esborra la zona del frame actual (reconstrucció neta)
surface_display_->fillRect(&CLIP, TRANSPARENT);
// Copia píxels filtrats per progress_
for (int row = 0; row < SH; ++row) {
for (int col = 0; col < SW; ++col) {
const Uint8 COLOR = src_data->data[(SY + row) * SRC_W + (SX + col)];
if (COLOR == TRANSPARENT) {
continue;
}
const float RANK = computePixelRank(col, row, SH, direction_);
if (RANK >= progress_) {
const Uint8 OUT = (COLOR == source_color_) ? target_color_ : COLOR;
dst_data->data[(SY + row) * DST_W + (SX + col)] = OUT;
}
}
}
prev_clip_ = CLIP;
needs_rebuild_ = false;
}
// Actualitza animació, moviment i transició temporal
void SurfaceDissolveSprite::update(float delta_time) {
const SDL_FRect OLD_CLIP = clip_;
SurfaceAnimatedSprite::update(delta_time);
// Detecta canvi de frame d'animació
if (clip_.x != OLD_CLIP.x || clip_.y != OLD_CLIP.y ||
clip_.w != OLD_CLIP.w || clip_.h != OLD_CLIP.h) {
needs_rebuild_ = true;
}
// Actualitza transició temporal si activa
if (transition_mode_ != TransitionMode::NONE) {
transition_elapsed_ += delta_time * 1000.0F;
const float T = std::min(transition_elapsed_ / transition_duration_, 1.0F);
progress_ = (transition_mode_ == TransitionMode::DISSOLVING) ? T : (1.0F - T);
needs_rebuild_ = true;
if (T >= 1.0F) {
transition_mode_ = TransitionMode::NONE;
}
}
if (needs_rebuild_) {
rebuildDisplaySurface();
}
}
// Renderitza: usa surface_display_ (amb color replace) si disponible
void SurfaceDissolveSprite::render() {
if (!surface_display_) {
SurfaceAnimatedSprite::render();
return;
}
surface_display_->render(static_cast<int>(pos_.x), static_cast<int>(pos_.y), &clip_, flip_);
}
// Estableix el progrés manualment
void SurfaceDissolveSprite::setProgress(float progress) {
progress_ = std::min(std::max(progress, 0.0F), 1.0F);
needs_rebuild_ = true;
}
// Inicia dissolució temporal (visible → invisible)
void SurfaceDissolveSprite::startDissolve(float duration_ms, DissolveDirection dir) {
direction_ = dir;
transition_mode_ = TransitionMode::DISSOLVING;
transition_duration_ = duration_ms;
transition_elapsed_ = 0.0F;
progress_ = 0.0F;
needs_rebuild_ = true;
}
// Inicia generació temporal (invisible → visible)
void SurfaceDissolveSprite::startGenerate(float duration_ms, DissolveDirection dir) {
direction_ = dir;
transition_mode_ = TransitionMode::GENERATING;
transition_duration_ = duration_ms;
transition_elapsed_ = 0.0F;
progress_ = 1.0F;
needs_rebuild_ = true;
}
// Atura la transició temporal
void SurfaceDissolveSprite::stopTransition() {
transition_mode_ = TransitionMode::NONE;
}
// Retorna si la transició ha acabat
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

@@ -0,0 +1,59 @@
#pragma once
#include <SDL3/SDL.h>
#include <memory> // Para shared_ptr
#include "core/rendering/surface_animated_sprite.hpp" // Para SurfaceAnimatedSprite
class Surface;
// Direcció de la dissolució
enum class DissolveDirection { NONE, DOWN, UP };
// Sprite que pot dissoldre's o generar-se de forma aleatòria en X mil·lisegons.
// progress_ va de 0.0 (totalment visible) a 1.0 (totalment invisible).
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;
void render() override;
// Progrés manual [0.0 = totalment visible, 1.0 = totalment invisible]
void setProgress(float progress);
[[nodiscard]] auto getProgress() const -> float { return progress_; }
// Inicia una dissolució temporal (visible → invisible en duration_ms)
void startDissolve(float duration_ms, DissolveDirection dir = DissolveDirection::NONE);
// Inicia una generació temporal (invisible → visible en duration_ms)
void startGenerate(float duration_ms, DissolveDirection dir = DissolveDirection::NONE);
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 };
std::shared_ptr<Surface> surface_display_; // Superfície amb els píxels filtrats
float progress_{0.0F}; // [0=visible, 1=invisible]
DissolveDirection direction_{DissolveDirection::NONE};
TransitionMode transition_mode_{TransitionMode::NONE};
float transition_duration_{0.0F};
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,
DissolveDirection dir) -> float;
};

View File

@@ -31,6 +31,19 @@ void SurfaceSprite::render(Uint8 source_color, Uint8 target_color) {
surface_->renderWithColorReplace(pos_.x, pos_.y, source_color, target_color, &clip_);
}
void SurfaceSprite::renderWithVerticalFade(int fade_h, int canvas_height) {
surface_->renderWithVerticalFade(
static_cast<int>(pos_.x), static_cast<int>(pos_.y),
fade_h, canvas_height, &clip_);
}
void SurfaceSprite::renderWithVerticalFade(int fade_h, int canvas_height,
Uint8 source_color, Uint8 target_color) {
surface_->renderWithVerticalFade(
static_cast<int>(pos_.x), static_cast<int>(pos_.y),
fade_h, canvas_height, source_color, target_color, &clip_);
}
// Establece la posición del objeto
void SurfaceSprite::setPosition(float x, float y) {
pos_.x = x;

View File

@@ -22,6 +22,8 @@ class SurfaceSprite {
virtual void update(float delta_time); // Actualiza el estado del sprite (time-based)
virtual void render(); // Muestra el sprite por pantalla
virtual void render(Uint8 source_color, Uint8 target_color); // Renderiza con reemplazo de color
virtual void renderWithVerticalFade(int fade_h, int canvas_height); // Renderiza amb dissolució vertical (hash 2D, sense parpelleig)
virtual void renderWithVerticalFade(int fade_h, int canvas_height, Uint8 source_color, Uint8 target_color); // Idem amb reemplaç de color
// Gestión de estado
virtual void clear(); // Reinicia las variables a cero

View File

@@ -34,7 +34,7 @@ enum class Options {
// --- Variables de estado globales ---
#ifdef _DEBUG
inline Scene current = Scene::CREDITS; // Escena actual
inline Scene current = Scene::ENDING2; // Escena actual
inline Options options = Options::LOGO_TO_LOADING_SCREEN; // Opciones de la escena actual
#else
inline Scene current = Scene::LOGO; // Escena actual

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
@@ -90,27 +90,6 @@ void Ending2::render() {
// Dibuja los sprites con el texto del final
renderTexts();
// Dibuja una trama arriba y abajo
auto color = static_cast<Uint8>(PaletteColor::BLACK);
auto surface = Screen::get()->getRendererSurface();
for (int i = 0; i < 256; i += 2) {
surface->putPixel(i + 0, 0, color);
surface->putPixel(i + 1, 1, color);
surface->putPixel(i + 0, 2, color);
surface->putPixel(i + 1, 3, color);
surface->putPixel(i, 4, color);
surface->putPixel(i, 6, color);
surface->putPixel(i + 0, 191, color);
surface->putPixel(i + 1, 190, color);
surface->putPixel(i + 0, 189, color);
surface->putPixel(i + 1, 188, color);
surface->putPixel(i, 187, color);
surface->putPixel(i, 185, color);
}
// Vuelca el contenido del renderizador en pantalla
Screen::get()->render();
}
@@ -167,7 +146,7 @@ void Ending2::updateState(float delta_time) {
case EndingState::FADING:
if (state_time_ >= STATE_FADE_DURATION) {
SceneManager::current = SceneManager::Scene::LOGO;
SceneManager::options = SceneManager::Options::LOGO_TO_LOADING_SCREEN;
SceneManager::options = SceneManager::Options::LOGO_TO_TITLE;
}
break;
@@ -288,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);
}
}
}
@@ -305,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);
}
}
}
@@ -312,33 +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() {
const auto COLOR_A = static_cast<Uint8>(PaletteColor::RED);
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) {
sprite->render(1, COLOR_A);
sprite->render();
}
}
// Pinta el ultimo elemento de otro color
const auto COLOR_B = static_cast<Uint8>(PaletteColor::WHITE);
sprites_.back()->render(1, COLOR_B);
}
// Dibuja los sprites con el texto
void Ending2::renderSpriteTexts() {
const auto COLOR = static_cast<Uint8>(PaletteColor::WHITE);
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) {
sprite->render(1, COLOR);
sprite->render();
}
}
}
@@ -408,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);
}
@@ -439,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);
}
@@ -468,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 {
@@ -42,6 +44,9 @@ class Ending2 {
static constexpr int DIST_SPRITE_SPRITE = 0; // Distancia entre dos sprites de la misma columna
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)
@@ -73,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