From 44b6f6830d7700ea0792e4b34097b6ed348fc01f Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 2 Apr 2026 16:55:56 +0200 Subject: [PATCH] =?UTF-8?q?primera=20versi=C3=B3=20del=20editor=20de=20til?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/game/editor/map_editor.cpp | 102 +++++++++++++++++++++- source/game/editor/map_editor.hpp | 4 + source/game/editor/tile_picker.cpp | 1 + source/game/gameplay/room.cpp | 8 ++ source/game/gameplay/room.hpp | 3 + source/game/gameplay/tilemap_renderer.cpp | 31 +++++++ source/game/gameplay/tilemap_renderer.hpp | 1 + 7 files changed, 148 insertions(+), 2 deletions(-) diff --git a/source/game/editor/map_editor.cpp b/source/game/editor/map_editor.cpp index e766589..0d405c9 100644 --- a/source/game/editor/map_editor.cpp +++ b/source/game/editor/map_editor.cpp @@ -81,6 +81,9 @@ void MapEditor::enter(std::shared_ptr room, std::shared_ptr player // Resetear estado drag_ = {}; selected_enemy_ = -1; + selected_item_ = -1; + brush_tile_ = NO_BRUSH; + painting_ = false; active_ = true; std::cout << "MapEditor: ON (room " << room_path_ << ")\n"; @@ -135,7 +138,14 @@ auto MapEditor::revert() -> std::string { room_->setBgColor(room_data_.bg_color); Screen::get()->setBorderColor(stringToColor(room_data_.border_color)); + // Restaurar el tilemap completo + for (int i = 0; i < static_cast(room_data_.tile_map.size()); ++i) { + room_->setTile(i, room_data_.tile_map[i]); + } + selected_enemy_ = -1; + selected_item_ = -1; + brush_tile_ = NO_BRUSH; return "Reverted to original"; } @@ -171,6 +181,17 @@ void MapEditor::update(float delta_time) { updateDrag(); } + // Si estamos pintando tiles, pintar en la posición actual del ratón + if (painting_ && brush_tile_ != NO_BRUSH) { + int tile_index = mouse_tile_y_ * 32 + mouse_tile_x_; + if (tile_index >= 0 && tile_index < static_cast(room_data_.tile_map.size())) { + if (room_data_.tile_map[tile_index] != brush_tile_) { + room_data_.tile_map[tile_index] = brush_tile_; + room_->setTile(tile_index, brush_tile_); + } + } + } + // Actualizar la barra de estado updateStatusBarInfo(); if (statusbar_) { @@ -212,10 +233,79 @@ void MapEditor::handleEvent(const SDL_Event& event) { return; } + // ESC: desactivar brush + if (event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_ESCAPE && brush_tile_ != NO_BRUSH) { + brush_tile_ = NO_BRUSH; + return; + } + + // E: toggle borrador + if (event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_E && static_cast(event.key.repeat) == 0) { + brush_tile_ = (brush_tile_ == ERASER_BRUSH) ? NO_BRUSH : ERASER_BRUSH; + return; + } + + // Click derecho: abrir TilePicker del mapa + if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN && event.button.button == SDL_BUTTON_RIGHT) { + // Deseleccionar entidades + selected_enemy_ = -1; + selected_item_ = -1; + + // Tile bajo el cursor como tile actual del picker + int tile_index = mouse_tile_y_ * 32 + mouse_tile_x_; + int current = (tile_index >= 0 && tile_index < static_cast(room_data_.tile_map.size())) + ? room_data_.tile_map[tile_index] + : -1; + + tile_picker_.on_select = [this](int tile) { + brush_tile_ = tile; + }; + tile_picker_.open(room_->getTileSetFile(), current, + stringToColor(room_data_.bg_color)); + return; + } + + // Click izquierdo if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN && event.button.button == SDL_BUTTON_LEFT) { + // Si hay brush activo y no hacemos hit en ninguna entidad → pintar + if (brush_tile_ != NO_BRUSH) { + // Comprobar si hay hit en alguna entidad primero + bool hit_entity = false; + SDL_FRect player_rect = player_->getRect(); + if (pointInRect(mouse_game_x_, mouse_game_y_, player_rect)) { hit_entity = true; } + + if (!hit_entity) { + auto* enemy_mgr = room_->getEnemyManager(); + for (int i = 0; i < enemy_mgr->getCount() && !hit_entity; ++i) { + if (pointInRect(mouse_game_x_, mouse_game_y_, enemy_mgr->getEnemy(i)->getRect())) { hit_entity = true; } + } + } + if (!hit_entity) { + auto* item_mgr = room_->getItemManager(); + for (int i = 0; i < item_mgr->getCount() && !hit_entity; ++i) { + if (pointInRect(mouse_game_x_, mouse_game_y_, item_mgr->getItem(i)->getCollider())) { hit_entity = true; } + } + } + + if (!hit_entity) { + // Pintar tile y entrar en modo painting + painting_ = true; + int tile_index = mouse_tile_y_ * 32 + mouse_tile_x_; + if (tile_index >= 0 && tile_index < static_cast(room_data_.tile_map.size())) { + room_data_.tile_map[tile_index] = brush_tile_; + room_->setTile(tile_index, brush_tile_); + } + return; + } + } handleMouseDown(mouse_game_x_, mouse_game_y_); } else if (event.type == SDL_EVENT_MOUSE_BUTTON_UP && event.button.button == SDL_BUTTON_LEFT) { - handleMouseUp(); + if (painting_) { + painting_ = false; + autosave(); + } else { + handleMouseUp(); + } } } @@ -640,9 +730,17 @@ void MapEditor::updateStatusBarInfo() { " itm:" + room_data_.item_color1 + "/" + room_data_.item_color2; } + // Línea 4: brush activo + std::string line4; + if (brush_tile_ == ERASER_BRUSH) { + line4 = "brush: eraser (e)"; + } else if (brush_tile_ != NO_BRUSH) { + line4 = "brush: tile " + std::to_string(brush_tile_); + } + statusbar_->setLine2(line2); statusbar_->setLine3(line3); - statusbar_->setLine4(""); + statusbar_->setLine4(line4); statusbar_->setLine5(line5); // Actualizar el prompt de la consola según la selección diff --git a/source/game/editor/map_editor.hpp b/source/game/editor/map_editor.hpp index 699e975..7164ea3 100644 --- a/source/game/editor/map_editor.hpp +++ b/source/game/editor/map_editor.hpp @@ -93,6 +93,10 @@ class MapEditor { DragState drag_; int selected_enemy_{-1}; // Índice del enemigo seleccionado (-1 = ninguno) int selected_item_{-1}; // Índice del item seleccionado (-1 = ninguno) + static constexpr int NO_BRUSH = -2; // Sin brush activo + static constexpr int ERASER_BRUSH = -1; // Brush borrador (pinta tile vacío = -1) + int brush_tile_{NO_BRUSH}; // Tile activo para pintar + bool painting_{false}; // true mientras se está pintando con click izquierdo mantenido // Datos de la habitación Room::Data room_data_; diff --git a/source/game/editor/tile_picker.cpp b/source/game/editor/tile_picker.cpp index e8473ed..f013886 100644 --- a/source/game/editor/tile_picker.cpp +++ b/source/game/editor/tile_picker.cpp @@ -113,6 +113,7 @@ void TilePicker::open(const std::string& tileset_name, int current_tile, } open_ = true; + updateMousePosition(); } // Cierra el picker diff --git a/source/game/gameplay/room.cpp b/source/game/gameplay/room.cpp index 7d990a2..c4ba5d3 100644 --- a/source/game/gameplay/room.cpp +++ b/source/game/gameplay/room.cpp @@ -134,6 +134,14 @@ void Room::resetEnemyPositions(const std::vector& enemy_data) { enemy_manager_->resetPositions(enemy_data); } +// Cambia un tile y repinta la celda (para editor) +void Room::setTile(int index, int tile_value) { + if (index >= 0 && index < static_cast(tile_map_.size())) { + tile_map_[index] = tile_value; + tilemap_renderer_->setTile(index, tile_value); + } +} + // Cambia color de fondo y redibuja el mapa (para editor) void Room::setBgColor(const std::string& color) { bg_color_ = color; diff --git a/source/game/gameplay/room.hpp b/source/game/gameplay/room.hpp index fe22d3a..260d6cd 100644 --- a/source/game/gameplay/room.hpp +++ b/source/game/gameplay/room.hpp @@ -76,6 +76,9 @@ class Room { auto getItemManager() -> ItemManager* { return item_manager_.get(); } // Acceso al gestor de items (para editor) void setBgColor(const std::string& color); // Cambia color de fondo y redibuja (para editor) void setItemColors(const std::string& color1, const std::string& color2); // Cambia colores de items (para editor) + void setTile(int index, int tile_value); // Cambia un tile y redibuja (para editor) + [[nodiscard]] auto getTileSetFile() const -> const std::string& { return tile_set_file_; } + [[nodiscard]] auto getTileSetWidth() const -> int { return tile_set_width_; } #endif void update(float delta_time); // Actualiza las variables y objetos de la habitación auto getRoom(Border border) -> std::string; // Devuelve la cadena del fichero de la habitación contigua segun el borde diff --git a/source/game/gameplay/tilemap_renderer.cpp b/source/game/gameplay/tilemap_renderer.cpp index c272f5c..b317ba0 100644 --- a/source/game/gameplay/tilemap_renderer.cpp +++ b/source/game/gameplay/tilemap_renderer.cpp @@ -100,6 +100,37 @@ static void renderDebugCollisionSurfaces(const CollisionMap* collision_map) { void TilemapRenderer::redrawMap(const CollisionMap* collision_map) { fillMapTexture(collision_map); } + +// Cambia un tile y repinta solo esa celda en la map_surface +void TilemapRenderer::setTile(int index, int tile_value) { + if (index < 0 || index >= static_cast(tile_map_.size())) { return; } + + tile_map_[index] = tile_value; + + int col = index % MAP_WIDTH; + int row = index / MAP_WIDTH; + + auto previous_renderer = Screen::get()->getRendererSurface(); + Screen::get()->setRendererSurface(map_surface_); + + // Borrar la celda con el color de fondo + SDL_FRect cell = {.x = static_cast(col * TILE_SIZE), .y = static_cast(row * TILE_SIZE), + .w = static_cast(TILE_SIZE), .h = static_cast(TILE_SIZE)}; + map_surface_->fillRect(&cell, stringToColor(bg_color_)); + + // Dibujar el nuevo tile (si no es vacío ni animado) + if (tile_value > -1) { + const bool IS_ANIMATED = (tile_value >= 18 * tile_set_width_) && (tile_value < 19 * tile_set_width_); + if (!IS_ANIMATED) { + SDL_FRect clip = {.x = static_cast((tile_value % tile_set_width_) * TILE_SIZE), + .y = static_cast((tile_value / tile_set_width_) * TILE_SIZE), + .w = static_cast(TILE_SIZE), .h = static_cast(TILE_SIZE)}; + tileset_surface_->render(col * TILE_SIZE, row * TILE_SIZE, &clip); + } + } + + Screen::get()->setRendererSurface(previous_renderer); +} #endif // Pinta el mapa estático y debug lines diff --git a/source/game/gameplay/tilemap_renderer.hpp b/source/game/gameplay/tilemap_renderer.hpp index 52b8070..2f88a7d 100644 --- a/source/game/gameplay/tilemap_renderer.hpp +++ b/source/game/gameplay/tilemap_renderer.hpp @@ -70,6 +70,7 @@ class TilemapRenderer { */ void redrawMap(const CollisionMap* collision_map); void setBgColor(const std::string& color) { bg_color_ = color; } + void setTile(int index, int tile_value); // Cambia un tile y repinta esa celda #endif /**