forked from jaildesigner-jailgames/jaildoctors_dilemma
treballant en PixelReveal
This commit is contained in:
@@ -47,6 +47,7 @@ set(APP_SOURCES
|
|||||||
|
|
||||||
# Core - Rendering
|
# Core - Rendering
|
||||||
source/core/rendering/gif.cpp
|
source/core/rendering/gif.cpp
|
||||||
|
source/core/rendering/pixel_reveal.cpp
|
||||||
source/core/rendering/screen.cpp
|
source/core/rendering/screen.cpp
|
||||||
source/core/rendering/surface.cpp
|
source/core/rendering/surface.cpp
|
||||||
source/core/rendering/surface_animated_sprite.cpp
|
source/core/rendering/surface_animated_sprite.cpp
|
||||||
|
|||||||
78
source/core/rendering/pixel_reveal.cpp
Normal file
78
source/core/rendering/pixel_reveal.cpp
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#include "core/rendering/pixel_reveal.hpp"
|
||||||
|
|
||||||
|
#include <algorithm> // Para min
|
||||||
|
#include <numeric> // Para iota
|
||||||
|
#include <random> // Para mt19937, shuffle
|
||||||
|
|
||||||
|
#include "core/rendering/surface.hpp" // Para Surface
|
||||||
|
#include "utils/utils.hpp" // Para PaletteColor
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
PixelReveal::PixelReveal(int width, int height, float pixels_per_second, float step_duration, int num_steps)
|
||||||
|
: cover_surface_(std::make_shared<Surface>(width, height)),
|
||||||
|
reveal_order_(height),
|
||||||
|
row_step_(height, 0),
|
||||||
|
width_(width),
|
||||||
|
height_(height),
|
||||||
|
pixels_per_second_(pixels_per_second),
|
||||||
|
step_duration_(step_duration),
|
||||||
|
num_steps_(num_steps) {
|
||||||
|
// Rellena la máscara con negro sólido
|
||||||
|
cover_surface_->clear(static_cast<Uint8>(PaletteColor::BLACK));
|
||||||
|
|
||||||
|
// Genera el orden aleatorio de columnas por fila usando la fila como semilla (reproducible)
|
||||||
|
for (int r = 0; r < height_; r++) {
|
||||||
|
reveal_order_[r].resize(width_);
|
||||||
|
std::iota(reveal_order_[r].begin(), reveal_order_[r].end(), 0);
|
||||||
|
std::mt19937 rng(static_cast<unsigned int>(r));
|
||||||
|
std::shuffle(reveal_order_[r].begin(), reveal_order_[r].end(), rng);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
PixelReveal::~PixelReveal() = default;
|
||||||
|
|
||||||
|
// Actualiza el estado del revelado
|
||||||
|
void PixelReveal::update(float time_active) {
|
||||||
|
const auto TRANSPARENT = static_cast<Uint8>(PaletteColor::TRANSPARENT);
|
||||||
|
|
||||||
|
for (int r = 0; r < height_; r++) {
|
||||||
|
const float T_START = static_cast<float>(r) / pixels_per_second_;
|
||||||
|
const float TIME_IN_ROW = time_active - T_START;
|
||||||
|
|
||||||
|
if (TIME_IN_ROW < 0.0F) {
|
||||||
|
continue; // Esta fila aún no ha empezado
|
||||||
|
}
|
||||||
|
|
||||||
|
const int STEPS = std::min(num_steps_, static_cast<int>(TIME_IN_ROW / step_duration_));
|
||||||
|
|
||||||
|
if (STEPS > row_step_[r]) {
|
||||||
|
// Revela los píxeles de los pasos pendientes
|
||||||
|
for (int step = row_step_[r]; step < STEPS; step++) {
|
||||||
|
const int START_IDX = step * width_ / num_steps_;
|
||||||
|
const int END_IDX = (step == num_steps_ - 1) ? width_ : (step + 1) * width_ / num_steps_;
|
||||||
|
|
||||||
|
for (int idx = START_IDX; idx < END_IDX; idx++) {
|
||||||
|
const int COL = reveal_order_[r][idx];
|
||||||
|
cover_surface_->putPixel(COL, r, TRANSPARENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
row_step_[r] = STEPS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dibuja la máscara en la posición indicada
|
||||||
|
void PixelReveal::render(int dst_x, int dst_y) const {
|
||||||
|
cover_surface_->render(dst_x, dst_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indica si el revelado ha completado todas las filas
|
||||||
|
bool PixelReveal::isComplete() const {
|
||||||
|
for (const int step : row_step_) {
|
||||||
|
if (step < num_steps_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
36
source/core/rendering/pixel_reveal.hpp
Normal file
36
source/core/rendering/pixel_reveal.hpp
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory> // Para shared_ptr
|
||||||
|
#include <vector> // Para vector
|
||||||
|
|
||||||
|
class Surface;
|
||||||
|
|
||||||
|
// Efecto de revelado pixel a pixel por filas, de arriba a abajo.
|
||||||
|
// Cada fila se revela en num_steps pasos, con píxeles aleatorios en cada paso.
|
||||||
|
class PixelReveal {
|
||||||
|
public:
|
||||||
|
// Constructor
|
||||||
|
PixelReveal(int width, int height, float pixels_per_second, float step_duration, int num_steps = 4);
|
||||||
|
|
||||||
|
// Destructor definido en el .cpp para que unique_ptr<Surface> funcione con forward declaration
|
||||||
|
~PixelReveal();
|
||||||
|
|
||||||
|
// Actualiza el estado del revelado según el tiempo transcurrido
|
||||||
|
void update(float time_active);
|
||||||
|
|
||||||
|
// Dibuja la máscara de revelado en la posición indicada
|
||||||
|
void render(int dst_x, int dst_y) const;
|
||||||
|
|
||||||
|
// Indica si el revelado ha completado todas las filas
|
||||||
|
[[nodiscard]] bool isComplete() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<Surface> cover_surface_; // Máscara negra que se va haciendo transparente
|
||||||
|
std::vector<std::vector<int>> reveal_order_; // Orden aleatorio de columnas por fila
|
||||||
|
std::vector<int> row_step_; // Paso actual de revelado por fila (0..num_steps_)
|
||||||
|
int width_;
|
||||||
|
int height_;
|
||||||
|
float pixels_per_second_; // Filas reveladas por segundo
|
||||||
|
float step_duration_; // Segundos por paso dentro de una fila
|
||||||
|
int num_steps_; // Número de pasos de revelado por fila
|
||||||
|
};
|
||||||
@@ -34,7 +34,7 @@ enum class Options {
|
|||||||
|
|
||||||
// --- Variables de estado globales ---
|
// --- Variables de estado globales ---
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
inline Scene current = Scene::GAME; // Escena actual
|
inline Scene current = Scene::ENDING; // Escena actual
|
||||||
inline Options options = Options::LOGO_TO_LOADING_SCREEN; // Opciones de la escena actual
|
inline Options options = Options::LOGO_TO_LOADING_SCREEN; // Opciones de la escena actual
|
||||||
#else
|
#else
|
||||||
inline Scene current = Scene::LOGO; // Escena actual
|
inline Scene current = Scene::LOGO; // Escena actual
|
||||||
|
|||||||
@@ -2,11 +2,10 @@
|
|||||||
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
#include <algorithm> // Para min
|
|
||||||
|
|
||||||
#include "core/audio/audio.hpp" // Para Audio
|
#include "core/audio/audio.hpp" // Para Audio
|
||||||
#include "core/input/global_inputs.hpp" // Para check
|
#include "core/input/global_inputs.hpp" // Para check
|
||||||
#include "core/input/input.hpp" // Para Input
|
#include "core/input/input.hpp" // Para Input
|
||||||
|
#include "core/rendering/pixel_reveal.hpp" // Para PixelReveal
|
||||||
#include "core/rendering/screen.hpp" // Para Screen
|
#include "core/rendering/screen.hpp" // Para Screen
|
||||||
#include "core/rendering/surface.hpp" // Para Surface
|
#include "core/rendering/surface.hpp" // Para Surface
|
||||||
#include "core/rendering/surface_animated_sprite.hpp" // Para SAnimatedSprite
|
#include "core/rendering/surface_animated_sprite.hpp" // Para SAnimatedSprite
|
||||||
@@ -19,10 +18,12 @@
|
|||||||
#include "utils/delta_timer.hpp" // Para DeltaTimer
|
#include "utils/delta_timer.hpp" // Para DeltaTimer
|
||||||
#include "utils/utils.hpp" // Para PaletteColor
|
#include "utils/utils.hpp" // Para PaletteColor
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
Credits::~Credits() = default;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Credits::Credits()
|
Credits::Credits()
|
||||||
: text_surface_(std::make_shared<Surface>(Options::game.width, Options::game.height)),
|
: text_surface_(std::make_shared<Surface>(Options::game.width, Options::game.height)),
|
||||||
cover_surface_(std::make_shared<Surface>(Options::game.width, Options::game.height)),
|
|
||||||
shining_sprite_(std::make_shared<SurfaceAnimatedSprite>(Resource::Cache::get()->getAnimationData("shine.yaml"))),
|
shining_sprite_(std::make_shared<SurfaceAnimatedSprite>(Resource::Cache::get()->getAnimationData("shine.yaml"))),
|
||||||
delta_timer_(std::make_unique<DeltaTimer>()) {
|
delta_timer_(std::make_unique<DeltaTimer>()) {
|
||||||
// Configura la escena
|
// Configura la escena
|
||||||
@@ -115,24 +116,8 @@ void Credits::fillTexture() {
|
|||||||
// Recoloca el sprite del brillo
|
// Recoloca el sprite del brillo
|
||||||
shining_sprite_->setPosX(POS_X + 2);
|
shining_sprite_->setPosX(POS_X + 2);
|
||||||
|
|
||||||
// Rellena la textura que cubre el texto con color transparente
|
// Crea el efecto de revelado pixel a pixel
|
||||||
cover_surface_->clear(static_cast<Uint8>(PaletteColor::TRANSPARENT));
|
pixel_reveal_ = std::make_unique<PixelReveal>(Options::game.width, Options::game.height, PIXELS_PER_SECOND, STEP_DURATION, REVEAL_STEPS);
|
||||||
|
|
||||||
// Los primeros 8 pixels crea una malla
|
|
||||||
auto color = static_cast<Uint8>(PaletteColor::BLACK);
|
|
||||||
for (int i = 0; i < 256; i += 2) {
|
|
||||||
cover_surface_->putPixel(i, 0, color);
|
|
||||||
cover_surface_->putPixel(i, 2, color);
|
|
||||||
cover_surface_->putPixel(i, 4, color);
|
|
||||||
cover_surface_->putPixel(i, 6, color);
|
|
||||||
|
|
||||||
cover_surface_->putPixel(i + 1, 5, color);
|
|
||||||
cover_surface_->putPixel(i + 1, 7, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
// El resto se rellena de color sólido
|
|
||||||
SDL_FRect rect = {0, 8, 256, 192};
|
|
||||||
cover_surface_->fillRect(&rect, color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualiza las variables
|
// Actualiza las variables
|
||||||
@@ -145,6 +130,8 @@ void Credits::update() {
|
|||||||
|
|
||||||
updateState(DELTA_TIME); // Actualiza la máquina de estados
|
updateState(DELTA_TIME); // Actualiza la máquina de estados
|
||||||
|
|
||||||
|
pixel_reveal_->update(reveal_time_); // Actualiza el efecto de revelado
|
||||||
|
|
||||||
// Actualiza el sprite con el brillo si está después del tiempo de inicio
|
// Actualiza el sprite con el brillo si está después del tiempo de inicio
|
||||||
if (reveal_time_ > SHINE_START_TIME) {
|
if (reveal_time_ > SHINE_START_TIME) {
|
||||||
shining_sprite_->update(DELTA_TIME);
|
shining_sprite_->update(DELTA_TIME);
|
||||||
@@ -239,11 +226,8 @@ void Credits::render() {
|
|||||||
// Dibuja la textura con el texto en pantalla
|
// Dibuja la textura con el texto en pantalla
|
||||||
text_surface_->render(0, 0);
|
text_surface_->render(0, 0);
|
||||||
|
|
||||||
// Dibuja la textura que cubre el texto
|
// Dibuja la máscara de revelado pixel a pixel
|
||||||
// OFFSET basado en reveal_time_ (que se congela durante pausas, como counter_ original)
|
pixel_reveal_->render(0, 0);
|
||||||
const float OFFSET = std::min(reveal_time_ * REVEAL_SPEED / 8.0F, 192.0F / 2.0F);
|
|
||||||
SDL_FRect src_rect = {0.0F, 0.0F, 256.0F, 192.0F - (OFFSET * 2.0F)};
|
|
||||||
cover_surface_->render(0, static_cast<int>(OFFSET * 2.0F), &src_rect);
|
|
||||||
|
|
||||||
// Dibuja el sprite con el brillo
|
// Dibuja el sprite con el brillo
|
||||||
if (reveal_time_ > SHINE_START_TIME) {
|
if (reveal_time_ > SHINE_START_TIME) {
|
||||||
|
|||||||
@@ -7,13 +7,14 @@
|
|||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
class SurfaceAnimatedSprite; // lines 11-11
|
class SurfaceAnimatedSprite; // lines 11-11
|
||||||
class Surface;
|
class Surface;
|
||||||
|
class PixelReveal;
|
||||||
class DeltaTimer;
|
class DeltaTimer;
|
||||||
|
|
||||||
class Credits {
|
class Credits {
|
||||||
public:
|
public:
|
||||||
// --- Constructor y Destructor ---
|
// --- Constructor y Destructor ---
|
||||||
Credits();
|
Credits();
|
||||||
~Credits() = default;
|
~Credits();
|
||||||
|
|
||||||
// --- Bucle principal ---
|
// --- Bucle principal ---
|
||||||
void run();
|
void run();
|
||||||
@@ -47,7 +48,9 @@ class Credits {
|
|||||||
static constexpr float TOTAL_DURATION = 20.0F; // 1200 frames @ 60fps
|
static constexpr float TOTAL_DURATION = 20.0F; // 1200 frames @ 60fps
|
||||||
static constexpr float SHINE_START_TIME = 12.833F; // 770 frames @ 60fps
|
static constexpr float SHINE_START_TIME = 12.833F; // 770 frames @ 60fps
|
||||||
static constexpr float FADE_OUT_START = 19.167F; // 1150 frames @ 60fps
|
static constexpr float FADE_OUT_START = 19.167F; // 1150 frames @ 60fps
|
||||||
static constexpr float REVEAL_SPEED = 60.0F; // counter equivalente por segundo @ 60fps
|
static constexpr float PIXELS_PER_SECOND = 15.0F; // Filas reveladas por segundo (REVEAL_SPEED/8*2 = 60/8*2 = 15)
|
||||||
|
static constexpr float STEP_DURATION = 2.0F / 60.0F; // Segundos por paso de revelado (2 frames @ 60fps)
|
||||||
|
static constexpr int REVEAL_STEPS = 16; // Pasos de revelado por fila (más pasos = efecto más visible)
|
||||||
|
|
||||||
// --- Métodos privados ---
|
// --- Métodos privados ---
|
||||||
void update(); // Actualiza las variables
|
void update(); // Actualiza las variables
|
||||||
@@ -62,7 +65,7 @@ class Credits {
|
|||||||
// --- Variables miembro ---
|
// --- Variables miembro ---
|
||||||
// Recursos gráficos
|
// Recursos gráficos
|
||||||
std::shared_ptr<Surface> text_surface_; // Textura para dibujar el texto
|
std::shared_ptr<Surface> text_surface_; // Textura para dibujar el texto
|
||||||
std::shared_ptr<Surface> cover_surface_; // Textura para cubrir el texto
|
std::unique_ptr<PixelReveal> pixel_reveal_; // Efecto de revelado pixel a pixel
|
||||||
std::shared_ptr<SurfaceAnimatedSprite> shining_sprite_; // Sprite para el brillo del corazón
|
std::shared_ptr<SurfaceAnimatedSprite> shining_sprite_; // Sprite para el brillo del corazón
|
||||||
|
|
||||||
// Temporizadores y estado
|
// Temporizadores y estado
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "core/audio/audio.hpp" // Para Audio
|
#include "core/audio/audio.hpp" // Para Audio
|
||||||
#include "core/input/global_inputs.hpp" // Para check
|
#include "core/input/global_inputs.hpp" // Para check
|
||||||
#include "core/input/input.hpp" // Para Input
|
#include "core/input/input.hpp" // Para Input
|
||||||
|
#include "core/rendering/pixel_reveal.hpp" // Para PixelReveal
|
||||||
#include "core/rendering/screen.hpp" // Para Screen
|
#include "core/rendering/screen.hpp" // Para Screen
|
||||||
#include "core/rendering/surface.hpp" // Para Surface
|
#include "core/rendering/surface.hpp" // Para Surface
|
||||||
#include "core/rendering/surface_sprite.hpp" // Para SSprite
|
#include "core/rendering/surface_sprite.hpp" // Para SSprite
|
||||||
@@ -34,6 +35,9 @@ Ending::Ending()
|
|||||||
fillCoverTexture(); // Rellena la textura para la cortinilla
|
fillCoverTexture(); // Rellena la textura para la cortinilla
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
Ending::~Ending() = default;
|
||||||
|
|
||||||
// Actualiza el objeto
|
// Actualiza el objeto
|
||||||
void Ending::update() {
|
void Ending::update() {
|
||||||
const float DELTA_TIME = delta_timer_->tick();
|
const float DELTA_TIME = delta_timer_->tick();
|
||||||
@@ -60,8 +64,9 @@ void Ending::render() {
|
|||||||
// Skip rendering durante WARMING_UP
|
// Skip rendering durante WARMING_UP
|
||||||
if (state_ != State::WARMING_UP) {
|
if (state_ != State::WARMING_UP) {
|
||||||
// Dibuja las imagenes de la escena
|
// Dibuja las imagenes de la escena
|
||||||
sprite_pics_.at(current_scene_).image_sprite->render();
|
const auto& pic = sprite_pics_.at(current_scene_);
|
||||||
sprite_pics_.at(current_scene_).cover_sprite->render();
|
pic.image_sprite->render();
|
||||||
|
pic.pixel_reveal->render(pic.pos_x, pic.pos_y);
|
||||||
|
|
||||||
// Dibuja los textos de la escena
|
// Dibuja los textos de la escena
|
||||||
for (const auto& ti : scenes_.at(current_scene_).text_index) {
|
for (const auto& ti : scenes_.at(current_scene_).text_index) {
|
||||||
@@ -69,8 +74,9 @@ void Ending::render() {
|
|||||||
const float TRIGGER_TIME = static_cast<float>(ti.trigger) / 60.0F;
|
const float TRIGGER_TIME = static_cast<float>(ti.trigger) / 60.0F;
|
||||||
|
|
||||||
if (state_time_ > TRIGGER_TIME) {
|
if (state_time_ > TRIGGER_TIME) {
|
||||||
sprite_texts_.at(ti.index).image_sprite->render();
|
const auto& txt = sprite_texts_.at(ti.index);
|
||||||
sprite_texts_.at(ti.index).cover_sprite->render();
|
txt.image_sprite->render();
|
||||||
|
txt.pixel_reveal->render(txt.pos_x, txt.pos_y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,42 +225,14 @@ void Ending::iniTexts() {
|
|||||||
|
|
||||||
// Crea el sprite
|
// Crea el sprite
|
||||||
st.image_sprite = std::make_shared<SurfaceSprite>(st.image_surface, 0, 0, st.image_surface->getWidth(), st.image_surface->getHeight());
|
st.image_sprite = std::make_shared<SurfaceSprite>(st.image_surface, 0, 0, st.image_surface->getWidth(), st.image_surface->getHeight());
|
||||||
st.image_sprite->setPosition((Options::game.width - st.image_surface->getWidth()) / 2, txt.pos);
|
st.pos_x = static_cast<int>((Options::game.width - st.image_surface->getWidth()) / 2);
|
||||||
|
st.pos_y = txt.pos;
|
||||||
|
st.image_sprite->setPosition(st.pos_x, st.pos_y);
|
||||||
|
|
||||||
// Crea la cover_surface
|
// Crea el efecto de revelado pixel a pixel
|
||||||
st.cover_surface = std::make_shared<Surface>(WIDTH, HEIGHT + 8);
|
st.pixel_reveal = std::make_unique<PixelReveal>(static_cast<int>(WIDTH), static_cast<int>(HEIGHT), TEXT_PIXELS_PER_SECOND, STEP_DURATION, REVEAL_STEPS);
|
||||||
Screen::get()->setRendererSurface(st.cover_surface);
|
|
||||||
|
|
||||||
// Rellena la cover_surface con color transparente
|
sprite_texts_.push_back(std::move(st));
|
||||||
st.cover_surface->clear(static_cast<Uint8>(PaletteColor::TRANSPARENT));
|
|
||||||
|
|
||||||
// Crea una malla de 8 pixels de alto
|
|
||||||
auto surface = Screen::get()->getRendererSurface();
|
|
||||||
auto color = static_cast<Uint8>(PaletteColor::BLACK);
|
|
||||||
for (int i = 0; i < WIDTH; i += 2) {
|
|
||||||
surface->putPixel(i, 0, color);
|
|
||||||
surface->putPixel(i, 2, color);
|
|
||||||
surface->putPixel(i, 4, color);
|
|
||||||
surface->putPixel(i, 6, color);
|
|
||||||
|
|
||||||
surface->putPixel(i + 1, 5, color);
|
|
||||||
surface->putPixel(i + 1, 7, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
// El resto se rellena de color sólido
|
|
||||||
SDL_FRect rect = {0, 8, WIDTH, HEIGHT};
|
|
||||||
surface->fillRect(&rect, color);
|
|
||||||
|
|
||||||
// Crea el sprite
|
|
||||||
st.cover_sprite = std::make_shared<SurfaceSprite>(st.cover_surface, 0, 0, st.cover_surface->getWidth(), st.cover_surface->getHeight() - 8);
|
|
||||||
st.cover_sprite->setPosition((Options::game.width - st.cover_surface->getWidth()) / 2, txt.pos);
|
|
||||||
st.cover_sprite->setClip(0, 8, st.cover_surface->getWidth(), st.cover_surface->getHeight());
|
|
||||||
|
|
||||||
// Inicializa variables
|
|
||||||
st.cover_clip_desp = 8;
|
|
||||||
st.cover_clip_height = HEIGHT;
|
|
||||||
|
|
||||||
sprite_texts_.push_back(st);
|
|
||||||
Screen::get()->setRendererSurface(previuos_renderer);
|
Screen::get()->setRendererSurface(previuos_renderer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,45 +261,15 @@ void Ending::iniPics() {
|
|||||||
const float HEIGHT = sp.image_surface->getHeight();
|
const float HEIGHT = sp.image_surface->getHeight();
|
||||||
|
|
||||||
// Crea el sprite
|
// Crea el sprite
|
||||||
|
sp.pos_x = static_cast<int>((Options::game.width - WIDTH) / 2);
|
||||||
|
sp.pos_y = pic.pos;
|
||||||
sp.image_sprite = std::make_shared<SurfaceSprite>(sp.image_surface, 0, 0, WIDTH, HEIGHT);
|
sp.image_sprite = std::make_shared<SurfaceSprite>(sp.image_surface, 0, 0, WIDTH, HEIGHT);
|
||||||
sp.image_sprite->setPosition((Options::game.width - WIDTH) / 2, pic.pos);
|
sp.image_sprite->setPosition(sp.pos_x, sp.pos_y);
|
||||||
|
|
||||||
// Crea la cover_surface
|
// Crea el efecto de revelado pixel a pixel
|
||||||
sp.cover_surface = std::make_shared<Surface>(WIDTH, HEIGHT + 8);
|
sp.pixel_reveal = std::make_unique<PixelReveal>(static_cast<int>(WIDTH), static_cast<int>(HEIGHT), IMAGE_PIXELS_PER_SECOND, STEP_DURATION, REVEAL_STEPS);
|
||||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
|
||||||
Screen::get()->setRendererSurface(sp.cover_surface);
|
|
||||||
|
|
||||||
// Rellena la cover_surface con color transparente
|
sprite_pics_.push_back(std::move(sp));
|
||||||
sp.cover_surface->clear(static_cast<Uint8>(PaletteColor::TRANSPARENT));
|
|
||||||
|
|
||||||
// Crea una malla en los primeros 8 pixels
|
|
||||||
auto surface = Screen::get()->getRendererSurface();
|
|
||||||
auto color = static_cast<Uint8>(PaletteColor::BLACK);
|
|
||||||
for (int i = 0; i < WIDTH; i += 2) {
|
|
||||||
surface->putPixel(i, 0, color);
|
|
||||||
surface->putPixel(i, 2, color);
|
|
||||||
surface->putPixel(i, 4, color);
|
|
||||||
surface->putPixel(i, 6, color);
|
|
||||||
|
|
||||||
surface->putPixel(i + 1, 5, color);
|
|
||||||
surface->putPixel(i + 1, 7, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
// El resto se rellena de color sólido
|
|
||||||
SDL_FRect rect = {0.0F, 8.0F, WIDTH, HEIGHT};
|
|
||||||
surface->fillRect(&rect, color);
|
|
||||||
|
|
||||||
// Crea el sprite
|
|
||||||
sp.cover_sprite = std::make_shared<SurfaceSprite>(sp.cover_surface, 0, 0, sp.cover_surface->getWidth(), sp.cover_surface->getHeight() - 8);
|
|
||||||
sp.cover_sprite->setPosition((Options::game.width - sp.cover_surface->getWidth()) / 2, pic.pos);
|
|
||||||
sp.cover_sprite->setClip(0, 8, sp.cover_surface->getWidth(), sp.cover_surface->getHeight());
|
|
||||||
|
|
||||||
// Inicializa variables
|
|
||||||
sp.cover_clip_desp = 8;
|
|
||||||
sp.cover_clip_height = HEIGHT;
|
|
||||||
|
|
||||||
sprite_pics_.push_back(sp);
|
|
||||||
Screen::get()->setRendererSurface(previuos_renderer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,68 +374,18 @@ void Ending::updateSpriteCovers() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualiza la cortinilla de los textos
|
// Actualiza el revelado de los textos
|
||||||
for (const auto& ti : scenes_.at(current_scene_).text_index) {
|
for (const auto& ti : scenes_.at(current_scene_).text_index) {
|
||||||
// Convertir trigger de frames a segundos @ 60fps
|
|
||||||
const float TRIGGER_TIME = static_cast<float>(ti.trigger) / 60.0F;
|
const float TRIGGER_TIME = static_cast<float>(ti.trigger) / 60.0F;
|
||||||
|
|
||||||
if (state_time_ > TRIGGER_TIME) {
|
if (state_time_ > TRIGGER_TIME) {
|
||||||
// Tiempo transcurrido desde que se activó el trigger
|
|
||||||
const float TIME_SINCE_TRIGGER = state_time_ - TRIGGER_TIME;
|
const float TIME_SINCE_TRIGGER = state_time_ - TRIGGER_TIME;
|
||||||
|
sprite_texts_.at(ti.index).pixel_reveal->update(TIME_SINCE_TRIGGER);
|
||||||
// Píxeles revelados: tiempo * velocidad
|
|
||||||
const float PIXELS_REVEALED = TIME_SINCE_TRIGGER * TEXT_REVEAL_SPEED;
|
|
||||||
|
|
||||||
// Obtiene el sprite
|
|
||||||
auto sprite_text = sprite_texts_.at(ti.index);
|
|
||||||
|
|
||||||
// Obtener altura inicial de la superficie
|
|
||||||
const float INITIAL_HEIGHT = sprite_text.image_surface->getHeight();
|
|
||||||
const float Y_INITIAL = sprite_text.image_sprite->getY();
|
|
||||||
|
|
||||||
// Fase 1: Revelar malla decorativa (8 píxeles)
|
|
||||||
if (PIXELS_REVEALED < 8.0F) {
|
|
||||||
sprite_text.cover_clip_desp = static_cast<int>(8.0F - PIXELS_REVEALED);
|
|
||||||
sprite_text.cover_clip_height = static_cast<int>(INITIAL_HEIGHT);
|
|
||||||
sprite_text.cover_sprite->setY(Y_INITIAL);
|
|
||||||
}
|
|
||||||
// Fase 2: Revelar contenido
|
|
||||||
else {
|
|
||||||
sprite_text.cover_clip_desp = 0;
|
|
||||||
const int CONTENT_PIXELS = PIXELS_REVEALED - 8.0F;
|
|
||||||
sprite_text.cover_clip_height = std::max(0, static_cast<int>(INITIAL_HEIGHT - CONTENT_PIXELS));
|
|
||||||
sprite_text.cover_sprite->setY(Y_INITIAL + static_cast<int>(CONTENT_PIXELS));
|
|
||||||
}
|
|
||||||
|
|
||||||
sprite_text.cover_sprite->setClip(
|
|
||||||
0,
|
|
||||||
sprite_text.cover_clip_desp,
|
|
||||||
sprite_text.cover_sprite->getWidth(),
|
|
||||||
sprite_text.cover_clip_height);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualiza la cortinilla de las imágenes (revelación continua desde el inicio de la escena)
|
// Actualiza el revelado de la imagen (desde el inicio de la escena)
|
||||||
auto sprite_pics = sprite_pics_.at(current_scene_);
|
sprite_pics_.at(current_scene_).pixel_reveal->update(state_time_);
|
||||||
const float PIXELS_REVEALED = state_time_ * IMAGE_REVEAL_SPEED;
|
|
||||||
const float INITIAL_HEIGHT = sprite_pics.image_surface->getHeight();
|
|
||||||
const float Y_INITIAL = sprite_pics.image_sprite->getY();
|
|
||||||
|
|
||||||
// Fase 1: Revelar malla decorativa (8 píxeles)
|
|
||||||
if (PIXELS_REVEALED < 8.0F) {
|
|
||||||
sprite_pics.cover_clip_desp = static_cast<int>(8.0F - PIXELS_REVEALED);
|
|
||||||
sprite_pics.cover_clip_height = static_cast<int>(INITIAL_HEIGHT);
|
|
||||||
sprite_pics.cover_sprite->setY(Y_INITIAL);
|
|
||||||
}
|
|
||||||
// Fase 2: Revelar contenido
|
|
||||||
else {
|
|
||||||
sprite_pics.cover_clip_desp = 0;
|
|
||||||
const int CONTENT_PIXELS = PIXELS_REVEALED - 8.0F;
|
|
||||||
sprite_pics.cover_clip_height = std::max(0, static_cast<int>(INITIAL_HEIGHT - CONTENT_PIXELS));
|
|
||||||
sprite_pics.cover_sprite->setY(Y_INITIAL + static_cast<int>(CONTENT_PIXELS));
|
|
||||||
}
|
|
||||||
|
|
||||||
sprite_pics.cover_sprite->setClip(0, sprite_pics.cover_clip_desp, sprite_pics.cover_sprite->getWidth(), sprite_pics.cover_clip_height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comprueba si se ha de cambiar de escena
|
// Comprueba si se ha de cambiar de escena
|
||||||
|
|||||||
@@ -7,13 +7,14 @@
|
|||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
class SurfaceSprite; // lines 8-8
|
class SurfaceSprite; // lines 8-8
|
||||||
class Surface; // lines 9-9
|
class Surface; // lines 9-9
|
||||||
|
class PixelReveal;
|
||||||
class DeltaTimer;
|
class DeltaTimer;
|
||||||
|
|
||||||
class Ending {
|
class Ending {
|
||||||
public:
|
public:
|
||||||
// --- Constructor y Destructor ---
|
// --- Constructor y Destructor ---
|
||||||
Ending();
|
Ending();
|
||||||
~Ending() = default;
|
~Ending();
|
||||||
|
|
||||||
// --- Bucle principal ---
|
// --- Bucle principal ---
|
||||||
void run();
|
void run();
|
||||||
@@ -34,10 +35,9 @@ class Ending {
|
|||||||
struct EndingSurface {
|
struct EndingSurface {
|
||||||
std::shared_ptr<Surface> image_surface; // Surface a mostrar
|
std::shared_ptr<Surface> image_surface; // Surface a mostrar
|
||||||
std::shared_ptr<SurfaceSprite> image_sprite; // SSprite para mostrar la textura
|
std::shared_ptr<SurfaceSprite> image_sprite; // SSprite para mostrar la textura
|
||||||
std::shared_ptr<Surface> cover_surface; // Surface que cubre a la otra textura
|
std::unique_ptr<PixelReveal> pixel_reveal; // Efecto de revelado pixel a pixel
|
||||||
std::shared_ptr<SurfaceSprite> cover_sprite; // SSprite para mostrar la textura que cubre a la otra textura
|
int pos_x{0}; // Posición X de renderizado
|
||||||
int cover_clip_desp{0}; // Desplazamiento del spriteClip de la textura de cobertura
|
int pos_y{0}; // Posición Y de renderizado
|
||||||
int cover_clip_height{0}; // Altura del spriteClip de la textura de cobertura
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TextAndPosition {
|
struct TextAndPosition {
|
||||||
@@ -64,8 +64,10 @@ class Ending {
|
|||||||
static constexpr float SCENE_2_DURATION = 16.667F; // 1000 frames @ 60fps
|
static constexpr float SCENE_2_DURATION = 16.667F; // 1000 frames @ 60fps
|
||||||
static constexpr float SCENE_3_DURATION = 13.333F; // 800 frames @ 60fps
|
static constexpr float SCENE_3_DURATION = 13.333F; // 800 frames @ 60fps
|
||||||
static constexpr float SCENE_4_DURATION = 16.667F; // 1000 frames @ 60fps
|
static constexpr float SCENE_4_DURATION = 16.667F; // 1000 frames @ 60fps
|
||||||
static constexpr float TEXT_REVEAL_SPEED = 30.0F; // 2px cada 4 frames @ 60fps
|
static constexpr float TEXT_PIXELS_PER_SECOND = 30.0F; // Filas de texto reveladas por segundo
|
||||||
static constexpr float IMAGE_REVEAL_SPEED = 60.0F; // 2px cada 2 frames @ 60fps
|
static constexpr float IMAGE_PIXELS_PER_SECOND = 60.0F; // Filas de imagen reveladas por segundo
|
||||||
|
static constexpr float STEP_DURATION = 2.0F / 60.0F; // Segundos por paso de revelado (2 frames @ 60fps)
|
||||||
|
static constexpr int REVEAL_STEPS = 10; // Pasos de revelado por fila (más pasos = efecto más visible)
|
||||||
static constexpr float TEXT_LAPSE = 1.333F; // 80 frames @ 60fps
|
static constexpr float TEXT_LAPSE = 1.333F; // 80 frames @ 60fps
|
||||||
static constexpr float FADEOUT_START_OFFSET = 1.667F; // Inicio fade-out 100 frames antes del fin
|
static constexpr float FADEOUT_START_OFFSET = 1.667F; // Inicio fade-out 100 frames antes del fin
|
||||||
static constexpr float ENDING_DURATION = 2.0F; // Duración del estado ENDING (2 segundos)
|
static constexpr float ENDING_DURATION = 2.0F; // Duración del estado ENDING (2 segundos)
|
||||||
|
|||||||
Reference in New Issue
Block a user