mes retocs a minimap. arreglat el calcul dels minipixels en els tiles amb transparent

This commit is contained in:
2026-04-02 19:49:43 +02:00
parent b5e822c65f
commit cccb2359cf
4 changed files with 160 additions and 38 deletions

View File

@@ -15,6 +15,7 @@
#include "core/resources/resource_cache.hpp" // Para Resource::Cache
#include "core/resources/resource_list.hpp" // Para Resource::List
#include "game/editor/editor_statusbar.hpp" // Para EditorStatusBar
#include "game/game_control.hpp" // Para GameControl
#include "game/editor/room_saver.hpp" // Para RoomSaver
#include "game/entities/player.hpp" // Para Player
#include "game/gameplay/enemy_manager.hpp" // Para EnemyManager
@@ -119,8 +120,19 @@ static auto parseColor(const std::string& value) -> Uint8 {
void MapEditor::toggleMiniMap() {
if (!mini_map_) {
mini_map_ = std::make_unique<MiniMap>(parseColor(settings_.minimap_bg), parseColor(settings_.minimap_conn));
mini_map_->on_navigate = [this](const std::string& room_name) {
mini_map_visible_ = false;
// Navegar a la room (usa changeRoomWithEditor vía GameControl)
if (GameControl::exit_editor) { GameControl::exit_editor(); }
if (GameControl::change_room && GameControl::change_room(room_name)) {
if (GameControl::enter_editor) { GameControl::enter_editor(); }
}
};
}
mini_map_visible_ = !mini_map_visible_;
if (mini_map_visible_) {
mini_map_->centerOnRoom(room_path_);
}
}
auto MapEditor::setMiniMapBg(const std::string& color) -> std::string {
@@ -347,18 +359,16 @@ void MapEditor::handleEvent(const SDL_Event& event) {
return;
}
// Si el mini mapa está visible, cerrarlo con click o ESC
if (mini_map_visible_) {
if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN ||
(event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_ESCAPE)) {
// Si el mini mapa está visible, delegar eventos (ESC o M para cerrar)
if (mini_map_visible_ && mini_map_) {
if (event.type == SDL_EVENT_KEY_DOWN &&
(event.key.key == SDLK_ESCAPE || event.key.key == SDLK_M) &&
static_cast<int>(event.key.repeat) == 0) {
mini_map_visible_ = false;
return;
}
if (event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_M) {
mini_map_visible_ = false;
return;
}
return; // Bloquear otros eventos mientras el minimapa está visible
mini_map_->handleEvent(event, room_path_);
return;
}
// ESC: desactivar brush

View File

@@ -3,6 +3,7 @@
#include "game/editor/mini_map.hpp"
#include <algorithm> // Para std::max, std::min
#include <cmath> // Para std::floor
#include <array> // Para std::array
#include <iostream> // Para cout
#include <map> // Para std::map
@@ -37,6 +38,7 @@ void MiniMap::buildTileColorTable(const std::string& tileset_name) {
if (!tileset) { return; }
tileset_width_ = static_cast<int>(tileset->getWidth()) / Tile::SIZE;
tileset_transparent_ = tileset->getTransparentColor();
int tileset_height = static_cast<int>(tileset->getHeight()) / Tile::SIZE;
int total_tiles = tileset_width_ * tileset_height;
@@ -46,21 +48,23 @@ void MiniMap::buildTileColorTable(const std::string& tileset_name) {
int tile_x = (tile % tileset_width_) * Tile::SIZE;
int tile_y = (tile / tileset_width_) * Tile::SIZE;
// Contar frecuencia de cada color en el tile (ignorar transparente=255 y negro=0)
// Contar frecuencia de cada color en el tile (ignorar el color transparente del tileset)
Uint8 transparent = tileset->getTransparentColor();
std::array<int, 256> freq{};
for (int y = 0; y < Tile::SIZE; ++y) {
for (int x = 0; x < Tile::SIZE; ++x) {
Uint8 pixel = tileset->getPixel(tile_x + x, tile_y + y);
if (pixel != 0 && pixel != 255) {
if (pixel != transparent) {
freq[pixel]++;
}
}
}
// Encontrar el color más frecuente
Uint8 best_color = 0;
// Encontrar el color más frecuente (transparent = tile vacío, no se pinta)
Uint8 best_color = transparent;
int best_count = 0;
for (int c = 1; c < 256; ++c) {
for (int c = 0; c < 256; ++c) {
if (c == transparent) { continue; }
if (freq[c] > best_count) {
best_count = freq[c];
best_color = static_cast<Uint8>(c);
@@ -182,7 +186,7 @@ auto MiniMap::getRoomMiniSurface(const std::string& room_name) -> std::shared_pt
if (tile < 0 || tile >= static_cast<int>(tile_colors_.size())) { continue; }
Uint8 color = tile_colors_[tile];
if (color != 0) {
if (color != tileset_transparent_) {
surface->putPixel(x, y, color);
}
}
@@ -267,35 +271,125 @@ void MiniMap::drawConnections() {
}
}
// Renderiza el minimapa centrado en la room actual
// Centra el viewport en una room
void MiniMap::centerOnRoom(const std::string& room_name) {
auto it = room_positions_.find(room_name);
if (it == room_positions_.end()) { return; }
const auto& pos = it->second.pos;
float room_cx = static_cast<float>(cellPixelX(pos.x) + CELL_W / 2);
float room_cy = static_cast<float>(cellPixelY(pos.y) + CELL_H / 2);
view_x_ = static_cast<float>(PlayArea::WIDTH) / 2.0F - room_cx;
view_y_ = static_cast<float>(PlayArea::HEIGHT) / 2.0F - room_cy;
}
// Devuelve el nombre de la room en una posición de pantalla, o vacío si no hay ninguna
auto MiniMap::roomAtScreen(float screen_x, float screen_y) -> std::string {
// Convertir coordenada de pantalla a coordenada dentro del minimapa
float map_x = screen_x - view_x_;
float map_y = screen_y - view_y_;
for (const auto& [name, mini] : room_positions_) {
float rx = static_cast<float>(cellPixelX(mini.pos.x));
float ry = static_cast<float>(cellPixelY(mini.pos.y));
if (map_x >= rx && map_x < rx + CELL_W && map_y >= ry && map_y < ry + CELL_H) {
return name;
}
}
return "";
}
// Renderiza el minimapa
void MiniMap::render(const std::string& current_room) {
if (!map_surface_) { return; }
auto game_surface = Screen::get()->getRendererSurface();
if (!game_surface) { return; }
// Centrar el minimapa en el play area, centrado en la room actual
auto it = room_positions_.find(current_room);
if (it == room_positions_.end()) { return; }
const auto& current_pos = it->second.pos;
int room_cx = cellPixelX(current_pos.x) + CELL_W / 2;
int room_cy = cellPixelY(current_pos.y) + CELL_H / 2;
int offset_x = PlayArea::WIDTH / 2 - room_cx;
int offset_y = PlayArea::HEIGHT / 2 - room_cy;
// Renderizar la surface del minimapa con offset
SDL_FRect dst = {.x = static_cast<float>(offset_x), .y = static_cast<float>(offset_y),
// Renderizar la surface del minimapa con el viewport actual (alineado a pixel)
float vx = std::floor(view_x_);
float vy = std::floor(view_y_);
SDL_FRect dst = {.x = vx, .y = vy,
.w = static_cast<float>(map_width_ + SHADOW_OFFSET), .h = static_cast<float>(map_height_ + SHADOW_OFFSET)};
map_surface_->render(nullptr, &dst);
// Highlight de la room actual (borde bright_white alrededor de la celda)
float cur_x = static_cast<float>(offset_x + cellPixelX(current_pos.x));
float cur_y = static_cast<float>(offset_y + cellPixelY(current_pos.y));
SDL_FRect highlight = {.x = cur_x - 1, .y = cur_y - 1,
.w = static_cast<float>(CELL_W + 2), .h = static_cast<float>(CELL_H + 2)};
game_surface->drawRectBorder(&highlight, stringToColor("bright_white"));
// Highlight de la room actual (solo si está completamente visible en el play area)
auto it = room_positions_.find(current_room);
if (it != room_positions_.end()) {
float cur_x = vx + static_cast<float>(cellPixelX(it->second.pos.x)) - 1;
float cur_y = vy + static_cast<float>(cellPixelY(it->second.pos.y)) - 1;
float cur_w = static_cast<float>(CELL_W + 2);
float cur_h = static_cast<float>(CELL_H + 2);
if (cur_x >= 0 && cur_y >= 0 && cur_x + cur_w <= PlayArea::WIDTH && cur_y + cur_h <= PlayArea::HEIGHT) {
SDL_FRect highlight = {.x = cur_x, .y = cur_y, .w = cur_w, .h = cur_h};
game_surface->drawRectBorder(&highlight, stringToColor("bright_white"));
}
}
}
// Maneja eventos del minimapa (drag para explorar, click para navegar)
void MiniMap::handleEvent(const SDL_Event& event, const std::string& current_room) {
if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN && event.button.button == SDL_BUTTON_LEFT) {
// Guardar posición inicial para detectar si es click o drag
float mouse_x = 0.0F;
float mouse_y = 0.0F;
SDL_GetMouseState(&mouse_x, &mouse_y);
float render_x = 0.0F;
float render_y = 0.0F;
SDL_RenderCoordinatesFromWindow(Screen::get()->getRenderer(), mouse_x, mouse_y, &render_x, &render_y);
SDL_FRect dst_rect = Screen::get()->getGameSurfaceDstRect();
dragging_ = true;
drag_start_x_ = render_x - dst_rect.x;
drag_start_y_ = render_y - dst_rect.y;
view_start_x_ = view_x_;
view_start_y_ = view_y_;
}
if (event.type == SDL_EVENT_MOUSE_MOTION && dragging_) {
float mouse_x = 0.0F;
float mouse_y = 0.0F;
SDL_GetMouseState(&mouse_x, &mouse_y);
float render_x = 0.0F;
float render_y = 0.0F;
SDL_RenderCoordinatesFromWindow(Screen::get()->getRenderer(), mouse_x, mouse_y, &render_x, &render_y);
SDL_FRect dst_rect = Screen::get()->getGameSurfaceDstRect();
float game_x = render_x - dst_rect.x;
float game_y = render_y - dst_rect.y;
view_x_ = view_start_x_ + (game_x - drag_start_x_);
view_y_ = view_start_y_ + (game_y - drag_start_y_);
}
if (event.type == SDL_EVENT_MOUSE_BUTTON_UP && event.button.button == SDL_BUTTON_LEFT) {
if (dragging_) {
// Comprobar si fue click (sin mover) o drag
float mouse_x = 0.0F;
float mouse_y = 0.0F;
SDL_GetMouseState(&mouse_x, &mouse_y);
float render_x = 0.0F;
float render_y = 0.0F;
SDL_RenderCoordinatesFromWindow(Screen::get()->getRenderer(), mouse_x, mouse_y, &render_x, &render_y);
SDL_FRect dst_rect = Screen::get()->getGameSurfaceDstRect();
float game_x = render_x - dst_rect.x;
float game_y = render_y - dst_rect.y;
float dx = game_x - drag_start_x_;
float dy = game_y - drag_start_y_;
bool was_click = (dx * dx + dy * dy) < 4.0F; // Menos de 2px de movimiento = click
if (was_click) {
// Click: navegar a la room bajo el cursor
std::string room = roomAtScreen(game_x, game_y);
if (!room.empty() && room != current_room && on_navigate) {
on_navigate(room);
}
}
dragging_ = false;
}
}
}
#endif // _DEBUG

View File

@@ -4,6 +4,7 @@
#include <SDL3/SDL.h>
#include <functional> // Para function
#include <memory> // Para shared_ptr
#include <string> // Para string
#include <unordered_map> // Para unordered_map
@@ -25,9 +26,14 @@ class MiniMap {
~MiniMap() = default;
void render(const std::string& current_room);
void rebuild(Uint8 bg_color, Uint8 conn_color); // Regenera la surface final
void handleEvent(const SDL_Event& event, const std::string& current_room);
void rebuild(Uint8 bg_color, Uint8 conn_color);
void centerOnRoom(const std::string& room_name);
[[nodiscard]] auto isReady() const -> bool { return !room_positions_.empty(); }
// Callback al hacer click en una minihabitación (nombre del room)
std::function<void(const std::string&)> on_navigate;
private:
// Posición de una room en el grid del minimapa
struct GridPos {
@@ -47,12 +53,14 @@ class MiniMap {
void composeFinalSurface();
auto getRoomMiniSurface(const std::string& room_name) -> std::shared_ptr<Surface>;
void drawConnections();
auto roomAtScreen(float screen_x, float screen_y) -> std::string;
auto cellPixelX(int grid_x) const -> int { return PADDING + (grid_x - min_grid_x_) * (CELL_W + GAP); }
auto cellPixelY(int grid_y) const -> int { return PADDING + (grid_y - min_grid_y_) * (CELL_H + GAP); }
// Tabla de color predominante por tile index
std::vector<Uint8> tile_colors_; // tile_index → palette color index
int tileset_width_{0}; // Ancho del tileset en tiles
std::vector<Uint8> tile_colors_; // tile_index → palette color index
int tileset_width_{0}; // Ancho del tileset en tiles
Uint8 tileset_transparent_{16}; // Color transparente del tileset
// Rooms renderizadas y posicionadas
std::unordered_map<std::string, RoomMini> room_positions_;
@@ -66,6 +74,15 @@ class MiniMap {
int min_grid_x_{0};
int min_grid_y_{0};
// Viewport: offset de la surface del minimapa respecto al play area
float view_x_{0.0F}; // Offset X actual
float view_y_{0.0F}; // Offset Y actual
bool dragging_{false};
float drag_start_x_{0.0F}; // Posición del ratón al inicio del drag
float drag_start_y_{0.0F};
float view_start_x_{0.0F}; // Viewport al inicio del drag
float view_start_y_{0.0F};
// Constantes
static constexpr int ROOM_W = 32; // Ancho de una room en pixels del minimapa
static constexpr int ROOM_H = 16; // Alto de una room en pixels del minimapa

View File

@@ -450,6 +450,7 @@ void Game::renderPlaying() {
// Si el editor está activo, delegar el renderizado de entidades y statusbar
if (MapEditor::get()->isActive()) {
MapEditor::get()->render();
renderRoomName();
Screen::get()->render();
return;
}