Compare commits
2 Commits
dfa66b0e95
...
metal-inte
| Author | SHA1 | Date | |
|---|---|---|---|
| b3f6e2fcf0 | |||
| 7f00942517 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,4 @@
|
||||
.vscode
|
||||
.claude
|
||||
build/
|
||||
data/config/config.txt
|
||||
*.DS_Store
|
||||
|
||||
@@ -43,10 +43,6 @@ auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffe
|
||||
std::vector<std::string> buffer;
|
||||
std::string line;
|
||||
while (std::getline(input_stream, line)) {
|
||||
// Eliminar caracteres de retorno de carro (\r) al final de la línea
|
||||
if (!line.empty() && line.back() == '\r') {
|
||||
line.pop_back();
|
||||
}
|
||||
if (!line.empty()) {
|
||||
buffer.push_back(line);
|
||||
}
|
||||
@@ -86,7 +82,7 @@ auto AnimatedSprite::getAnimationIndex(const std::string& name) -> int {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Calcula el frame correspondiente a la animación (frame-based)
|
||||
// Calcula el frame correspondiente a la animación
|
||||
void AnimatedSprite::animate() {
|
||||
if (animations_[current_animation_].speed == 0 || animations_[current_animation_].paused) {
|
||||
return;
|
||||
@@ -116,39 +112,6 @@ void AnimatedSprite::animate() {
|
||||
}
|
||||
}
|
||||
|
||||
// Calcula el frame correspondiente a la animación (time-based)
|
||||
void AnimatedSprite::animate(float deltaTime) {
|
||||
if (animations_[current_animation_].speed == 0 || animations_[current_animation_].paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convertir speed (frames) a tiempo: speed frames = speed/60 segundos a 60fps
|
||||
float frameTime = static_cast<float>(animations_[current_animation_].speed) / 60.0f;
|
||||
|
||||
// Acumular tiempo transcurrido
|
||||
animations_[current_animation_].time_accumulator += deltaTime;
|
||||
|
||||
// Verificar si es momento de cambiar frame
|
||||
if (animations_[current_animation_].time_accumulator >= frameTime) {
|
||||
animations_[current_animation_].time_accumulator -= frameTime;
|
||||
animations_[current_animation_].current_frame++;
|
||||
|
||||
// Si alcanza el final de la animación
|
||||
if (animations_[current_animation_].current_frame >= animations_[current_animation_].frames.size()) {
|
||||
if (animations_[current_animation_].loop == -1) { // Si no hay loop, deja el último frame
|
||||
animations_[current_animation_].current_frame = animations_[current_animation_].frames.size() - 1;
|
||||
animations_[current_animation_].completed = true;
|
||||
} else { // Si hay loop, vuelve al frame indicado
|
||||
animations_[current_animation_].time_accumulator = 0.0f;
|
||||
animations_[current_animation_].current_frame = animations_[current_animation_].loop;
|
||||
}
|
||||
}
|
||||
|
||||
// Actualizar el sprite clip
|
||||
updateSpriteClip();
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba si ha terminado la animación
|
||||
auto AnimatedSprite::animationIsCompleted() -> bool {
|
||||
return animations_[current_animation_].completed;
|
||||
@@ -163,12 +126,10 @@ void AnimatedSprite::setCurrentAnimation(const std::string& name, bool reset) {
|
||||
if (reset) {
|
||||
animations_[current_animation_].current_frame = 0;
|
||||
animations_[current_animation_].counter = 0;
|
||||
animations_[current_animation_].time_accumulator = 0.0f;
|
||||
animations_[current_animation_].completed = false;
|
||||
} else {
|
||||
animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size() - 1);
|
||||
animations_[current_animation_].counter = animations_[OLD_ANIMATION].counter;
|
||||
animations_[current_animation_].time_accumulator = animations_[OLD_ANIMATION].time_accumulator;
|
||||
animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed;
|
||||
}
|
||||
updateSpriteClip();
|
||||
@@ -184,35 +145,26 @@ void AnimatedSprite::setCurrentAnimation(int index, bool reset) {
|
||||
if (reset) {
|
||||
animations_[current_animation_].current_frame = 0;
|
||||
animations_[current_animation_].counter = 0;
|
||||
animations_[current_animation_].time_accumulator = 0.0f;
|
||||
animations_[current_animation_].completed = false;
|
||||
} else {
|
||||
animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size());
|
||||
animations_[current_animation_].counter = animations_[OLD_ANIMATION].counter;
|
||||
animations_[current_animation_].time_accumulator = animations_[OLD_ANIMATION].time_accumulator;
|
||||
animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed;
|
||||
}
|
||||
updateSpriteClip();
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza las variables del objeto (frame-based)
|
||||
// Actualiza las variables del objeto
|
||||
void AnimatedSprite::update() {
|
||||
animate();
|
||||
MovingSprite::update();
|
||||
}
|
||||
|
||||
// Actualiza las variables del objeto (time-based)
|
||||
void AnimatedSprite::update(float deltaTime) {
|
||||
animate(deltaTime);
|
||||
MovingSprite::update(deltaTime);
|
||||
}
|
||||
|
||||
// Reinicia la animación
|
||||
void AnimatedSprite::resetAnimation() {
|
||||
animations_[current_animation_].current_frame = 0;
|
||||
animations_[current_animation_].counter = 0;
|
||||
animations_[current_animation_].time_accumulator = 0.0f;
|
||||
animations_[current_animation_].completed = false;
|
||||
animations_[current_animation_].paused = false;
|
||||
updateSpriteClip();
|
||||
|
||||
@@ -21,12 +21,11 @@ struct Animation {
|
||||
|
||||
std::string name; // Nombre de la animación
|
||||
std::vector<SDL_FRect> frames; // Frames que componen la animación
|
||||
int speed{DEFAULT_SPEED}; // Velocidad de reproducción (frame-based)
|
||||
int speed{DEFAULT_SPEED}; // Velocidad de reproducción
|
||||
int loop{0}; // Frame de vuelta al terminar (-1 para no repetir)
|
||||
bool completed{false}; // Indica si la animación ha finalizado
|
||||
size_t current_frame{0}; // Frame actual en reproducción
|
||||
int counter{0}; // Contador para la animación (frame-based)
|
||||
float time_accumulator{0.0f}; // Acumulador de tiempo para animaciones time-based
|
||||
int counter{0}; // Contador para la animación
|
||||
bool paused{false}; // La animación no avanza
|
||||
|
||||
Animation() = default;
|
||||
@@ -56,8 +55,7 @@ class AnimatedSprite : public MovingSprite {
|
||||
~AnimatedSprite() override = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
void update() override; // Actualiza la animación (frame-based)
|
||||
void update(float deltaTime); // Actualiza la animación (time-based)
|
||||
void update() override; // Actualiza la animación
|
||||
|
||||
// --- Control de animaciones ---
|
||||
void setCurrentAnimation(const std::string& name = "default", bool reset = true); // Establece la animación por nombre
|
||||
@@ -80,8 +78,7 @@ class AnimatedSprite : public MovingSprite {
|
||||
int current_animation_ = 0; // Índice de la animación activa
|
||||
|
||||
// --- Métodos internos ---
|
||||
void animate(); // Calcula el frame correspondiente a la animación (frame-based)
|
||||
void animate(float deltaTime); // Calcula el frame correspondiente a la animación (time-based)
|
||||
void animate(); // Calcula el frame correspondiente a la animación
|
||||
void loadFromAnimationsFileBuffer(const AnimationsFileBuffer& source); // Carga la animación desde un vector de cadenas
|
||||
void processConfigLine(const std::string& line, AnimationConfig& config); // Procesa una línea de configuración
|
||||
void updateFrameCalculations(AnimationConfig& config); // Actualiza los cálculos basados en las dimensiones del frame
|
||||
|
||||
@@ -126,14 +126,7 @@ void Background::initializeTextures() {
|
||||
}
|
||||
|
||||
// Actualiza la lógica del objeto
|
||||
// Actualiza la lógica del objeto (compatibilidad)
|
||||
void Background::update() {
|
||||
constexpr float FRAME_TIME_MS = 1000.0f / 60.0f; // 16.67ms por frame a 60 FPS
|
||||
update(FRAME_TIME_MS);
|
||||
}
|
||||
|
||||
// Actualiza la lógica del objeto
|
||||
void Background::update(float delta_time) {
|
||||
// Actualiza la progresión y calcula transiciones
|
||||
if (!manual_mode_) {
|
||||
updateProgression();
|
||||
|
||||
@@ -31,8 +31,7 @@ class Background {
|
||||
~Background(); // Destructor
|
||||
|
||||
// --- Métodos principales ---
|
||||
void update(); // Actualiza la lógica del objeto (compatibilidad)
|
||||
void update(float delta_time); // Actualiza la lógica del objeto
|
||||
void update(); // Actualiza la lógica del objeto
|
||||
void render(); // Dibuja el objeto
|
||||
void reset(); // Reinicia la progresión
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ constexpr SDL_ScaleMode VIDEO_SCALE_MODE = SDL_ScaleMode::SDL_SCALEMODE_NEAREST;
|
||||
constexpr bool VIDEO_FULLSCREEN = false;
|
||||
constexpr bool VIDEO_VSYNC = true;
|
||||
constexpr bool VIDEO_INTEGER_SCALE = true;
|
||||
constexpr bool VIDEO_SHADERS = false;
|
||||
constexpr bool VIDEO_SHADERS = true;
|
||||
|
||||
// Music
|
||||
constexpr bool MUSIC_ENABLED = true;
|
||||
|
||||
@@ -42,7 +42,7 @@ Director::Director(int argc, std::span<char *> argv) {
|
||||
Section::name = Section::Name::GAME;
|
||||
Section::options = Section::Options::GAME_PLAY_1P;
|
||||
#elif _DEBUG
|
||||
Section::name = Section::Name::INSTRUCTIONS;
|
||||
Section::name = Section::Name::HI_SCORE_TABLE;
|
||||
Section::options = Section::Options::GAME_PLAY_1P;
|
||||
#else // NORMAL GAME
|
||||
Section::name = Section::Name::LOGO;
|
||||
|
||||
16
source/external/jail_shader.h
vendored
16
source/external/jail_shader.h
vendored
@@ -4,6 +4,20 @@
|
||||
#include <string> // Para basic_string, string
|
||||
|
||||
namespace shader {
|
||||
bool init(SDL_Window *ventana, SDL_Texture *texturaBackBuffer, const std::string &vertexShader, const std::string &fragmentShader = "");
|
||||
bool init(SDL_Window *ventana, SDL_Texture *texturaBackBuffer, const std::string &shaderSource, const std::string &fragmentShader = "");
|
||||
void render();
|
||||
void cleanup();
|
||||
bool isUsingOpenGL();
|
||||
|
||||
#ifdef __APPLE__
|
||||
namespace metal {
|
||||
bool initMetal(SDL_Window* window, SDL_Texture* backBuffer, const std::string& shaderFilename);
|
||||
SDL_Texture* createMetalRenderTarget(SDL_Renderer* renderer, int width, int height);
|
||||
void updateMetalTexture(SDL_Texture* backBuffer);
|
||||
void renderMetal();
|
||||
void renderWithPostProcessing(SDL_Renderer* renderer, SDL_Texture* sourceTexture);
|
||||
void cleanupMetal();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace shader
|
||||
387
source/external/jail_shader_metal.mm
vendored
Normal file
387
source/external/jail_shader_metal.mm
vendored
Normal file
@@ -0,0 +1,387 @@
|
||||
#include "jail_shader.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_metal.h>
|
||||
#include <Metal/Metal.h>
|
||||
#include <QuartzCore/CAMetalLayer.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include "../asset.h"
|
||||
|
||||
namespace shader {
|
||||
namespace metal {
|
||||
|
||||
// Metal objects
|
||||
id<MTLDevice> device = nullptr;
|
||||
id<MTLRenderPipelineState> pipelineState = nullptr;
|
||||
id<MTLBuffer> vertexBuffer = nullptr;
|
||||
id<MTLTexture> backBufferTexture = nullptr;
|
||||
id<MTLTexture> gameCanvasTexture = nullptr; // Our custom render target texture
|
||||
id<MTLSamplerState> sampler = nullptr;
|
||||
|
||||
// SDL objects (references from main shader module)
|
||||
SDL_Window* win = nullptr;
|
||||
SDL_Renderer* renderer = nullptr;
|
||||
SDL_Texture* backBuffer = nullptr;
|
||||
|
||||
// Vertex data for fullscreen quad
|
||||
struct Vertex {
|
||||
float position[4]; // x, y, z, w
|
||||
float texcoord[2]; // u, v
|
||||
};
|
||||
|
||||
const Vertex quadVertices[] = {
|
||||
// Position (x, y, z, w) // TexCoord (u, v) - Standard OpenGL-style coordinates
|
||||
{{-1.0f, -1.0f, 0.0f, 1.0f}, {0.0f, 1.0f}}, // Bottom-left
|
||||
{{ 1.0f, -1.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}, // Bottom-right
|
||||
{{-1.0f, 1.0f, 0.0f, 1.0f}, {0.0f, 0.0f}}, // Top-left
|
||||
{{ 1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, 0.0f}}, // Top-right
|
||||
};
|
||||
|
||||
std::string loadMetalShader(const std::string& filename) {
|
||||
// Try to load the .metal file from the same location as GLSL files
|
||||
auto data = Asset::get()->loadData(filename);
|
||||
if (!data.empty()) {
|
||||
return std::string(data.begin(), data.end());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
SDL_Texture* createMetalRenderTarget(SDL_Renderer* renderer, int width, int height) {
|
||||
if (!renderer) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "createMetalRenderTarget: No renderer provided");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Crear textura Metal como render target
|
||||
SDL_Texture* metalTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
|
||||
if (!metalTexture) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create Metal render target texture: %s", SDL_GetError());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Configurar filtrado nearest neighbor para look pixelado
|
||||
SDL_SetTextureScaleMode(metalTexture, SDL_SCALEMODE_NEAREST);
|
||||
|
||||
// Try to extract and store the Metal texture directly
|
||||
SDL_PropertiesID props = SDL_GetTextureProperties(metalTexture);
|
||||
if (props != 0) {
|
||||
const char* propertyNames[] = {
|
||||
"SDL.texture.metal.texture",
|
||||
"SDL.renderer.metal.texture",
|
||||
"metal.texture",
|
||||
"texture.metal",
|
||||
"MTLTexture",
|
||||
"texture"
|
||||
};
|
||||
|
||||
for (const char* propName : propertyNames) {
|
||||
gameCanvasTexture = (__bridge id<MTLTexture>)SDL_GetPointerProperty(props, propName, nullptr);
|
||||
if (gameCanvasTexture) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Successfully extracted Metal texture via property '%s' (size: %lux%lu)",
|
||||
propName, [gameCanvasTexture width], [gameCanvasTexture height]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!gameCanvasTexture) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Could not extract Metal texture from SDL texture - shaders may not work");
|
||||
}
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Created Metal render target texture (%dx%d)", width, height);
|
||||
return metalTexture;
|
||||
}
|
||||
|
||||
bool initMetal(SDL_Window* window, SDL_Texture* backBufferTexture, const std::string& shaderFilename) {
|
||||
// Store references
|
||||
win = window;
|
||||
backBuffer = backBufferTexture;
|
||||
renderer = SDL_GetRenderer(window);
|
||||
|
||||
if (!renderer) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL renderer");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get Metal layer from SDL renderer and extract device from it
|
||||
CAMetalLayer* metalLayer = (__bridge CAMetalLayer*)SDL_GetRenderMetalLayer(renderer);
|
||||
if (!metalLayer) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get Metal layer from SDL renderer");
|
||||
return false;
|
||||
}
|
||||
|
||||
device = metalLayer.device;
|
||||
if (!device) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get Metal device from layer");
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Got Metal device from SDL layer: %s", [[device name] UTF8String]);
|
||||
|
||||
// Note: We no longer need our own texture - we'll use the backBuffer directly
|
||||
|
||||
// Load and compile shaders
|
||||
std::string metalShaderSource = loadMetalShader(shaderFilename);
|
||||
if (metalShaderSource.empty()) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load Metal shader: %s", shaderFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Loaded Metal shader %s (length: %zu)",
|
||||
shaderFilename.c_str(), metalShaderSource.length());
|
||||
|
||||
NSString* shaderNSString = [NSString stringWithUTF8String:metalShaderSource.c_str()];
|
||||
NSError* error = nil;
|
||||
id<MTLLibrary> library = [device newLibraryWithSource:shaderNSString options:nil error:&error];
|
||||
if (!library || error) {
|
||||
if (error) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to compile Metal shader: %s",
|
||||
[[error localizedDescription] UTF8String]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"vertex_main"];
|
||||
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"fragment_main"];
|
||||
|
||||
if (!vertexFunction || !fragmentFunction) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load Metal shader functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create render pipeline
|
||||
MTLRenderPipelineDescriptor* pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||
pipelineDescriptor.vertexFunction = vertexFunction;
|
||||
pipelineDescriptor.fragmentFunction = fragmentFunction;
|
||||
pipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||
|
||||
// Set up vertex descriptor
|
||||
MTLVertexDescriptor* vertexDescriptor = [[MTLVertexDescriptor alloc] init];
|
||||
vertexDescriptor.attributes[0].format = MTLVertexFormatFloat4;
|
||||
vertexDescriptor.attributes[0].offset = 0;
|
||||
vertexDescriptor.attributes[0].bufferIndex = 0;
|
||||
vertexDescriptor.attributes[1].format = MTLVertexFormatFloat2;
|
||||
vertexDescriptor.attributes[1].offset = 4 * sizeof(float);
|
||||
vertexDescriptor.attributes[1].bufferIndex = 0;
|
||||
vertexDescriptor.layouts[0].stride = sizeof(Vertex);
|
||||
vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
|
||||
|
||||
pipelineDescriptor.vertexDescriptor = vertexDescriptor;
|
||||
|
||||
pipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];
|
||||
if (!pipelineState || error) {
|
||||
if (error) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create Metal render pipeline: %s",
|
||||
[[error localizedDescription] UTF8String]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create vertex buffer
|
||||
vertexBuffer = [device newBufferWithBytes:quadVertices
|
||||
length:sizeof(quadVertices)
|
||||
options:MTLResourceOptionCPUCacheModeDefault];
|
||||
|
||||
// Create sampler state for nearest neighbor filtering (pixelated look)
|
||||
MTLSamplerDescriptor* samplerDescriptor = [[MTLSamplerDescriptor alloc] init];
|
||||
samplerDescriptor.minFilter = MTLSamplerMinMagFilterNearest;
|
||||
samplerDescriptor.magFilter = MTLSamplerMinMagFilterNearest;
|
||||
samplerDescriptor.sAddressMode = MTLSamplerAddressModeClampToEdge;
|
||||
samplerDescriptor.tAddressMode = MTLSamplerAddressModeClampToEdge;
|
||||
|
||||
sampler = [device newSamplerStateWithDescriptor:samplerDescriptor];
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "** Metal shader system initialized successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
void updateMetalTexture(SDL_Texture* backBuffer) {
|
||||
if (!device || !backBuffer) return;
|
||||
|
||||
// Only log this occasionally to avoid spam
|
||||
static int attemptCount = 0;
|
||||
static bool hasLogged = false;
|
||||
|
||||
// Try multiple property names that SDL3 might use
|
||||
SDL_PropertiesID props = SDL_GetTextureProperties(backBuffer);
|
||||
if (props != 0) {
|
||||
const char* propertyNames[] = {
|
||||
"SDL.texture.metal.texture",
|
||||
"SDL.renderer.metal.texture",
|
||||
"metal.texture",
|
||||
"texture.metal",
|
||||
"MTLTexture",
|
||||
"texture"
|
||||
};
|
||||
|
||||
for (const char* propName : propertyNames) {
|
||||
id<MTLTexture> sdlMetalTexture = (__bridge id<MTLTexture>)SDL_GetPointerProperty(props, propName, nullptr);
|
||||
if (sdlMetalTexture) {
|
||||
backBufferTexture = sdlMetalTexture;
|
||||
if (!hasLogged) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Got Metal texture via property '%s' (size: %lux%lu)",
|
||||
propName, [backBufferTexture width], [backBufferTexture height]);
|
||||
hasLogged = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we can't get the texture after several attempts, log once and continue
|
||||
if (!hasLogged && attemptCount++ > 10) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Could not access SDL Metal texture after %d attempts - shader will be skipped", attemptCount);
|
||||
hasLogged = true;
|
||||
}
|
||||
}
|
||||
|
||||
void renderMetal() {
|
||||
if (!renderer || !device || !pipelineState) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Metal render failed: missing components");
|
||||
return;
|
||||
}
|
||||
|
||||
// Correct pipeline: backBuffer → Metal shaders → screen (no double rendering)
|
||||
|
||||
// Try to get the Metal texture directly from the SDL backBuffer texture
|
||||
updateMetalTexture(backBuffer);
|
||||
|
||||
if (!backBufferTexture) {
|
||||
static int fallbackLogCount = 0;
|
||||
if (fallbackLogCount++ < 3) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Metal texture not available - falling back to normal SDL rendering (attempt %d)", fallbackLogCount);
|
||||
}
|
||||
// Fallback: render without shaders using normal SDL path
|
||||
SDL_SetRenderTarget(renderer, nullptr);
|
||||
SDL_RenderTexture(renderer, backBuffer, nullptr, nullptr);
|
||||
SDL_RenderPresent(renderer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply Metal CRT shader directly: backBuffer texture → screen
|
||||
SDL_SetRenderTarget(renderer, nullptr);
|
||||
|
||||
// Get Metal command encoder to render directly to screen
|
||||
void* encoder_ptr = SDL_GetRenderMetalCommandEncoder(renderer);
|
||||
if (encoder_ptr) {
|
||||
id<MTLRenderCommandEncoder> encoder = (__bridge id<MTLRenderCommandEncoder>)encoder_ptr;
|
||||
|
||||
static int debugCount = 0;
|
||||
if (debugCount++ < 5) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Metal render attempt %d: encoder=%p, pipeline=%p, texture=%p",
|
||||
debugCount, encoder, pipelineState, backBufferTexture);
|
||||
}
|
||||
|
||||
// Apply CRT shader effect directly to backBuffer texture
|
||||
[encoder setRenderPipelineState:pipelineState];
|
||||
[encoder setVertexBuffer:vertexBuffer offset:0 atIndex:0];
|
||||
[encoder setFragmentTexture:backBufferTexture atIndex:0];
|
||||
[encoder setFragmentSamplerState:sampler atIndex:0];
|
||||
|
||||
// Draw fullscreen quad with CRT effect directly to screen
|
||||
[encoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||
|
||||
static int successCount = 0;
|
||||
if (successCount++ < 5) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Applied CRT shader to backBuffer (attempt %d) - texture size: %lux%lu",
|
||||
successCount, [backBufferTexture width], [backBufferTexture height]);
|
||||
}
|
||||
} else {
|
||||
// Fallback: render normally without shaders
|
||||
SDL_RenderTexture(renderer, backBuffer, nullptr, nullptr);
|
||||
|
||||
static int fallbackCount = 0;
|
||||
if (fallbackCount++ < 3) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Failed to get Metal command encoder - fallback rendering");
|
||||
}
|
||||
}
|
||||
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
void renderWithPostProcessing(SDL_Renderer* renderer, SDL_Texture* sourceTexture) {
|
||||
if (!renderer || !sourceTexture || !device || !pipelineState) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Metal post-processing failed: missing components");
|
||||
// Fallback: render normally without shaders
|
||||
SDL_SetRenderTarget(renderer, nullptr);
|
||||
SDL_RenderTexture(renderer, sourceTexture, nullptr, nullptr);
|
||||
SDL_RenderPresent(renderer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Use our stored Metal texture if available
|
||||
id<MTLTexture> metalTexture = gameCanvasTexture;
|
||||
|
||||
if (!metalTexture) {
|
||||
static int fallbackLogCount = 0;
|
||||
if (fallbackLogCount++ < 3) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "gameCanvasTexture not available - falling back to normal rendering (attempt %d)", fallbackLogCount);
|
||||
}
|
||||
// Fallback: render normally without shaders
|
||||
SDL_SetRenderTarget(renderer, nullptr);
|
||||
SDL_RenderTexture(renderer, sourceTexture, nullptr, nullptr);
|
||||
SDL_RenderPresent(renderer);
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply Metal CRT shader post-processing: sourceTexture → screen
|
||||
SDL_SetRenderTarget(renderer, nullptr);
|
||||
|
||||
// Get Metal command encoder to render directly to screen
|
||||
void* encoder_ptr = SDL_GetRenderMetalCommandEncoder(renderer);
|
||||
if (encoder_ptr) {
|
||||
id<MTLRenderCommandEncoder> encoder = (__bridge id<MTLRenderCommandEncoder>)encoder_ptr;
|
||||
|
||||
static int debugCount = 0;
|
||||
if (debugCount++ < 3) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Metal post-processing attempt %d: encoder=%p, pipeline=%p, texture=%p",
|
||||
debugCount, encoder, pipelineState, metalTexture);
|
||||
}
|
||||
|
||||
// Apply CRT shader effect to sourceTexture
|
||||
[encoder setRenderPipelineState:pipelineState];
|
||||
[encoder setVertexBuffer:vertexBuffer offset:0 atIndex:0];
|
||||
[encoder setFragmentTexture:metalTexture atIndex:0];
|
||||
[encoder setFragmentSamplerState:sampler atIndex:0];
|
||||
|
||||
// Draw fullscreen quad with CRT effect directly to screen
|
||||
[encoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||
|
||||
static int successCount = 0;
|
||||
if (successCount++ < 3) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Applied CRT post-processing (attempt %d) - texture size: %lux%lu",
|
||||
successCount, [metalTexture width], [metalTexture height]);
|
||||
}
|
||||
} else {
|
||||
// Fallback: render normally without shaders
|
||||
SDL_RenderTexture(renderer, sourceTexture, nullptr, nullptr);
|
||||
|
||||
static int fallbackCount = 0;
|
||||
if (fallbackCount++ < 3) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Failed to get Metal command encoder for post-processing - fallback rendering");
|
||||
}
|
||||
}
|
||||
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
void cleanupMetal() {
|
||||
// Release Metal objects (ARC handles most of this automatically)
|
||||
pipelineState = nullptr;
|
||||
backBufferTexture = nullptr;
|
||||
gameCanvasTexture = nullptr;
|
||||
vertexBuffer = nullptr;
|
||||
sampler = nullptr;
|
||||
device = nullptr;
|
||||
renderer = nullptr;
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Metal shader system cleaned up");
|
||||
}
|
||||
|
||||
} // namespace metal
|
||||
} // namespace shader
|
||||
|
||||
#endif // __APPLE__
|
||||
@@ -82,11 +82,6 @@ void Fade::update() {
|
||||
}
|
||||
}
|
||||
|
||||
// Compatibilidad delta-time (ignora el parámetro ya que usa SDL_GetTicks)
|
||||
void Fade::update(float delta_time) {
|
||||
update(); // Llama al método original
|
||||
}
|
||||
|
||||
void Fade::updatePreState() {
|
||||
// Sistema basado en tiempo únicamente
|
||||
Uint32 elapsed_time = SDL_GetTicks() - pre_start_time_;
|
||||
|
||||
@@ -37,11 +37,10 @@ class Fade {
|
||||
~Fade();
|
||||
|
||||
// --- Métodos principales ---
|
||||
void reset(); // Resetea variables para reutilizar el fade
|
||||
void render(); // Dibuja la transición en pantalla
|
||||
void update(); // Actualiza el estado interno (ya usa tiempo real)
|
||||
void update(float delta_time); // Compatibilidad delta-time (ignora el parámetro)
|
||||
void activate(); // Activa el fade
|
||||
void reset(); // Resetea variables para reutilizar el fade
|
||||
void render(); // Dibuja la transición en pantalla
|
||||
void update(); // Actualiza el estado interno
|
||||
void activate(); // Activa el fade
|
||||
|
||||
// --- Configuración ---
|
||||
void setColor(Uint8 r, Uint8 g, Uint8 b); // Establece el color RGB del fade
|
||||
|
||||
@@ -45,7 +45,6 @@ void GameLogo::init() {
|
||||
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);
|
||||
@@ -113,20 +112,13 @@ void GameLogo::render() {
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza la lógica de la clase (frame-based)
|
||||
// Actualiza la lógica de la clase
|
||||
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:
|
||||
@@ -143,22 +135,6 @@ void GameLogo::updateCoffeeCrisis() {
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
@@ -172,19 +148,6 @@ void GameLogo::updateArcadeEdition() {
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
@@ -195,16 +158,6 @@ void GameLogo::handleCoffeeCrisisMoving() {
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
@@ -215,24 +168,10 @@ void GameLogo::handleCoffeeCrisisShaking() {
|
||||
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_);
|
||||
@@ -242,16 +181,6 @@ void GameLogo::handleArcadeEditionMoving() {
|
||||
}
|
||||
}
|
||||
|
||||
void GameLogo::handleArcadeEditionMoving(float deltaTime) {
|
||||
// Convertir 0.1F * ZOOM_FACTOR por frame a por segundo (asumiendo 60fps)
|
||||
zoom_ -= (0.1F * ZOOM_FACTOR * 60.0F) * deltaTime;
|
||||
arcade_edition_sprite_->setZoom(zoom_);
|
||||
|
||||
if (zoom_ <= 1.0F) {
|
||||
finishArcadeEditionMoving();
|
||||
}
|
||||
}
|
||||
|
||||
void GameLogo::handleArcadeEditionShaking() {
|
||||
if (shake_.remaining > 0) {
|
||||
processArcadeEditionShake();
|
||||
@@ -261,15 +190,6 @@ void GameLogo::handleArcadeEditionShaking() {
|
||||
}
|
||||
}
|
||||
|
||||
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--;
|
||||
@@ -284,23 +204,6 @@ void GameLogo::processShakeEffect(SmartSprite* primary_sprite, SmartSprite* seco
|
||||
}
|
||||
}
|
||||
|
||||
void GameLogo::processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite, float deltaTime) {
|
||||
// Convertir delay (frames) a tiempo: delay frames = delay/60 segundos a 60fps
|
||||
float delayTime = static_cast<float>(shake_.delay) / 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--;
|
||||
@@ -312,20 +215,6 @@ void GameLogo::processArcadeEditionShake() {
|
||||
}
|
||||
}
|
||||
|
||||
void GameLogo::processArcadeEditionShake(float deltaTime) {
|
||||
// Convertir delay (frames) a tiempo: delay frames = delay/60 segundos a 60fps
|
||||
float delayTime = static_cast<float>(shake_.delay) / 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;
|
||||
}
|
||||
@@ -356,11 +245,6 @@ void GameLogo::updateDustSprites() {
|
||||
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 &&
|
||||
@@ -369,23 +253,6 @@ void GameLogo::updatePostFinishedCounter() {
|
||||
}
|
||||
}
|
||||
|
||||
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 = 1/60 segundos a 60fps
|
||||
float frameTime = 1.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();
|
||||
|
||||
@@ -16,10 +16,9 @@ class GameLogo {
|
||||
~GameLogo() = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
void render(); // Pinta la clase en pantalla
|
||||
void update(); // Actualiza la lógica de la clase (frame-based)
|
||||
void update(float deltaTime); // Actualiza la lógica de la clase (time-based)
|
||||
void enable(); // Activa la clase
|
||||
void render(); // Pinta la clase en pantalla
|
||||
void update(); // Actualiza la lógica de la clase
|
||||
void enable(); // Activa la clase
|
||||
|
||||
// --- Getters ---
|
||||
[[nodiscard]] auto hasFinished() const -> bool; // Indica si ha terminado la animación
|
||||
@@ -35,13 +34,12 @@ class GameLogo {
|
||||
|
||||
// --- Estructuras privadas ---
|
||||
struct Shake {
|
||||
int desp = 1; // Pixels de desplazamiento para agitar la pantalla en el eje x
|
||||
int delay = 2; // Retraso entre cada desplazamiento de la pantalla al agitarse (frame-based)
|
||||
int length = 8; // Cantidad de desplazamientos a realizar
|
||||
int remaining = length; // Cantidad de desplazamientos pendientes a realizar
|
||||
int counter = delay; // Contador para el retraso (frame-based)
|
||||
float time_accumulator = 0.0f; // Acumulador de tiempo para deltaTime
|
||||
int origin = 0; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
|
||||
int desp = 1; // Pixels de desplazamiento para agitar la pantalla en el eje x
|
||||
int delay = 2; // Retraso entre cada desplazamiento de la pantalla al agitarse
|
||||
int length = 8; // Cantidad de desplazamientos a realizar
|
||||
int remaining = length; // Cantidad de desplazamientos pendientes a realizar
|
||||
int counter = delay; // Contador para el retraso
|
||||
int origin = 0; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
|
||||
|
||||
Shake() = default;
|
||||
Shake(int d, int de, int l, int o)
|
||||
@@ -58,7 +56,6 @@ class GameLogo {
|
||||
length = l;
|
||||
remaining = l;
|
||||
counter = de;
|
||||
time_accumulator = 0.0f;
|
||||
origin = o;
|
||||
}
|
||||
};
|
||||
@@ -82,44 +79,32 @@ class GameLogo {
|
||||
float x_; // Posición X del logo
|
||||
float y_; // Posición Y del logo
|
||||
float zoom_ = 1.0F; // Zoom aplicado al texto "ARCADE EDITION"
|
||||
int post_finished_counter_ = 1; // Contador final tras animaciones (frame-based)
|
||||
float post_finished_time_accumulator_ = 0.0f; // Acumulador de tiempo para post_finished_counter
|
||||
int post_finished_counter_ = 1; // Contador final tras animaciones
|
||||
|
||||
// --- Inicialización ---
|
||||
void init(); // Inicializa las variables
|
||||
[[nodiscard]] auto getInitialVerticalDesp() const -> int; // Calcula el desplazamiento vertical inicial
|
||||
|
||||
// --- Actualización de estados específicos ---
|
||||
void updateCoffeeCrisis(); // Actualiza el estado de "Coffee Crisis" (frame-based)
|
||||
void updateCoffeeCrisis(float deltaTime); // Actualiza el estado de "Coffee Crisis" (time-based)
|
||||
void updateArcadeEdition(); // Actualiza el estado de "Arcade Edition" (frame-based)
|
||||
void updateArcadeEdition(float deltaTime); // Actualiza el estado de "Arcade Edition" (time-based)
|
||||
void updatePostFinishedCounter(); // Actualiza el contador tras finalizar una animación (frame-based)
|
||||
void updatePostFinishedCounter(float deltaTime); // Actualiza el contador tras finalizar una animación (time-based)
|
||||
void updateCoffeeCrisis(); // Actualiza el estado de "Coffee Crisis"
|
||||
void updateArcadeEdition(); // Actualiza el estado de "Arcade Edition"
|
||||
void updatePostFinishedCounter(); // Actualiza el contador tras finalizar una animación
|
||||
|
||||
// --- Efectos visuales: movimiento y sacudidas ---
|
||||
void handleCoffeeCrisisMoving(); // Maneja el movimiento de "Coffee Crisis" (frame-based)
|
||||
void handleCoffeeCrisisMoving(float deltaTime); // Maneja el movimiento de "Coffee Crisis" (time-based)
|
||||
void handleCoffeeCrisisShaking(); // Maneja la sacudida de "Coffee Crisis" (frame-based)
|
||||
void handleCoffeeCrisisShaking(float deltaTime); // Maneja la sacudida de "Coffee Crisis" (time-based)
|
||||
void handleArcadeEditionMoving(); // Maneja el movimiento de "Arcade Edition" (frame-based)
|
||||
void handleArcadeEditionMoving(float deltaTime); // Maneja el movimiento de "Arcade Edition" (time-based)
|
||||
void handleArcadeEditionShaking(); // Maneja la sacudida de "Arcade Edition" (frame-based)
|
||||
void handleArcadeEditionShaking(float deltaTime); // Maneja la sacudida de "Arcade Edition" (time-based)
|
||||
void processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite = nullptr); // Procesa el efecto de sacudida en sprites (frame-based)
|
||||
void processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite, float deltaTime); // Procesa el efecto de sacudida en sprites (time-based)
|
||||
void processArcadeEditionShake(); // Procesa la sacudida específica de "Arcade Edition" (frame-based)
|
||||
void processArcadeEditionShake(float deltaTime); // Procesa la sacudida específica de "Arcade Edition" (time-based)
|
||||
[[nodiscard]] auto calculateShakeDisplacement() const -> int; // Calcula el desplazamiento de la sacudida
|
||||
void handleCoffeeCrisisMoving(); // Maneja el movimiento de "Coffee Crisis"
|
||||
void handleCoffeeCrisisShaking(); // Maneja la sacudida de "Coffee Crisis"
|
||||
void handleArcadeEditionMoving(); // Maneja el movimiento de "Arcade Edition"
|
||||
void handleArcadeEditionShaking(); // Maneja la sacudida de "Arcade Edition"
|
||||
void processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite = nullptr); // Procesa el efecto de sacudida en sprites
|
||||
void processArcadeEditionShake(); // Procesa la sacudida específica de "Arcade Edition"
|
||||
[[nodiscard]] auto calculateShakeDisplacement() const -> int; // Calcula el desplazamiento de la sacudida
|
||||
|
||||
// --- Gestión de finalización de efectos ---
|
||||
void handleCoffeeCrisisFinished(); // Maneja el final de la animación "Coffee Crisis" (frame-based)
|
||||
void handleCoffeeCrisisFinished(float deltaTime); // Maneja el final de la animación "Coffee Crisis" (time-based)
|
||||
void finishCoffeeCrisisShaking(); // Finaliza la sacudida de "Coffee Crisis"
|
||||
void finishArcadeEditionMoving(); // Finaliza el movimiento de "Arcade Edition"
|
||||
void handleCoffeeCrisisFinished(); // Maneja el final de la animación "Coffee Crisis"
|
||||
void finishCoffeeCrisisShaking(); // Finaliza la sacudida de "Coffee Crisis"
|
||||
void finishArcadeEditionMoving(); // Finaliza el movimiento de "Arcade Edition"
|
||||
|
||||
// --- Utilidades ---
|
||||
static void playTitleEffects(); // Reproduce efectos visuales/sonoros del título
|
||||
void updateDustSprites(); // Actualiza los sprites de polvo (frame-based)
|
||||
void updateDustSprites(float deltaTime); // Actualiza los sprites de polvo (time-based)
|
||||
static void playTitleEffects(); // Reproduce efectos visuales/sonoros del título
|
||||
void updateDustSprites(); // Actualiza los sprites de polvo
|
||||
};
|
||||
@@ -53,7 +53,7 @@ void MovingSprite::stop() {
|
||||
flip_ = SDL_FLIP_NONE; // Establece como se ha de voltear el sprite
|
||||
}
|
||||
|
||||
// Mueve el sprite (frame-based)
|
||||
// Mueve el sprite
|
||||
void MovingSprite::move() {
|
||||
x_ += vx_;
|
||||
y_ += vy_;
|
||||
@@ -65,34 +65,16 @@ void MovingSprite::move() {
|
||||
pos_.y = static_cast<int>(y_);
|
||||
}
|
||||
|
||||
// Mueve el sprite (time-based)
|
||||
void MovingSprite::move(float deltaTime) {
|
||||
x_ += vx_ * deltaTime;
|
||||
y_ += vy_ * deltaTime;
|
||||
|
||||
vx_ += ax_ * deltaTime;
|
||||
vy_ += ay_ * deltaTime;
|
||||
|
||||
pos_.x = static_cast<int>(x_);
|
||||
pos_.y = static_cast<int>(y_);
|
||||
}
|
||||
|
||||
// Actualiza las variables internas del objeto (frame-based)
|
||||
// Actualiza las variables internas del objeto
|
||||
void MovingSprite::update() {
|
||||
move();
|
||||
rotate();
|
||||
}
|
||||
|
||||
// Actualiza las variables internas del objeto (time-based)
|
||||
void MovingSprite::update(float deltaTime) {
|
||||
move(deltaTime);
|
||||
rotate(deltaTime);
|
||||
}
|
||||
|
||||
// Muestra el sprite por pantalla
|
||||
void MovingSprite::render() { getTexture()->render(pos_.x, pos_.y, &sprite_clip_, horizontal_zoom_, vertical_zoom_, rotate_.angle, &rotate_.center, flip_); }
|
||||
|
||||
// Establece la rotacion (frame-based)
|
||||
// Establece la rotacion
|
||||
void MovingSprite::rotate() {
|
||||
if (rotate_.enabled) {
|
||||
++rotate_.counter;
|
||||
@@ -103,15 +85,6 @@ void MovingSprite::rotate() {
|
||||
}
|
||||
}
|
||||
|
||||
// Establece la rotacion (time-based)
|
||||
void MovingSprite::rotate(float deltaTime) {
|
||||
if (rotate_.enabled) {
|
||||
// Convertir speed (frames) a tiempo: speed frames = speed/60 segundos a 60fps
|
||||
float rotationSpeed = static_cast<float>(rotate_.speed) / 60.0f;
|
||||
rotate_.angle += rotate_.amount * (deltaTime / rotationSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
// Activa o desactiva el efecto de rotación
|
||||
void MovingSprite::setRotate(bool enable) {
|
||||
rotate_.enabled = enable;
|
||||
|
||||
@@ -29,11 +29,10 @@ class MovingSprite : public Sprite {
|
||||
~MovingSprite() override = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
virtual void update(); // Actualiza las variables internas del objeto (frame-based)
|
||||
virtual void update(float deltaTime); // Actualiza las variables internas del objeto (time-based)
|
||||
void clear() override; // Reinicia todas las variables a cero
|
||||
void stop(); // Elimina el movimiento del sprite
|
||||
void render() override; // Muestra el sprite por pantalla
|
||||
virtual void update(); // Actualiza las variables internas del objeto
|
||||
void clear() override; // Reinicia todas las variables a cero
|
||||
void stop(); // Elimina el movimiento del sprite
|
||||
void render() override; // Muestra el sprite por pantalla
|
||||
|
||||
// --- Configuración ---
|
||||
void setPos(SDL_FRect rect); // Establece la posición y el tamaño del objeto
|
||||
@@ -80,8 +79,6 @@ class MovingSprite : public Sprite {
|
||||
|
||||
// --- Métodos internos ---
|
||||
void updateAngle() { rotate_.angle += rotate_.amount; } // Incrementa el valor del ángulo
|
||||
void move(); // Mueve el sprite según velocidad y aceleración (frame-based)
|
||||
void move(float deltaTime); // Mueve el sprite según velocidad y aceleración (time-based)
|
||||
void rotate(); // Rota el sprite según los parámetros de rotación (frame-based)
|
||||
void rotate(float deltaTime); // Rota el sprite según los parámetros de rotación (time-based)
|
||||
void move(); // Mueve el sprite según velocidad y aceleración
|
||||
void rotate(); // Rota el sprite según los parámetros de rotación
|
||||
};
|
||||
@@ -4,13 +4,6 @@
|
||||
#include <functional> // Para function
|
||||
#include <utility> // Para move
|
||||
|
||||
// Constructor para paths por puntos (compatibilidad)
|
||||
Path::Path(const std::vector<SDL_FPoint> &spots_init, int waiting_counter_init)
|
||||
: spots(spots_init), is_point_path(true) {
|
||||
constexpr float FRAME_TIME_MS = 1000.0f / 60.0f;
|
||||
waiting_time_ms = static_cast<float>(waiting_counter_init) * FRAME_TIME_MS;
|
||||
}
|
||||
|
||||
// Devuelve un vector con los puntos que conforman la ruta
|
||||
auto createPath(float start, float end, PathType type, float fixed_pos, int steps, const std::function<double(double)> &easing_function) -> std::vector<SDL_FPoint> {
|
||||
std::vector<SDL_FPoint> v;
|
||||
@@ -39,16 +32,10 @@ auto createPath(float start, float end, PathType type, float fixed_pos, int step
|
||||
return v;
|
||||
}
|
||||
|
||||
// Actualiza la posición y comprueba si ha llegado a su destino (compatibilidad)
|
||||
void PathSprite::update() {
|
||||
constexpr float FRAME_TIME_MS = 1000.0f / 60.0f; // 16.67ms por frame a 60 FPS
|
||||
update(FRAME_TIME_MS);
|
||||
}
|
||||
|
||||
// Actualiza la posición y comprueba si ha llegado a su destino
|
||||
void PathSprite::update(float delta_time) {
|
||||
void PathSprite::update() {
|
||||
if (enabled_ && !has_finished_) {
|
||||
moveThroughCurrentPath(delta_time);
|
||||
moveThroughCurrentPath();
|
||||
goToNextPathOrDie();
|
||||
}
|
||||
}
|
||||
@@ -92,13 +79,7 @@ void PathSprite::addPath(Path path, bool centered) {
|
||||
|
||||
// Añade un recorrido
|
||||
void PathSprite::addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easing_function, int waiting_counter) {
|
||||
// Convertir frames a milisegundos
|
||||
constexpr float FRAME_TIME_MS = 1000.0f / 60.0f;
|
||||
float duration_ms = static_cast<float>(steps) * FRAME_TIME_MS;
|
||||
float waiting_ms = static_cast<float>(waiting_counter) * FRAME_TIME_MS;
|
||||
|
||||
paths_.emplace_back(static_cast<float>(start), static_cast<float>(end), type, static_cast<float>(fixed_pos),
|
||||
duration_ms, waiting_ms, easing_function);
|
||||
paths_.emplace_back(createPath(start, end, type, fixed_pos, steps, easing_function), waiting_counter);
|
||||
}
|
||||
|
||||
// Añade un recorrido
|
||||
@@ -114,78 +95,35 @@ void PathSprite::enable() {
|
||||
|
||||
enabled_ = true;
|
||||
|
||||
// Establece la posición inicial
|
||||
// Establece la posición
|
||||
auto &path = paths_.at(current_path_);
|
||||
if (path.is_point_path) {
|
||||
const auto &p = path.spots.at(path.counter);
|
||||
setPosition(p);
|
||||
} else {
|
||||
// Para paths generados, establecer posición inicial
|
||||
SDL_FPoint initial_pos;
|
||||
if (path.type == PathType::HORIZONTAL) {
|
||||
initial_pos = {path.start_pos, path.fixed_pos};
|
||||
} else {
|
||||
initial_pos = {path.fixed_pos, path.start_pos};
|
||||
}
|
||||
setPosition(initial_pos);
|
||||
}
|
||||
const auto &p = path.spots.at(path.counter);
|
||||
setPosition(p);
|
||||
}
|
||||
|
||||
// Coloca el sprite en los diferentes puntos del recorrido
|
||||
void PathSprite::moveThroughCurrentPath(float delta_time) {
|
||||
void PathSprite::moveThroughCurrentPath() {
|
||||
auto &path = paths_.at(current_path_);
|
||||
|
||||
if (path.is_point_path) {
|
||||
// Lógica para paths por puntos (compatibilidad)
|
||||
const auto &p = path.spots.at(path.counter);
|
||||
setPosition(p);
|
||||
// Establece la posición
|
||||
const auto &p = path.spots.at(path.counter);
|
||||
setPosition(p);
|
||||
|
||||
if (!path.on_destination) {
|
||||
++path.counter;
|
||||
if (path.counter >= static_cast<int>(path.spots.size())) {
|
||||
path.on_destination = true;
|
||||
path.counter = static_cast<int>(path.spots.size()) - 1;
|
||||
}
|
||||
// Comprobar si ha terminado el recorrido
|
||||
if (!path.on_destination) {
|
||||
++path.counter;
|
||||
if (path.counter >= static_cast<int>(path.spots.size())) {
|
||||
path.on_destination = true;
|
||||
path.counter = static_cast<int>(path.spots.size()) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (path.on_destination) {
|
||||
path.waiting_elapsed += delta_time;
|
||||
if (path.waiting_elapsed >= path.waiting_time_ms) {
|
||||
path.finished = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Lógica para paths generados en tiempo real
|
||||
if (!path.on_destination) {
|
||||
path.elapsed_time += delta_time;
|
||||
|
||||
// Calcular progreso (0.0 a 1.0)
|
||||
float progress = path.elapsed_time / path.duration_ms;
|
||||
if (progress >= 1.0f) {
|
||||
progress = 1.0f;
|
||||
path.on_destination = true;
|
||||
}
|
||||
|
||||
// Aplicar función de easing
|
||||
double eased_progress = path.easing_function(progress);
|
||||
|
||||
// Calcular posición actual
|
||||
float current_pos = path.start_pos + (path.end_pos - path.start_pos) * static_cast<float>(eased_progress);
|
||||
|
||||
// Establecer posición según el tipo
|
||||
SDL_FPoint position;
|
||||
if (path.type == PathType::HORIZONTAL) {
|
||||
position = {current_pos, path.fixed_pos};
|
||||
} else {
|
||||
position = {path.fixed_pos, current_pos};
|
||||
}
|
||||
setPosition(position);
|
||||
// Comprobar si ha terminado la espera
|
||||
if (path.on_destination) {
|
||||
if (path.waiting_counter == 0) {
|
||||
path.finished = true;
|
||||
} else {
|
||||
// Esperar en destino
|
||||
path.waiting_elapsed += delta_time;
|
||||
if (path.waiting_elapsed >= path.waiting_time_ms) {
|
||||
path.finished = true;
|
||||
}
|
||||
--path.waiting_counter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,31 +24,17 @@ enum class PathCentered { // Centrado del recorrido
|
||||
};
|
||||
|
||||
// --- Estructuras ---
|
||||
struct Path { // Define un recorrido para el sprite
|
||||
float start_pos; // Posición inicial
|
||||
float end_pos; // Posición final
|
||||
PathType type; // Tipo de movimiento (horizontal/vertical)
|
||||
float fixed_pos; // Posición fija en el eje contrario
|
||||
float duration_ms; // Duración de la animación en milisegundos
|
||||
float waiting_time_ms; // Tiempo de espera una vez en el destino
|
||||
std::function<double(double)> easing_function; // Función de easing
|
||||
float elapsed_time = 0.0f; // Tiempo transcurrido
|
||||
float waiting_elapsed = 0.0f; // Tiempo de espera transcurrido
|
||||
bool on_destination = false; // Indica si ha llegado al destino
|
||||
bool finished = false; // Indica si ha terminado de esperarse
|
||||
struct Path { // Define un recorrido para el sprite
|
||||
std::vector<SDL_FPoint> spots; // Puntos por los que se desplazará el sprite
|
||||
int waiting_counter; // Tiempo de espera una vez en el destino
|
||||
bool on_destination = false; // Indica si ha llegado al destino
|
||||
bool finished = false; // Indica si ha terminado de esperarse
|
||||
int counter = 0; // Contador interno
|
||||
|
||||
// Constructor para paths generados
|
||||
Path(float start, float end, PathType path_type, float fixed, float duration, float waiting, std::function<double(double)> easing)
|
||||
: start_pos(start), end_pos(end), type(path_type), fixed_pos(fixed),
|
||||
duration_ms(duration), waiting_time_ms(waiting), easing_function(std::move(easing)) {}
|
||||
|
||||
// Constructor para paths por puntos (mantenemos compatibilidad)
|
||||
Path(const std::vector<SDL_FPoint> &spots_init, int waiting_counter_init);
|
||||
|
||||
// Variables para paths por puntos
|
||||
std::vector<SDL_FPoint> spots; // Solo para paths por puntos
|
||||
int counter = 0; // Solo para paths por puntos
|
||||
bool is_point_path = false; // Indica si es un path por puntos
|
||||
// Constructor
|
||||
Path(const std::vector<SDL_FPoint> &spots_init, int waiting_counter_init)
|
||||
: spots(spots_init),
|
||||
waiting_counter(waiting_counter_init) {}
|
||||
};
|
||||
|
||||
// --- Funciones ---
|
||||
@@ -63,8 +49,7 @@ class PathSprite : public Sprite {
|
||||
~PathSprite() override = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
void update(); // Actualiza la posición del sprite según el recorrido (compatibilidad)
|
||||
void update(float delta_time); // Actualiza la posición del sprite según el recorrido
|
||||
void update(); // Actualiza la posición del sprite según el recorrido
|
||||
void render() override; // Muestra el sprite por pantalla
|
||||
|
||||
// --- Gestión de recorridos ---
|
||||
@@ -87,6 +72,6 @@ class PathSprite : public Sprite {
|
||||
std::vector<Path> paths_; // Caminos a recorrer por el sprite
|
||||
|
||||
// --- Métodos internos ---
|
||||
void moveThroughCurrentPath(float delta_time); // Coloca el sprite en los diferentes puntos del recorrido
|
||||
void moveThroughCurrentPath(); // Coloca el sprite en los diferentes puntos del recorrido
|
||||
void goToNextPathOrDie(); // Cambia de recorrido o finaliza
|
||||
};
|
||||
@@ -44,8 +44,21 @@ Screen::Screen()
|
||||
initSDLVideo();
|
||||
|
||||
// Crea la textura de destino
|
||||
#ifdef __APPLE__
|
||||
const auto render_name = SDL_GetRendererName(renderer_);
|
||||
if (render_name && !strncmp(render_name, "metal", 5)) {
|
||||
// Usar nuestra propia Metal texture como render target
|
||||
game_canvas_ = shader::metal::createMetalRenderTarget(renderer_, param.game.width, param.game.height);
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Using custom Metal render target for game_canvas_");
|
||||
} else {
|
||||
// Fallback para otros renderers
|
||||
game_canvas_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);
|
||||
SDL_SetTextureScaleMode(game_canvas_, SDL_SCALEMODE_NEAREST);
|
||||
}
|
||||
#else
|
||||
game_canvas_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);
|
||||
SDL_SetTextureScaleMode(game_canvas_, SDL_SCALEMODE_NEAREST);
|
||||
#endif
|
||||
|
||||
// Crea el objeto de texto
|
||||
createText();
|
||||
@@ -99,7 +112,18 @@ void Screen::renderPresent() {
|
||||
clean();
|
||||
|
||||
if (Options::video.shaders) {
|
||||
#ifdef __APPLE__
|
||||
const auto render_name = SDL_GetRendererName(renderer_);
|
||||
if (render_name && !strncmp(render_name, "metal", 5)) {
|
||||
// Use Metal post-processing with our custom render target
|
||||
shader::metal::renderWithPostProcessing(renderer_, game_canvas_);
|
||||
} else {
|
||||
// Fallback to standard shader system for non-Metal renderers
|
||||
shader::render();
|
||||
}
|
||||
#else
|
||||
shader::render();
|
||||
#endif
|
||||
} else {
|
||||
SDL_RenderTexture(renderer_, game_canvas_, nullptr, nullptr);
|
||||
SDL_RenderPresent(renderer_);
|
||||
@@ -296,17 +320,29 @@ auto Screen::initSDLVideo() -> bool {
|
||||
// Obtener información de la pantalla
|
||||
getDisplayInfo();
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Configurar hint para Metal
|
||||
if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal")) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Warning: Failed to set Metal hint!");
|
||||
}
|
||||
// Configurar flags para la creación de la ventana
|
||||
SDL_WindowFlags window_flags = SDL_WINDOW_METAL;
|
||||
#else // NOT APPLE
|
||||
// Configurar hint para OpenGL
|
||||
if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl")) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Warning: Failed to set OpenGL hint!");
|
||||
}
|
||||
|
||||
// Crear ventana
|
||||
// Configurar flags para la creación de la ventana
|
||||
SDL_WindowFlags window_flags = SDL_WINDOW_OPENGL;
|
||||
#endif
|
||||
// Configurar flags para la creación de la ventana
|
||||
if (Options::video.fullscreen) {
|
||||
window_flags |= SDL_WINDOW_FULLSCREEN;
|
||||
}
|
||||
|
||||
// Crear ventana
|
||||
window_ = SDL_CreateWindow(
|
||||
Options::window.caption.c_str(),
|
||||
param.game.width * Options::window.zoom,
|
||||
|
||||
@@ -33,7 +33,7 @@ HiScoreTable::HiScoreTable()
|
||||
backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
|
||||
fade_(std::make_unique<Fade>()),
|
||||
background_(std::make_unique<Background>()),
|
||||
last_time_(0),
|
||||
ticks_(0),
|
||||
view_area_(SDL_FRect{0, 0, param.game.width, param.game.height}),
|
||||
fade_mode_(Fade::Mode::IN),
|
||||
background_fade_color_(Color(0, 0, 0)) {
|
||||
@@ -53,14 +53,17 @@ HiScoreTable::~HiScoreTable() {
|
||||
}
|
||||
|
||||
// Actualiza las variables
|
||||
void HiScoreTable::update(float delta_time) {
|
||||
Screen::get()->update(); // Actualiza el objeto screen
|
||||
void HiScoreTable::update() {
|
||||
if (SDL_GetTicks() - ticks_ > param.game.speed) {
|
||||
ticks_ = SDL_GetTicks(); // Actualiza el contador de ticks
|
||||
Screen::get()->update(); // Actualiza el objeto screen
|
||||
|
||||
updateSprites(delta_time); // Actualiza las posiciones de los sprites de texto
|
||||
background_->update(delta_time); // Actualiza el fondo
|
||||
updateFade(delta_time); // Gestiona el fade
|
||||
updateCounter(); // Gestiona el contador y sus eventos
|
||||
fillTexture(); // Dibuja los sprites en la textura
|
||||
updateSprites(); // Actualiza las posiciones de los sprites de texto
|
||||
background_->update(); // Actualiza el fondo
|
||||
updateFade(); // Gestiona el fade
|
||||
updateCounter(); // Gestiona el contador y sus eventos
|
||||
fillTexture(); // Dibuja los sprites en la textura
|
||||
}
|
||||
|
||||
Audio::update();
|
||||
}
|
||||
@@ -114,32 +117,20 @@ void HiScoreTable::checkInput() {
|
||||
GlobalInputs::check();
|
||||
}
|
||||
|
||||
// Calcula el tiempo transcurrido desde el último frame
|
||||
float HiScoreTable::calculateDeltaTime() {
|
||||
const Uint64 current_time = SDL_GetTicks();
|
||||
const float delta_time = static_cast<float>(current_time - last_time_);
|
||||
last_time_ = current_time;
|
||||
return delta_time;
|
||||
}
|
||||
|
||||
// Bucle para la pantalla de instrucciones
|
||||
void HiScoreTable::run() {
|
||||
last_time_ = SDL_GetTicks();
|
||||
Audio::get()->playMusic("title.ogg");
|
||||
|
||||
while (Section::name == Section::Name::HI_SCORE_TABLE) {
|
||||
const float delta_time = calculateDeltaTime();
|
||||
|
||||
checkInput();
|
||||
update(delta_time);
|
||||
update();
|
||||
checkEvents(); // Tiene que ir antes del render
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
// Gestiona el fade
|
||||
void HiScoreTable::updateFade(float delta_time) {
|
||||
fade_->update(delta_time);
|
||||
void HiScoreTable::updateFade() {
|
||||
fade_->update();
|
||||
|
||||
if (fade_->hasEnded() && fade_mode_ == Fade::Mode::IN) {
|
||||
fade_->reset();
|
||||
@@ -258,7 +249,7 @@ void HiScoreTable::createSprites() {
|
||||
}
|
||||
|
||||
// Actualiza las posiciones de los sprites de texto
|
||||
void HiScoreTable::updateSprites(float delta_time) {
|
||||
void HiScoreTable::updateSprites() {
|
||||
constexpr int INIT_COUNTER = 190;
|
||||
const int COUNTER_BETWEEN_ENTRIES = 16;
|
||||
if (counter_ >= INIT_COUNTER) {
|
||||
@@ -271,7 +262,7 @@ void HiScoreTable::updateSprites(float delta_time) {
|
||||
}
|
||||
}
|
||||
for (auto const &entry : entry_names_) {
|
||||
entry->update(delta_time);
|
||||
entry->update();
|
||||
}
|
||||
|
||||
glowEntryNames();
|
||||
|
||||
@@ -45,27 +45,26 @@ class HiScoreTable {
|
||||
|
||||
// --- Variables ---
|
||||
Uint16 counter_ = 0; // Contador
|
||||
Uint64 last_time_ = 0; // Último timestamp para calcular delta-time
|
||||
Uint64 ticks_; // Contador de ticks para ajustar la velocidad del programa
|
||||
SDL_FRect view_area_; // Parte de la textura que se muestra en pantalla
|
||||
Fade::Mode fade_mode_; // Modo de fade a utilizar
|
||||
Color background_fade_color_; // Color de atenuación del fondo
|
||||
std::vector<Color> entry_colors_; // Colores para destacar las entradas en la tabla
|
||||
|
||||
// --- Métodos internos ---
|
||||
void update(float delta_time); // Actualiza las variables
|
||||
void update(); // Actualiza las variables
|
||||
void render(); // Pinta en pantalla
|
||||
static void checkEvents(); // Comprueba los eventos
|
||||
static void checkInput(); // Comprueba las entradas
|
||||
static auto format(int number) -> std::string; // Convierte un entero a un string con separadores de miles
|
||||
void fillTexture(); // Dibuja los sprites en la textura
|
||||
void updateFade(float delta_time); // Gestiona el fade
|
||||
void updateFade(); // Gestiona el fade
|
||||
void createSprites(); // Crea los sprites con los textos
|
||||
void updateSprites(float delta_time); // Actualiza las posiciones de los sprites de texto
|
||||
void updateSprites(); // Actualiza las posiciones de los sprites de texto
|
||||
void initFade(); // Inicializa el fade
|
||||
void initBackground(); // Inicializa el fondo
|
||||
auto getEntryColor(int counter) -> Color; // Obtiene un color del vector de colores de entradas
|
||||
void iniEntryColors(); // Inicializa los colores de las entradas
|
||||
void glowEntryNames(); // Hace brillar los nombres de la tabla de records
|
||||
void updateCounter(); // Gestiona el contador
|
||||
float calculateDeltaTime(); // Calcula el tiempo transcurrido desde el último frame
|
||||
};
|
||||
@@ -204,15 +204,18 @@ void Instructions::fillBackbuffer() {
|
||||
}
|
||||
|
||||
// Actualiza las variables
|
||||
void Instructions::update(float delta_time) {
|
||||
Screen::get()->update(); // Actualiza el objeto screen
|
||||
void Instructions::update() {
|
||||
if (SDL_GetTicks() - ticks_ > param.game.speed) {
|
||||
ticks_ = SDL_GetTicks(); // Actualiza el contador de ticks
|
||||
Screen::get()->update(); // Actualiza el objeto screen
|
||||
|
||||
counter_++; // Incrementa el contador
|
||||
updateSprites(); // Actualiza los sprites
|
||||
updateBackbuffer(); // Gestiona la textura con los graficos
|
||||
tiled_bg_->update(delta_time); // Actualiza el mosaico de fondo
|
||||
fade_->update(delta_time); // Actualiza el objeto "fade"
|
||||
fillBackbuffer(); // Rellena el backbuffer
|
||||
counter_++; // Incrementa el contador
|
||||
updateSprites(); // Actualiza los sprites
|
||||
updateBackbuffer(); // Gestiona la textura con los graficos
|
||||
tiled_bg_->update(); // Actualiza el mosaico de fondo
|
||||
fade_->update(); // Actualiza el objeto "fade"
|
||||
fillBackbuffer(); // Rellena el backbuffer
|
||||
}
|
||||
|
||||
Audio::update();
|
||||
}
|
||||
@@ -252,24 +255,12 @@ void Instructions::checkInput() {
|
||||
GlobalInputs::check();
|
||||
}
|
||||
|
||||
// Calcula el tiempo transcurrido desde el último frame
|
||||
float Instructions::calculateDeltaTime() {
|
||||
const Uint64 current_time = SDL_GetTicks();
|
||||
const float delta_time = static_cast<float>(current_time - last_time_);
|
||||
last_time_ = current_time;
|
||||
return delta_time;
|
||||
}
|
||||
|
||||
// Bucle para la pantalla de instrucciones
|
||||
void Instructions::run() {
|
||||
last_time_ = SDL_GetTicks();
|
||||
Audio::get()->playMusic("title.ogg");
|
||||
|
||||
while (Section::name == Section::Name::INSTRUCTIONS) {
|
||||
const float delta_time = calculateDeltaTime();
|
||||
|
||||
checkInput();
|
||||
update(delta_time);
|
||||
update();
|
||||
checkEvents(); // Tiene que ir antes del render
|
||||
render();
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ class Instructions {
|
||||
|
||||
// --- Variables ---
|
||||
int counter_ = 0; // Contador para manejar el progreso en la pantalla de instrucciones
|
||||
Uint64 last_time_ = 0; // Último timestamp para calcular delta-time
|
||||
Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
SDL_FRect view_; // Vista del backbuffer que se va a mostrar por pantalla
|
||||
SDL_FPoint sprite_pos_ = {0, 0}; // Posición del primer sprite en la lista
|
||||
float item_space_ = 2.0; // Espacio entre los items en pantalla
|
||||
@@ -73,7 +73,7 @@ class Instructions {
|
||||
bool start_delay_triggered_ = false; // Bandera para determinar si el retraso ha comenzado
|
||||
|
||||
// --- Métodos internos ---
|
||||
void update(float delta_time); // Actualiza las variables
|
||||
void update(); // Actualiza las variables
|
||||
void render(); // Pinta en pantalla
|
||||
static void checkEvents(); // Comprueba los eventos
|
||||
static void checkInput(); // Comprueba las entradas
|
||||
@@ -82,8 +82,7 @@ class Instructions {
|
||||
void iniSprites(); // Inicializa los sprites de los items
|
||||
void updateSprites(); // Actualiza los sprites
|
||||
static auto initializeLines(int height) -> std::vector<Line>; // Inicializa las líneas animadas
|
||||
static auto moveLines(std::vector<Line> &lines, int width, float duration, Uint32 start_delay) -> bool; // Mueve las líneas (ya usa tiempo real)
|
||||
static auto moveLines(std::vector<Line> &lines, int width, float duration, Uint32 start_delay) -> bool; // Mueve las líneas
|
||||
static void renderLines(SDL_Renderer *renderer, SDL_Texture *texture, const std::vector<Line> &lines); // Renderiza las líneas
|
||||
void updateBackbuffer(); // Gestiona la textura con los gráficos
|
||||
float calculateDeltaTime(); // Calcula el tiempo transcurrido desde el último frame
|
||||
};
|
||||
@@ -207,21 +207,24 @@ void Intro::switchText(int from_index, int to_index) {
|
||||
}
|
||||
|
||||
// Actualiza las variables del objeto
|
||||
void Intro::update(float delta_time) {
|
||||
Screen::get()->update(); // Actualiza el objeto screen
|
||||
void Intro::update() {
|
||||
if (SDL_GetTicks() - ticks_ > param.game.speed) {
|
||||
ticks_ = SDL_GetTicks(); // Actualiza el contador de ticks
|
||||
Screen::get()->update(); // Actualiza el objeto screen
|
||||
|
||||
tiled_bg_->update(delta_time); // Actualiza el fondo
|
||||
tiled_bg_->update(); // Actualiza el fondo
|
||||
|
||||
switch (state_) {
|
||||
case State::SCENES:
|
||||
updateSprites(delta_time);
|
||||
updateTexts(delta_time);
|
||||
updateScenes();
|
||||
break;
|
||||
switch (state_) {
|
||||
case State::SCENES:
|
||||
updateSprites();
|
||||
updateTexts();
|
||||
updateScenes();
|
||||
break;
|
||||
|
||||
case State::POST:
|
||||
updatePostState();
|
||||
break;
|
||||
case State::POST:
|
||||
updatePostState();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Audio::update();
|
||||
@@ -250,24 +253,12 @@ void Intro::render() {
|
||||
SCREEN->render(); // Vuelca el contenido del renderizador en pantalla
|
||||
}
|
||||
|
||||
// Calcula el tiempo transcurrido desde el último frame
|
||||
float Intro::calculateDeltaTime() {
|
||||
const Uint64 current_time = SDL_GetTicks();
|
||||
const float delta_time = static_cast<float>(current_time - last_time_);
|
||||
last_time_ = current_time;
|
||||
return delta_time;
|
||||
}
|
||||
|
||||
// Bucle principal
|
||||
void Intro::run() {
|
||||
last_time_ = SDL_GetTicks();
|
||||
Audio::get()->playMusic("intro.ogg", 0);
|
||||
|
||||
while (Section::name == Section::Name::INTRO) {
|
||||
const float delta_time = calculateDeltaTime();
|
||||
|
||||
checkInput();
|
||||
update(delta_time);
|
||||
update();
|
||||
checkEvents(); // Tiene que ir antes del render
|
||||
render();
|
||||
}
|
||||
@@ -453,20 +444,20 @@ void Intro::initTexts() {
|
||||
}
|
||||
|
||||
// Actualiza los sprites
|
||||
void Intro::updateSprites(float delta_time) {
|
||||
void Intro::updateSprites() {
|
||||
for (auto &sprite : card_sprites_) {
|
||||
sprite->update(delta_time);
|
||||
sprite->update();
|
||||
}
|
||||
|
||||
for (auto &sprite : shadow_sprites_) {
|
||||
sprite->update(delta_time);
|
||||
sprite->update();
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza los textos
|
||||
void Intro::updateTexts(float delta_time) {
|
||||
void Intro::updateTexts() {
|
||||
for (auto &text : texts_) {
|
||||
text->update(delta_time);
|
||||
text->update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class Intro {
|
||||
std::unique_ptr<TiledBG> tiled_bg_; // Fondo en mosaico
|
||||
|
||||
// --- Variables ---
|
||||
Uint64 last_time_ = 0; // Último timestamp para calcular delta-time
|
||||
Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
int scene_ = 0; // Indica qué escena está activa
|
||||
State state_ = State::SCENES; // Estado principal de la intro
|
||||
PostState post_state_ = PostState::STOP_BG; // Estado POST
|
||||
@@ -50,20 +50,19 @@ class Intro {
|
||||
Color bg_color_ = param.intro.bg_color; // Color de fondo
|
||||
|
||||
// --- Métodos internos ---
|
||||
void update(float delta_time); // Actualiza las variables del objeto
|
||||
void update(); // Actualiza las variables del objeto
|
||||
void render(); // Dibuja el objeto en pantalla
|
||||
static void checkInput(); // Comprueba las entradas
|
||||
static void checkEvents(); // Comprueba los eventos
|
||||
void updateScenes(); // Actualiza las escenas de la intro
|
||||
void initSprites(); // Inicializa las imágenes
|
||||
void initTexts(); // Inicializa los textos
|
||||
void updateSprites(float delta_time); // Actualiza los sprites
|
||||
void updateTexts(float delta_time); // Actualiza los textos
|
||||
void updateSprites(); // Actualiza los sprites
|
||||
void updateTexts(); // Actualiza los textos
|
||||
void renderSprites(); // Dibuja los sprites
|
||||
void renderTexts(); // Dibuja los textos
|
||||
static void renderTextRect(); // Dibuja el rectangulo de fondo del texto;
|
||||
void updatePostState(); // Actualiza el estado POST
|
||||
float calculateDeltaTime(); // Calcula el tiempo transcurrido desde el último frame
|
||||
|
||||
// --- Métodos para manejar cada escena individualmente ---
|
||||
void updateScene0();
|
||||
|
||||
@@ -79,23 +79,21 @@ void Logo::checkInput() {
|
||||
}
|
||||
|
||||
// Gestiona el logo de JAILGAMES
|
||||
void Logo::updateJAILGAMES(float delta_time) {
|
||||
void Logo::updateJAILGAMES() {
|
||||
if (counter_ == 30) {
|
||||
Audio::get()->playSound("logo.wav");
|
||||
}
|
||||
|
||||
if (counter_ > 30) {
|
||||
const float pixels_to_move = SPEED * delta_time;
|
||||
|
||||
for (int i = 0; i < (int)jail_sprite_.size(); ++i) {
|
||||
if (jail_sprite_[i]->getX() != dest_.x) {
|
||||
if (i % 2 == 0) {
|
||||
jail_sprite_[i]->incX(-pixels_to_move);
|
||||
jail_sprite_[i]->incX(-SPEED);
|
||||
if (jail_sprite_[i]->getX() < dest_.x) {
|
||||
jail_sprite_[i]->setX(dest_.x);
|
||||
}
|
||||
} else {
|
||||
jail_sprite_[i]->incX(pixels_to_move);
|
||||
jail_sprite_[i]->incX(SPEED);
|
||||
if (jail_sprite_[i]->getX() > dest_.x) {
|
||||
jail_sprite_[i]->setX(dest_.x);
|
||||
}
|
||||
@@ -131,21 +129,16 @@ void Logo::updateTextureColors() {
|
||||
}
|
||||
|
||||
// Actualiza las variables
|
||||
void Logo::update(float delta_time) {
|
||||
static float logic_accumulator = 0.0f;
|
||||
logic_accumulator += delta_time;
|
||||
|
||||
// Ejecutar lógica a 60 FPS (cada 16.67ms) para mantener consistencia en counter_ y colores
|
||||
constexpr float LOGIC_FRAME_TIME = 1000.0f / 60.0f;
|
||||
|
||||
if (logic_accumulator >= LOGIC_FRAME_TIME) {
|
||||
void Logo::update() {
|
||||
if (SDL_GetTicks() - ticks_ > param.game.speed) {
|
||||
ticks_ = SDL_GetTicks(); // Actualiza el contador de ticks
|
||||
Screen::get()->update(); // Actualiza el objeto screen
|
||||
|
||||
updateJAILGAMES(); // Actualiza el logo de JAILGAMES
|
||||
updateTextureColors(); // Actualiza los colores de las texturas
|
||||
++counter_; // Gestiona el contador
|
||||
logic_accumulator -= LOGIC_FRAME_TIME;
|
||||
}
|
||||
|
||||
updateJAILGAMES(delta_time); // Actualiza el logo de JAILGAMES con delta-time real
|
||||
Audio::update();
|
||||
}
|
||||
|
||||
@@ -161,23 +154,11 @@ void Logo::render() {
|
||||
SCREEN->render();
|
||||
}
|
||||
|
||||
// Calcula el tiempo transcurrido desde el último frame
|
||||
float Logo::calculateDeltaTime() {
|
||||
const Uint64 current_time = SDL_GetTicks();
|
||||
const float delta_time = static_cast<float>(current_time - last_time_);
|
||||
last_time_ = current_time;
|
||||
return delta_time;
|
||||
}
|
||||
|
||||
// Bucle para el logo del juego
|
||||
void Logo::run() {
|
||||
last_time_ = SDL_GetTicks();
|
||||
|
||||
while (Section::name == Section::Name::LOGO) {
|
||||
const float delta_time = calculateDeltaTime();
|
||||
|
||||
checkInput();
|
||||
update(delta_time);
|
||||
update();
|
||||
checkEvents(); // Tiene que ir antes del render
|
||||
render();
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ class Logo {
|
||||
static constexpr int INIT_FADE_COUNTER_MARK = 300; // Tiempo del contador cuando inicia el fade a negro
|
||||
static constexpr int END_LOGO_COUNTER_MARK = 400; // Tiempo del contador para terminar el logo
|
||||
static constexpr int POST_LOGO_DURATION = 20; // Tiempo que dura el logo con el fade al máximo
|
||||
static constexpr float SPEED = 8.0f / 15.0f; // Velocidad de desplazamiento de cada línea (píxeles por ms)
|
||||
static constexpr int SPEED = 8; // Velocidad de desplazamiento de cada línea
|
||||
|
||||
// --- Objetos y punteros ---
|
||||
std::shared_ptr<Texture> since_texture_; // Textura con los gráficos "Since 1998"
|
||||
@@ -42,16 +42,15 @@ class Logo {
|
||||
// --- Variables ---
|
||||
std::vector<Color> color_; // Vector con los colores para el fade
|
||||
int counter_ = 0; // Contador
|
||||
Uint64 last_time_ = 0; // Último timestamp para calcular delta-time
|
||||
Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
SDL_FPoint dest_; // Posición donde dibujar el logo
|
||||
|
||||
// --- Métodos internos ---
|
||||
void update(float delta_time); // Actualiza las variables
|
||||
void update(); // Actualiza las variables
|
||||
void render(); // Dibuja en pantalla
|
||||
static void checkEvents(); // Comprueba el manejador de eventos
|
||||
static void checkInput(); // Comprueba las entradas
|
||||
void updateJAILGAMES(float delta_time); // Gestiona el logo de JAILGAMES
|
||||
void updateJAILGAMES(); // Gestiona el logo de JAILGAMES
|
||||
void renderJAILGAMES(); // Renderiza el logo de JAILGAMES
|
||||
void updateTextureColors(); // Gestiona el color de las texturas
|
||||
float calculateDeltaTime(); // Calcula el tiempo transcurrido desde el último frame
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "moving_sprite.h" // Para MovingSprite
|
||||
|
||||
// Actualiza la posición y comprueba si ha llegado a su destino (frame-based)
|
||||
// Actualiza la posición y comprueba si ha llegado a su destino
|
||||
void SmartSprite::update() {
|
||||
if (enabled_) {
|
||||
MovingSprite::update();
|
||||
@@ -11,15 +11,6 @@ void SmartSprite::update() {
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza la posición y comprueba si ha llegado a su destino (time-based)
|
||||
void SmartSprite::update(float deltaTime) {
|
||||
if (enabled_) {
|
||||
MovingSprite::update(deltaTime);
|
||||
checkMove();
|
||||
checkFinished();
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja el sprite
|
||||
void SmartSprite::render() {
|
||||
if (enabled_) {
|
||||
|
||||
@@ -16,9 +16,8 @@ class SmartSprite : public AnimatedSprite {
|
||||
~SmartSprite() override = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
void update() override; // Actualiza la posición y comprueba si ha llegado a su destino (frame-based)
|
||||
void update(float deltaTime) override; // Actualiza la posición y comprueba si ha llegado a su destino (time-based)
|
||||
void render() override; // Dibuja el sprite
|
||||
void update() override; // Actualiza la posición y comprueba si ha llegado a su destino
|
||||
void render() override; // Dibuja el sprite
|
||||
|
||||
// --- Getters ---
|
||||
auto getDestX() const -> int { return dest_x_; } // Obtiene la posición de destino en X
|
||||
|
||||
@@ -81,15 +81,9 @@ void TiledBG::render() {
|
||||
SDL_RenderTexture(renderer_, canvas_, &window_, &pos_);
|
||||
}
|
||||
|
||||
// Actualiza la lógica de la clase (compatibilidad)
|
||||
void TiledBG::update() {
|
||||
constexpr float FRAME_TIME_MS = 1000.0f / 60.0f; // 16.67ms por frame a 60 FPS
|
||||
update(FRAME_TIME_MS);
|
||||
}
|
||||
|
||||
// Actualiza la lógica de la clase
|
||||
void TiledBG::update(float delta_time) {
|
||||
updateDesp(delta_time);
|
||||
void TiledBG::update() {
|
||||
updateDesp();
|
||||
updateStop();
|
||||
|
||||
switch (mode_) {
|
||||
|
||||
@@ -24,9 +24,8 @@ class TiledBG {
|
||||
~TiledBG();
|
||||
|
||||
// --- Métodos principales ---
|
||||
void render(); // Pinta la clase en pantalla
|
||||
void update(); // Actualiza la lógica de la clase (compatibilidad)
|
||||
void update(float delta_time); // Actualiza la lógica de la clase
|
||||
void render(); // Pinta la clase en pantalla
|
||||
void update(); // Actualiza la lógica de la clase
|
||||
|
||||
// --- Configuración ---
|
||||
void setSpeed(float speed) { speed_ = speed; } // Establece la velocidad
|
||||
@@ -55,8 +54,7 @@ class TiledBG {
|
||||
bool stopping_ = false; // Indica si se está deteniendo
|
||||
|
||||
// --- Métodos internos ---
|
||||
void fillTexture(); // Rellena la textura con el contenido
|
||||
void updateDesp() { desp_ += speed_; } // Actualiza el desplazamiento (compatibilidad)
|
||||
void updateDesp(float delta_time) { desp_ += speed_ * delta_time / (1000.0f / 60.0f); } // Actualiza el desplazamiento
|
||||
void updateStop(); // Detiene el desplazamiento de forma ordenada
|
||||
void fillTexture(); // Rellena la textura con el contenido
|
||||
void updateDesp() { desp_ += speed_; } // Actualiza el desplazamiento
|
||||
void updateStop(); // Detiene el desplazamiento de forma ordenada
|
||||
};
|
||||
@@ -3,14 +3,15 @@
|
||||
#include "text.h" // Para Text
|
||||
|
||||
// Actualiza el objeto
|
||||
void Writer::update(float delta_time) {
|
||||
void Writer::update() {
|
||||
if (enabled_) {
|
||||
if (!completed_) {
|
||||
// No completado
|
||||
writing_timer_ += delta_time;
|
||||
if (writing_timer_ >= speed_ms_) {
|
||||
if (writing_counter_ > 0) {
|
||||
writing_counter_--;
|
||||
} else {
|
||||
index_++;
|
||||
writing_timer_ = 0.0f;
|
||||
writing_counter_ = speed_;
|
||||
}
|
||||
|
||||
if (index_ == length_) {
|
||||
@@ -18,8 +19,10 @@ void Writer::update(float delta_time) {
|
||||
}
|
||||
} else {
|
||||
// Completado
|
||||
enabled_timer_ += delta_time;
|
||||
finished_ = enabled_timer_ >= enabled_timer_target_;
|
||||
finished_ = enabled_counter_ <= 0;
|
||||
if (!finished_) {
|
||||
enabled_counter_--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,10 +57,8 @@ void Writer::setCaption(const std::string &text) {
|
||||
|
||||
// Establece el valor de la variable
|
||||
void Writer::setSpeed(int value) {
|
||||
// Convierte frames a milisegundos (frames * 16.67ms)
|
||||
constexpr float FRAME_TIME_MS = 1000.0f / 60.0f;
|
||||
speed_ms_ = static_cast<float>(value) * FRAME_TIME_MS;
|
||||
writing_timer_ = 0.0f;
|
||||
speed_ = value;
|
||||
writing_counter_ = value;
|
||||
}
|
||||
|
||||
// Establece el valor de la variable
|
||||
@@ -72,10 +73,7 @@ auto Writer::isEnabled() const -> bool {
|
||||
|
||||
// Establece el valor de la variable
|
||||
void Writer::setFinishedCounter(int time) {
|
||||
// Convierte frames a milisegundos (frames * 16.67ms)
|
||||
constexpr float FRAME_TIME_MS = 1000.0f / 60.0f;
|
||||
enabled_timer_target_ = static_cast<float>(time) * FRAME_TIME_MS;
|
||||
enabled_timer_ = 0.0f;
|
||||
enabled_counter_ = time;
|
||||
}
|
||||
|
||||
// Centra la cadena de texto a un punto X
|
||||
|
||||
@@ -15,7 +15,7 @@ class Writer {
|
||||
~Writer() = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
void update(float delta_time); // Actualiza el objeto
|
||||
void update(); // Actualiza el objeto
|
||||
void render() const; // Dibuja el objeto en pantalla
|
||||
|
||||
// --- Setters ---
|
||||
@@ -38,17 +38,16 @@ class Writer {
|
||||
std::shared_ptr<Text> text_; // Objeto encargado de escribir el texto
|
||||
|
||||
// --- Variables de estado ---
|
||||
std::string caption_; // El texto para escribir
|
||||
int pos_x_ = 0; // Posición en el eje X donde empezar a escribir el texto
|
||||
int pos_y_ = 0; // Posición en el eje Y donde empezar a escribir el texto
|
||||
int kerning_ = 0; // Kerning del texto, es decir, espaciado entre caracteres
|
||||
float speed_ms_ = 0.0f; // Velocidad de escritura en milisegundos
|
||||
float writing_timer_ = 0.0f; // Temporizador de escritura para cada caracter
|
||||
int index_ = 0; // Posición del texto que se está escribiendo
|
||||
int length_ = 0; // Longitud de la cadena a escribir
|
||||
float enabled_timer_ = 0.0f; // Temporizador para deshabilitar el objeto
|
||||
float enabled_timer_target_ = 0.0f; // Tiempo objetivo para deshabilitar el objeto
|
||||
bool completed_ = false; // Indica si se ha escrito todo el texto
|
||||
bool enabled_ = false; // Indica si el objeto está habilitado
|
||||
bool finished_ = false; // Indica si ya ha terminado
|
||||
std::string caption_; // El texto para escribir
|
||||
int pos_x_ = 0; // Posición en el eje X donde empezar a escribir el texto
|
||||
int pos_y_ = 0; // Posición en el eje Y donde empezar a escribir el texto
|
||||
int kerning_ = 0; // Kerning del texto, es decir, espaciado entre caracteres
|
||||
int speed_ = 0; // Velocidad de escritura
|
||||
int writing_counter_ = 0; // Temporizador de escritura para cada caracter
|
||||
int index_ = 0; // Posición del texto que se está escribiendo
|
||||
int length_ = 0; // Longitud de la cadena a escribir
|
||||
int enabled_counter_ = 0; // Temporizador para deshabilitar el objeto
|
||||
bool completed_ = false; // Indica si se ha escrito todo el texto
|
||||
bool enabled_ = false; // Indica si el objeto está habilitado
|
||||
bool finished_ = false; // Indica si ya ha terminado
|
||||
};
|
||||
Reference in New Issue
Block a user