mes retocs a minimap. arreglat el calcul dels minipixels en els tiles amb transparent
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user