From b6fec3eba7adadd1a2f4bfdc7d56368c946d5f87 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 2 Apr 2026 10:39:57 +0200 Subject: [PATCH] drag'n drop del jugador --- source/game/editor/map_editor.cpp | 113 ++++++++++++++++++++++++++++-- source/game/editor/map_editor.hpp | 26 ++++++- 2 files changed, 131 insertions(+), 8 deletions(-) diff --git a/source/game/editor/map_editor.cpp b/source/game/editor/map_editor.cpp index fa51839..ec14216 100644 --- a/source/game/editor/map_editor.cpp +++ b/source/game/editor/map_editor.cpp @@ -4,6 +4,7 @@ #include +#include // Para std::round #include // Para cout #include "core/input/mouse.hpp" // Para Mouse @@ -63,6 +64,9 @@ void MapEditor::enter(std::shared_ptr room, std::shared_ptr player // Crear la barra de estado statusbar_ = std::make_unique(room_->getNumber(), room_->getName()); + // Resetear estado de drag + drag_ = {}; + active_ = true; std::cout << "MapEditor: ON (room " << room_path_ << ")\n"; } @@ -78,6 +82,7 @@ void MapEditor::exit() { player_->setColor(); // Liberar recursos + drag_ = {}; statusbar_.reset(); room_.reset(); player_.reset(); @@ -98,6 +103,11 @@ void MapEditor::update(float delta_time) { // Actualizar posición del ratón updateMousePosition(); + // Si estamos arrastrando, actualizar la posición snapped + if (drag_.target != DragTarget::NONE) { + updateDrag(); + } + // Actualizar la barra de estado con las coordenadas del ratón if (statusbar_) { statusbar_->setMouseTile(mouse_tile_x_, mouse_tile_y_); @@ -117,6 +127,9 @@ void MapEditor::render() { room_->renderItems(); player_->render(); + // Renderizar highlight de selección (encima de los sprites) + renderSelectionHighlight(); + // Renderizar barra de estado del editor (reemplaza al scoreboard) if (statusbar_) { statusbar_->render(); @@ -124,9 +137,101 @@ void MapEditor::render() { } // Maneja eventos del editor -void MapEditor::handleEvent([[maybe_unused]] const SDL_Event& event) { - // Por ahora no procesamos eventos específicos del editor - // En fases posteriores: drag & drop +void MapEditor::handleEvent(const SDL_Event& event) { + if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN && event.button.button == SDL_BUTTON_LEFT) { + handleMouseDown(mouse_game_x_, mouse_game_y_); + } else if (event.type == SDL_EVENT_MOUSE_BUTTON_UP && event.button.button == SDL_BUTTON_LEFT) { + handleMouseUp(); + } +} + +// Procesa click del ratón: hit test + inicio de drag +void MapEditor::handleMouseDown(float game_x, float game_y) { + // Prioridad de hit test: jugador → enemigos → items + + // 1. Hit test sobre el jugador + SDL_FRect player_rect = player_->getRect(); + if (pointInRect(game_x, game_y, player_rect)) { + drag_.target = DragTarget::PLAYER; + drag_.index = -1; + drag_.offset_x = game_x - player_rect.x; + drag_.offset_y = game_y - player_rect.y; + drag_.snap_x = player_rect.x; + drag_.snap_y = player_rect.y; + return; + } + + // (Fases 4+: hit test sobre enemigos e items) +} + +// Procesa soltar el ratón: commit del drag +void MapEditor::handleMouseUp() { + if (drag_.target == DragTarget::NONE) { return; } + + switch (drag_.target) { + case DragTarget::PLAYER: + // Mover el jugador a la posición snapped + player_->setDebugPosition(drag_.snap_x, drag_.snap_y); + player_->finalizeDebugTeleport(); + break; + default: + break; + } + + // Resetear estado de drag + drag_ = {}; +} + +// Actualiza la posición snapped durante el drag +void MapEditor::updateDrag() { + float raw_x = mouse_game_x_ - drag_.offset_x; + float raw_y = mouse_game_y_ - drag_.offset_y; + + drag_.snap_x = snapToGrid(raw_x); + drag_.snap_y = snapToGrid(raw_y); + + // Mientras arrastramos, mover la entidad visualmente a la posición snapped + if (drag_.target == DragTarget::PLAYER) { + player_->setDebugPosition(drag_.snap_x, drag_.snap_y); + } +} + +// Dibuja highlight del elemento seleccionado/arrastrado +void MapEditor::renderSelectionHighlight() { + if (drag_.target == DragTarget::NONE) { return; } + + auto game_surface = Screen::get()->getRendererSurface(); + if (!game_surface) { return; } + + const Uint8 HIGHLIGHT_COLOR = stringToColor("bright_white"); + + SDL_FRect highlight_rect{}; + switch (drag_.target) { + case DragTarget::PLAYER: + highlight_rect = player_->getRect(); + break; + default: + return; + } + + // Dibujar rectángulo de highlight alrededor de la entidad + SDL_FRect border = { + .x = highlight_rect.x - 1, + .y = highlight_rect.y - 1, + .w = highlight_rect.w + 2, + .h = highlight_rect.h + 2 + }; + game_surface->drawRectBorder(&border, HIGHLIGHT_COLOR); +} + +// Alinea un valor a la cuadrícula de 8x8 +auto MapEditor::snapToGrid(float value) -> float { + return std::round(value / static_cast(Tile::SIZE)) * static_cast(Tile::SIZE); +} + +// Hit test: punto dentro de rectángulo +auto MapEditor::pointInRect(float px, float py, const SDL_FRect& rect) -> bool { + return px >= rect.x && px < rect.x + rect.w && py >= rect.y && py < rect.y + rect.h; } // Dibuja marcadores de boundaries y líneas de ruta para los enemigos @@ -140,7 +245,6 @@ void MapEditor::renderEnemyBoundaries() { for (const auto& enemy : room_data_.enemies) { // Dibujar línea de ruta: boundary1 → posición inicial → boundary2 - // Usamos el centro del tile como punto de referencia para las líneas constexpr float HALF = Tile::SIZE / 2.0F; float init_cx = enemy.x + HALF; @@ -166,7 +270,6 @@ void MapEditor::renderBoundaryMarker(float x, float y, Uint8 color) { auto game_surface = Screen::get()->getRendererSurface(); if (!game_surface) { return; } - // Dibujar un rectángulo de 8x8 como marcador SDL_FRect marker = {.x = x, .y = y, .w = static_cast(Tile::SIZE), .h = static_cast(Tile::SIZE)}; game_surface->drawRectBorder(&marker, color); } diff --git a/source/game/editor/map_editor.hpp b/source/game/editor/map_editor.hpp index 23dfccd..4cb5726 100644 --- a/source/game/editor/map_editor.hpp +++ b/source/game/editor/map_editor.hpp @@ -37,12 +37,32 @@ class MapEditor { MapEditor(); // Constructor ~MapEditor(); // Destructor - void updateMousePosition(); // Convierte coordenadas de ventana a coordenadas de juego y tile - void renderEnemyBoundaries(); // Dibuja marcadores de boundaries y líneas de ruta - void renderBoundaryMarker(float x, float y, Uint8 color); // Dibuja un marcador de boundary en una posición + // Tipos para drag & drop + enum class DragTarget { NONE, PLAYER, ENEMY_INITIAL, ENEMY_BOUND1, ENEMY_BOUND2, ITEM }; + + struct DragState { + DragTarget target{DragTarget::NONE}; + int index{-1}; // Índice del enemigo o item en room_data_ + float offset_x{0.0F}; // Offset entre el cursor y el origen de la entidad al inicio del drag + float offset_y{0.0F}; + float snap_x{0.0F}; // Posición snapped actual (para preview) + float snap_y{0.0F}; + }; + + // Métodos internos + void updateMousePosition(); // Convierte coordenadas de ventana a coordenadas de juego y tile + void renderEnemyBoundaries(); // Dibuja marcadores de boundaries y líneas de ruta + void renderBoundaryMarker(float x, float y, Uint8 color); // Dibuja un marcador de boundary en una posición + void renderSelectionHighlight(); // Dibuja highlight del elemento seleccionado/arrastrado + void handleMouseDown(float game_x, float game_y); // Procesa click del ratón (hit test + inicio de drag) + void handleMouseUp(); // Procesa soltar el ratón (commit del drag) + void updateDrag(); // Actualiza la posición snapped durante el drag + static auto snapToGrid(float value) -> float; // Alinea un valor a la cuadrícula de 8x8 + static auto pointInRect(float px, float py, const SDL_FRect& rect) -> bool; // Hit test punto en rectángulo // Estado del editor bool active_{false}; + DragState drag_; // Copia mutable de los datos de la habitación (para edición futura) Room::Data room_data_;