Implementar sistema de zoom dinámico y fullscreen
- Agregar zoom dinámico de ventana con F1/F2 - F1: reducir zoom hasta 1x mínimo - F2: aumentar zoom hasta máximo basado en resolución - Centrado inteligente al cambiar zoom - Cálculo correcto de zoom máximo usando SDL_GetCurrentDisplayMode() - F3: toggle fullscreen entre ventana y pantalla completa - Mover temas de colores de F1-F4 a teclado numérico (KP_1-4) - Mejorar resolución base a 640x480 con zoom inicial 2x - Resolver paths absolutos para data/ball.png 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6,17 +6,36 @@
|
||||
#include <SDL3/SDL_keycode.h> // for SDL_Keycode
|
||||
#include <SDL3/SDL_render.h> // for SDL_SetRenderDrawColor, SDL_RenderPresent
|
||||
#include <SDL3/SDL_timer.h> // for SDL_GetTicks
|
||||
#include <SDL3/SDL_video.h> // for SDL_CreateWindow, SDL_DestroyWindow
|
||||
#include <SDL3/SDL_video.h> // for SDL_CreateWindow, SDL_DestroyWindow, SDL_GetDisplayBounds
|
||||
|
||||
#include <algorithm> // for std::min, std::max
|
||||
#include <cstdlib> // for rand, srand
|
||||
#include <ctime> // for time
|
||||
#include <iostream> // for cout
|
||||
#include <string> // for string
|
||||
#include <filesystem> // for path operations
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h> // for GetModuleFileName
|
||||
#endif
|
||||
|
||||
#include "ball.h" // for Ball
|
||||
#include "external/dbgtxt.h" // for dbg_init, dbg_print
|
||||
#include "external/texture.h" // for Texture
|
||||
|
||||
// Función auxiliar para obtener la ruta del directorio del ejecutable
|
||||
std::string getExecutableDirectory() {
|
||||
#ifdef _WIN32
|
||||
char buffer[MAX_PATH];
|
||||
GetModuleFileNameA(NULL, buffer, MAX_PATH);
|
||||
std::filesystem::path exe_path(buffer);
|
||||
return exe_path.parent_path().string();
|
||||
#else
|
||||
// Para Linux/macOS se podría usar readlink("/proc/self/exe") o dladdr
|
||||
return "."; // Fallback para otros sistemas
|
||||
#endif
|
||||
}
|
||||
|
||||
// Implementación de métodos públicos
|
||||
bool Engine::initialize() {
|
||||
bool success = true;
|
||||
@@ -26,7 +45,7 @@ bool Engine::initialize() {
|
||||
success = false;
|
||||
} else {
|
||||
// Crear ventana principal
|
||||
window_ = SDL_CreateWindow(WINDOW_CAPTION, SCREEN_WIDTH * WINDOW_SIZE, SCREEN_HEIGHT * WINDOW_SIZE, SDL_WINDOW_OPENGL);
|
||||
window_ = SDL_CreateWindow(WINDOW_CAPTION, SCREEN_WIDTH * WINDOW_ZOOM, SCREEN_HEIGHT * WINDOW_ZOOM, SDL_WINDOW_OPENGL);
|
||||
if (window_ == nullptr) {
|
||||
std::cout << "¡No se pudo crear la ventana! Error de SDL: " << SDL_GetError() << std::endl;
|
||||
success = false;
|
||||
@@ -51,7 +70,10 @@ bool Engine::initialize() {
|
||||
|
||||
// Inicializar otros componentes si SDL se inicializó correctamente
|
||||
if (success) {
|
||||
texture_ = std::make_shared<Texture>(renderer_, "data/ball.png");
|
||||
// Construir ruta absoluta a la imagen
|
||||
std::string exe_dir = getExecutableDirectory();
|
||||
std::string texture_path = exe_dir + "/data/ball.png";
|
||||
texture_ = std::make_shared<Texture>(renderer_, texture_path);
|
||||
srand(static_cast<unsigned>(time(nullptr)));
|
||||
dbg_init(renderer_);
|
||||
initBalls(scenario_);
|
||||
@@ -181,22 +203,23 @@ void Engine::handleEvents() {
|
||||
initBalls(scenario_); // Regenerar bolas con nueva paleta
|
||||
break;
|
||||
|
||||
case SDLK_F1:
|
||||
// Temas de colores con teclado numérico
|
||||
case SDLK_KP_1:
|
||||
current_theme_ = ColorTheme::SUNSET;
|
||||
initBalls(scenario_);
|
||||
break;
|
||||
|
||||
case SDLK_F2:
|
||||
case SDLK_KP_2:
|
||||
current_theme_ = ColorTheme::OCEAN;
|
||||
initBalls(scenario_);
|
||||
break;
|
||||
|
||||
case SDLK_F3:
|
||||
case SDLK_KP_3:
|
||||
current_theme_ = ColorTheme::NEON;
|
||||
initBalls(scenario_);
|
||||
break;
|
||||
|
||||
case SDLK_F4:
|
||||
case SDLK_KP_4:
|
||||
current_theme_ = ColorTheme::FOREST;
|
||||
initBalls(scenario_);
|
||||
break;
|
||||
@@ -240,6 +263,20 @@ void Engine::handleEvents() {
|
||||
scenario_ = 7;
|
||||
initBalls(scenario_);
|
||||
break;
|
||||
|
||||
// Controles de zoom dinámico
|
||||
case SDLK_F1:
|
||||
zoomOut();
|
||||
break;
|
||||
|
||||
case SDLK_F2:
|
||||
zoomIn();
|
||||
break;
|
||||
|
||||
// Control de pantalla completa
|
||||
case SDLK_F3:
|
||||
toggleFullscreen();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -400,6 +437,11 @@ void Engine::toggleVSync() {
|
||||
SDL_SetRenderVSync(renderer_, vsync_enabled_ ? 1 : 0);
|
||||
}
|
||||
|
||||
void Engine::toggleFullscreen() {
|
||||
fullscreen_enabled_ = !fullscreen_enabled_;
|
||||
SDL_SetWindowFullscreen(window_, fullscreen_enabled_);
|
||||
}
|
||||
|
||||
std::string Engine::gravityDirectionToString(GravityDirection direction) const {
|
||||
switch (direction) {
|
||||
case GravityDirection::DOWN: return "DOWN";
|
||||
@@ -495,4 +537,80 @@ void Engine::addSpriteToBatch(float x, float y, float w, float h, int r, int g,
|
||||
batch_indices_.push_back(vertex_index + 2);
|
||||
batch_indices_.push_back(vertex_index + 3);
|
||||
batch_indices_.push_back(vertex_index + 0);
|
||||
}
|
||||
|
||||
// Sistema de zoom dinámico
|
||||
int Engine::calculateMaxWindowZoom() const {
|
||||
// Obtener información del display usando el método de Coffee Crisis
|
||||
int num_displays = 0;
|
||||
SDL_DisplayID *displays = SDL_GetDisplays(&num_displays);
|
||||
if (displays == nullptr || num_displays == 0) {
|
||||
return WINDOW_ZOOM_MIN; // Fallback si no se puede obtener
|
||||
}
|
||||
|
||||
// Obtener el modo de display actual
|
||||
const auto *dm = SDL_GetCurrentDisplayMode(displays[0]);
|
||||
if (dm == nullptr) {
|
||||
SDL_free(displays);
|
||||
return WINDOW_ZOOM_MIN;
|
||||
}
|
||||
|
||||
// Calcular zoom máximo usando la fórmula de Coffee Crisis
|
||||
const int MAX_ZOOM = std::min(dm->w / SCREEN_WIDTH, (dm->h - WINDOW_DECORATION_HEIGHT) / SCREEN_HEIGHT);
|
||||
|
||||
SDL_free(displays);
|
||||
|
||||
// Aplicar límites
|
||||
return std::max(WINDOW_ZOOM_MIN, std::min(MAX_ZOOM, WINDOW_ZOOM_MAX));
|
||||
}
|
||||
|
||||
void Engine::setWindowZoom(int new_zoom) {
|
||||
// Validar zoom
|
||||
int max_zoom = calculateMaxWindowZoom();
|
||||
new_zoom = std::max(WINDOW_ZOOM_MIN, std::min(new_zoom, max_zoom));
|
||||
|
||||
if (new_zoom == current_window_zoom_) {
|
||||
return; // No hay cambio
|
||||
}
|
||||
|
||||
// Obtener posición actual del centro de la ventana
|
||||
int current_x, current_y;
|
||||
SDL_GetWindowPosition(window_, ¤t_x, ¤t_y);
|
||||
int current_center_x = current_x + (SCREEN_WIDTH * current_window_zoom_) / 2;
|
||||
int current_center_y = current_y + (SCREEN_HEIGHT * current_window_zoom_) / 2;
|
||||
|
||||
// Calcular nuevo tamaño
|
||||
int new_width = SCREEN_WIDTH * new_zoom;
|
||||
int new_height = SCREEN_HEIGHT * new_zoom;
|
||||
|
||||
// Calcular nueva posición (centrada en el punto actual)
|
||||
int new_x = current_center_x - new_width / 2;
|
||||
int new_y = current_center_y - new_height / 2;
|
||||
|
||||
// Obtener límites del escritorio para no salirse
|
||||
SDL_Rect display_bounds;
|
||||
if (SDL_GetDisplayBounds(SDL_GetPrimaryDisplay(), &display_bounds) == 0) {
|
||||
// Aplicar márgenes
|
||||
int min_x = WINDOW_DESKTOP_MARGIN;
|
||||
int min_y = WINDOW_DESKTOP_MARGIN;
|
||||
int max_x = display_bounds.w - new_width - WINDOW_DESKTOP_MARGIN;
|
||||
int max_y = display_bounds.h - new_height - WINDOW_DESKTOP_MARGIN - WINDOW_DECORATION_HEIGHT;
|
||||
|
||||
// Limitar posición
|
||||
new_x = std::max(min_x, std::min(new_x, max_x));
|
||||
new_y = std::max(min_y, std::min(new_y, max_y));
|
||||
}
|
||||
|
||||
// Aplicar cambios
|
||||
SDL_SetWindowSize(window_, new_width, new_height);
|
||||
SDL_SetWindowPosition(window_, new_x, new_y);
|
||||
current_window_zoom_ = new_zoom;
|
||||
}
|
||||
|
||||
void Engine::zoomIn() {
|
||||
setWindowZoom(current_window_zoom_ + 1);
|
||||
}
|
||||
|
||||
void Engine::zoomOut() {
|
||||
setWindowZoom(current_window_zoom_ - 1);
|
||||
}
|
||||
Reference in New Issue
Block a user