drag'n drop de enemics, boundaries i items
This commit is contained in:
@@ -36,8 +36,8 @@
|
|||||||
#include "utils/defines.hpp" // Para WINDOW_CAPTION
|
#include "utils/defines.hpp" // Para WINDOW_CAPTION
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#include "core/system/debug.hpp" // Para Debug
|
#include "core/system/debug.hpp" // Para Debug
|
||||||
#include "game/editor/map_editor.hpp" // Para MapEditor
|
#include "game/editor/map_editor.hpp" // Para MapEditor
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
|||||||
@@ -4,13 +4,13 @@
|
|||||||
|
|
||||||
#include <string> // Para to_string
|
#include <string> // Para to_string
|
||||||
|
|
||||||
#include "core/rendering/screen.hpp" // Para Screen
|
#include "core/rendering/screen.hpp" // Para Screen
|
||||||
#include "core/rendering/surface.hpp" // Para Surface
|
#include "core/rendering/surface.hpp" // Para Surface
|
||||||
#include "core/rendering/text.hpp" // Para Text
|
#include "core/rendering/text.hpp" // Para Text
|
||||||
#include "core/resources/resource_cache.hpp" // Para Resource::Cache
|
#include "core/resources/resource_cache.hpp" // Para Resource::Cache
|
||||||
#include "game/options.hpp" // Para Options::game
|
#include "game/options.hpp" // Para Options::game
|
||||||
#include "utils/defines.hpp" // Para Tile::SIZE
|
#include "utils/defines.hpp" // Para Tile::SIZE
|
||||||
#include "utils/utils.hpp" // Para stringToColor
|
#include "utils/utils.hpp" // Para stringToColor
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
EditorStatusBar::EditorStatusBar(const std::string& room_number, const std::string& room_name)
|
EditorStatusBar::EditorStatusBar(const std::string& room_number, const std::string& room_name)
|
||||||
@@ -39,6 +39,11 @@ void EditorStatusBar::setMouseTile(int tile_x, int tile_y) {
|
|||||||
mouse_tile_y_ = tile_y;
|
mouse_tile_y_ = tile_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Establece la información de la entidad seleccionada
|
||||||
|
void EditorStatusBar::setSelectionInfo(const std::string& info) {
|
||||||
|
selection_info_ = info;
|
||||||
|
}
|
||||||
|
|
||||||
// Dibuja los elementos en la surface
|
// Dibuja los elementos en la surface
|
||||||
void EditorStatusBar::fillTexture() {
|
void EditorStatusBar::fillTexture() {
|
||||||
auto previous_renderer = Screen::get()->getRendererSurface();
|
auto previous_renderer = Screen::get()->getRendererSurface();
|
||||||
@@ -60,8 +65,12 @@ void EditorStatusBar::fillTexture() {
|
|||||||
text->writeColored(LEFT_X, LINE2_Y, "TILE:", LABEL_COLOR);
|
text->writeColored(LEFT_X, LINE2_Y, "TILE:", LABEL_COLOR);
|
||||||
text->writeColored(LEFT_X + 48, LINE2_Y, TILE_X_STR + "," + TILE_Y_STR, VALUE_COLOR);
|
text->writeColored(LEFT_X + 48, LINE2_Y, TILE_X_STR + "," + TILE_Y_STR, VALUE_COLOR);
|
||||||
|
|
||||||
// Indicador de modo editor
|
// Info de selección o indicador de modo editor
|
||||||
text->writeColored(176, LINE2_Y, "EDITOR", stringToColor("bright_green"));
|
if (!selection_info_.empty()) {
|
||||||
|
text->writeColored(LEFT_X + 112, LINE2_Y, selection_info_, stringToColor("bright_yellow"));
|
||||||
|
} else {
|
||||||
|
text->writeColored(176, LINE2_Y, "EDITOR", stringToColor("bright_green"));
|
||||||
|
}
|
||||||
|
|
||||||
Screen::get()->setRendererSurface(previous_renderer);
|
Screen::get()->setRendererSurface(previous_renderer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class EditorStatusBar {
|
|||||||
void render();
|
void render();
|
||||||
void update(float delta_time);
|
void update(float delta_time);
|
||||||
void setMouseTile(int tile_x, int tile_y);
|
void setMouseTile(int tile_x, int tile_y);
|
||||||
|
void setSelectionInfo(const std::string& info);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void fillTexture(); // Dibuja los elementos en la surface
|
void fillTexture(); // Dibuja los elementos en la surface
|
||||||
@@ -31,10 +32,11 @@ class EditorStatusBar {
|
|||||||
SDL_FRect surface_dest_{}; // Rectángulo destino en pantalla
|
SDL_FRect surface_dest_{}; // Rectángulo destino en pantalla
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
std::string room_number_; // Número de la habitación
|
std::string room_number_; // Número de la habitación
|
||||||
std::string room_name_; // Nombre de la habitación
|
std::string room_name_; // Nombre de la habitación
|
||||||
int mouse_tile_x_{0}; // Coordenada X del ratón en tiles
|
int mouse_tile_x_{0}; // Coordenada X del ratón en tiles
|
||||||
int mouse_tile_y_{0}; // Coordenada Y del ratón en tiles
|
int mouse_tile_y_{0}; // Coordenada Y del ratón en tiles
|
||||||
|
std::string selection_info_; // Información de la entidad seleccionada
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
|
|||||||
@@ -7,16 +7,18 @@
|
|||||||
#include <cmath> // Para std::round
|
#include <cmath> // Para std::round
|
||||||
#include <iostream> // Para cout
|
#include <iostream> // Para cout
|
||||||
|
|
||||||
#include "core/input/mouse.hpp" // Para Mouse
|
#include "core/input/mouse.hpp" // Para Mouse
|
||||||
#include "core/rendering/screen.hpp" // Para Screen
|
#include "core/rendering/screen.hpp" // Para Screen
|
||||||
#include "core/rendering/surface.hpp" // Para Surface
|
#include "core/rendering/surface.hpp" // Para Surface
|
||||||
#include "core/resources/resource_cache.hpp" // Para Resource::Cache
|
#include "core/resources/resource_cache.hpp" // Para Resource::Cache
|
||||||
#include "game/editor/editor_statusbar.hpp" // Para EditorStatusBar
|
#include "game/editor/editor_statusbar.hpp" // Para EditorStatusBar
|
||||||
#include "game/entities/player.hpp" // Para Player
|
#include "game/entities/player.hpp" // Para Player
|
||||||
#include "game/gameplay/room.hpp" // Para Room
|
#include "game/gameplay/enemy_manager.hpp" // Para EnemyManager
|
||||||
#include "game/options.hpp" // Para Options
|
#include "game/gameplay/item_manager.hpp" // Para ItemManager
|
||||||
#include "utils/defines.hpp" // Para Tile::SIZE, PlayArea
|
#include "game/gameplay/room.hpp" // Para Room
|
||||||
#include "utils/utils.hpp" // Para stringToColor
|
#include "game/options.hpp" // Para Options
|
||||||
|
#include "utils/defines.hpp" // Para Tile::SIZE, PlayArea
|
||||||
|
#include "utils/utils.hpp" // Para stringToColor
|
||||||
|
|
||||||
// Singleton
|
// Singleton
|
||||||
MapEditor* MapEditor::instance_ = nullptr;
|
MapEditor* MapEditor::instance_ = nullptr;
|
||||||
@@ -41,8 +43,7 @@ MapEditor::MapEditor() = default;
|
|||||||
MapEditor::~MapEditor() = default;
|
MapEditor::~MapEditor() = default;
|
||||||
|
|
||||||
// Entra en modo editor
|
// Entra en modo editor
|
||||||
void MapEditor::enter(std::shared_ptr<Room> room, std::shared_ptr<Player> player,
|
void MapEditor::enter(std::shared_ptr<Room> room, std::shared_ptr<Player> player, const std::string& room_path, std::shared_ptr<Scoreboard::Data> scoreboard_data) {
|
||||||
const std::string& room_path, std::shared_ptr<Scoreboard::Data> scoreboard_data) {
|
|
||||||
if (active_) { return; }
|
if (active_) { return; }
|
||||||
|
|
||||||
room_ = std::move(room);
|
room_ = std::move(room);
|
||||||
@@ -61,6 +62,9 @@ void MapEditor::enter(std::shared_ptr<Room> room, std::shared_ptr<Player> player
|
|||||||
Options::cheats.invincible = Options::Cheat::State::ENABLED;
|
Options::cheats.invincible = Options::Cheat::State::ENABLED;
|
||||||
player_->setColor();
|
player_->setColor();
|
||||||
|
|
||||||
|
// Resetear enemigos a su posición inicial (pueden haberse movido durante el gameplay)
|
||||||
|
room_->resetEnemyPositions(room_data_.enemies);
|
||||||
|
|
||||||
// Crear la barra de estado
|
// Crear la barra de estado
|
||||||
statusbar_ = std::make_unique<EditorStatusBar>(room_->getNumber(), room_->getName());
|
statusbar_ = std::make_unique<EditorStatusBar>(room_->getNumber(), room_->getName());
|
||||||
|
|
||||||
@@ -108,9 +112,34 @@ void MapEditor::update(float delta_time) {
|
|||||||
updateDrag();
|
updateDrag();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualizar la barra de estado con las coordenadas del ratón
|
// Actualizar la barra de estado con las coordenadas del ratón y la selección
|
||||||
if (statusbar_) {
|
if (statusbar_) {
|
||||||
statusbar_->setMouseTile(mouse_tile_x_, mouse_tile_y_);
|
statusbar_->setMouseTile(mouse_tile_x_, mouse_tile_y_);
|
||||||
|
|
||||||
|
// Construir info de selección
|
||||||
|
std::string sel_info;
|
||||||
|
if (drag_.target != DragTarget::NONE) {
|
||||||
|
switch (drag_.target) {
|
||||||
|
case DragTarget::PLAYER:
|
||||||
|
sel_info = "PLAYER";
|
||||||
|
break;
|
||||||
|
case DragTarget::ENEMY_INITIAL:
|
||||||
|
sel_info = "ENEMY " + std::to_string(drag_.index);
|
||||||
|
break;
|
||||||
|
case DragTarget::ENEMY_BOUND1:
|
||||||
|
sel_info = "E" + std::to_string(drag_.index) + " BOUND1";
|
||||||
|
break;
|
||||||
|
case DragTarget::ENEMY_BOUND2:
|
||||||
|
sel_info = "E" + std::to_string(drag_.index) + " BOUND2";
|
||||||
|
break;
|
||||||
|
case DragTarget::ITEM:
|
||||||
|
sel_info = "ITEM " + std::to_string(drag_.index);
|
||||||
|
break;
|
||||||
|
case DragTarget::NONE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statusbar_->setSelectionInfo(sel_info);
|
||||||
statusbar_->update(delta_time);
|
statusbar_->update(delta_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,34 +176,108 @@ void MapEditor::handleEvent(const SDL_Event& event) {
|
|||||||
|
|
||||||
// Procesa click del ratón: hit test + inicio de drag
|
// Procesa click del ratón: hit test + inicio de drag
|
||||||
void MapEditor::handleMouseDown(float game_x, float game_y) {
|
void MapEditor::handleMouseDown(float game_x, float game_y) {
|
||||||
// Prioridad de hit test: jugador → enemigos → items
|
// Prioridad de hit test: jugador → enemigos (initial) → enemigos (boundaries) → items
|
||||||
|
|
||||||
// 1. Hit test sobre el jugador
|
// Helper para iniciar drag
|
||||||
|
auto startDrag = [&](DragTarget target, int index, float entity_x, float entity_y) {
|
||||||
|
drag_.target = target;
|
||||||
|
drag_.index = index;
|
||||||
|
drag_.offset_x = game_x - entity_x;
|
||||||
|
drag_.offset_y = game_y - entity_y;
|
||||||
|
drag_.snap_x = entity_x;
|
||||||
|
drag_.snap_y = entity_y;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1. Hit test sobre el jugador (8x16)
|
||||||
SDL_FRect player_rect = player_->getRect();
|
SDL_FRect player_rect = player_->getRect();
|
||||||
if (pointInRect(game_x, game_y, player_rect)) {
|
if (pointInRect(game_x, game_y, player_rect)) {
|
||||||
drag_.target = DragTarget::PLAYER;
|
startDrag(DragTarget::PLAYER, -1, player_rect.x, player_rect.y);
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// (Fases 4+: hit test sobre enemigos e items)
|
// 2. Hit test sobre enemigos: posición inicial (usan el rect del sprite vivo)
|
||||||
|
auto* enemy_mgr = room_->getEnemyManager();
|
||||||
|
for (int i = 0; i < enemy_mgr->getCount(); ++i) {
|
||||||
|
SDL_FRect enemy_rect = enemy_mgr->getEnemy(i)->getRect();
|
||||||
|
if (pointInRect(game_x, game_y, enemy_rect)) {
|
||||||
|
startDrag(DragTarget::ENEMY_INITIAL, i, enemy_rect.x, enemy_rect.y);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Hit test sobre boundaries de enemigos (rectángulos 8x8 en las posiciones de room_data_)
|
||||||
|
for (int i = 0; i < static_cast<int>(room_data_.enemies.size()); ++i) {
|
||||||
|
const auto& ed = room_data_.enemies[i];
|
||||||
|
constexpr float SZ = static_cast<float>(Tile::SIZE);
|
||||||
|
|
||||||
|
SDL_FRect b1_rect = {.x = static_cast<float>(ed.x1), .y = static_cast<float>(ed.y1), .w = SZ, .h = SZ};
|
||||||
|
if (pointInRect(game_x, game_y, b1_rect)) {
|
||||||
|
startDrag(DragTarget::ENEMY_BOUND1, i, b1_rect.x, b1_rect.y);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_FRect b2_rect = {.x = static_cast<float>(ed.x2), .y = static_cast<float>(ed.y2), .w = SZ, .h = SZ};
|
||||||
|
if (pointInRect(game_x, game_y, b2_rect)) {
|
||||||
|
startDrag(DragTarget::ENEMY_BOUND2, i, b2_rect.x, b2_rect.y);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Hit test sobre items (8x8)
|
||||||
|
auto* item_mgr = room_->getItemManager();
|
||||||
|
for (int i = 0; i < item_mgr->getCount(); ++i) {
|
||||||
|
SDL_FRect item_rect = item_mgr->getItem(i)->getCollider();
|
||||||
|
if (pointInRect(game_x, game_y, item_rect)) {
|
||||||
|
startDrag(DragTarget::ITEM, i, item_rect.x, item_rect.y);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Procesa soltar el ratón: commit del drag
|
// Procesa soltar el ratón: commit del drag
|
||||||
void MapEditor::handleMouseUp() {
|
void MapEditor::handleMouseUp() {
|
||||||
if (drag_.target == DragTarget::NONE) { return; }
|
if (drag_.target == DragTarget::NONE) { return; }
|
||||||
|
|
||||||
|
const int IDX = drag_.index;
|
||||||
|
const int SNAP_X = static_cast<int>(drag_.snap_x);
|
||||||
|
const int SNAP_Y = static_cast<int>(drag_.snap_y);
|
||||||
|
|
||||||
switch (drag_.target) {
|
switch (drag_.target) {
|
||||||
case DragTarget::PLAYER:
|
case DragTarget::PLAYER:
|
||||||
// Mover el jugador a la posición snapped
|
|
||||||
player_->setDebugPosition(drag_.snap_x, drag_.snap_y);
|
player_->setDebugPosition(drag_.snap_x, drag_.snap_y);
|
||||||
player_->finalizeDebugTeleport();
|
player_->finalizeDebugTeleport();
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
|
case DragTarget::ENEMY_INITIAL:
|
||||||
|
// Actualizar datos mutables y posición del sprite vivo
|
||||||
|
if (IDX >= 0 && IDX < static_cast<int>(room_data_.enemies.size())) {
|
||||||
|
room_data_.enemies[IDX].x = drag_.snap_x;
|
||||||
|
room_data_.enemies[IDX].y = drag_.snap_y;
|
||||||
|
room_->getEnemyManager()->getEnemy(IDX)->resetToInitialPosition(room_data_.enemies[IDX]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DragTarget::ENEMY_BOUND1:
|
||||||
|
if (IDX >= 0 && IDX < static_cast<int>(room_data_.enemies.size())) {
|
||||||
|
room_data_.enemies[IDX].x1 = SNAP_X;
|
||||||
|
room_data_.enemies[IDX].y1 = SNAP_Y;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DragTarget::ENEMY_BOUND2:
|
||||||
|
if (IDX >= 0 && IDX < static_cast<int>(room_data_.enemies.size())) {
|
||||||
|
room_data_.enemies[IDX].x2 = SNAP_X;
|
||||||
|
room_data_.enemies[IDX].y2 = SNAP_Y;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DragTarget::ITEM:
|
||||||
|
if (IDX >= 0 && IDX < room_->getItemManager()->getCount()) {
|
||||||
|
room_->getItemManager()->getItem(IDX)->setPosition(drag_.snap_x, drag_.snap_y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DragTarget::NONE:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,8 +294,37 @@ void MapEditor::updateDrag() {
|
|||||||
drag_.snap_y = snapToGrid(raw_y);
|
drag_.snap_y = snapToGrid(raw_y);
|
||||||
|
|
||||||
// Mientras arrastramos, mover la entidad visualmente a la posición snapped
|
// Mientras arrastramos, mover la entidad visualmente a la posición snapped
|
||||||
if (drag_.target == DragTarget::PLAYER) {
|
switch (drag_.target) {
|
||||||
player_->setDebugPosition(drag_.snap_x, drag_.snap_y);
|
case DragTarget::PLAYER:
|
||||||
|
player_->setDebugPosition(drag_.snap_x, drag_.snap_y);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DragTarget::ENEMY_INITIAL:
|
||||||
|
if (drag_.index >= 0 && drag_.index < room_->getEnemyManager()->getCount()) {
|
||||||
|
// Mover el sprite vivo del enemigo durante el arrastre
|
||||||
|
auto& enemy = room_->getEnemyManager()->getEnemy(drag_.index);
|
||||||
|
Enemy::Data temp_data = room_data_.enemies[drag_.index];
|
||||||
|
temp_data.x = drag_.snap_x;
|
||||||
|
temp_data.y = drag_.snap_y;
|
||||||
|
enemy->resetToInitialPosition(temp_data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DragTarget::ENEMY_BOUND1:
|
||||||
|
// Los boundaries se actualizan visualmente en renderEnemyBoundaries() via drag_.snap
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DragTarget::ENEMY_BOUND2:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DragTarget::ITEM:
|
||||||
|
if (drag_.index >= 0 && drag_.index < room_->getItemManager()->getCount()) {
|
||||||
|
room_->getItemManager()->getItem(drag_.index)->setPosition(drag_.snap_x, drag_.snap_y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DragTarget::NONE:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,13 +336,32 @@ void MapEditor::renderSelectionHighlight() {
|
|||||||
if (!game_surface) { return; }
|
if (!game_surface) { return; }
|
||||||
|
|
||||||
const Uint8 HIGHLIGHT_COLOR = stringToColor("bright_white");
|
const Uint8 HIGHLIGHT_COLOR = stringToColor("bright_white");
|
||||||
|
constexpr float SZ = static_cast<float>(Tile::SIZE);
|
||||||
|
|
||||||
SDL_FRect highlight_rect{};
|
SDL_FRect highlight_rect{};
|
||||||
switch (drag_.target) {
|
switch (drag_.target) {
|
||||||
case DragTarget::PLAYER:
|
case DragTarget::PLAYER:
|
||||||
highlight_rect = player_->getRect();
|
highlight_rect = player_->getRect();
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
|
case DragTarget::ENEMY_INITIAL:
|
||||||
|
if (drag_.index >= 0 && drag_.index < room_->getEnemyManager()->getCount()) {
|
||||||
|
highlight_rect = room_->getEnemyManager()->getEnemy(drag_.index)->getRect();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DragTarget::ENEMY_BOUND1:
|
||||||
|
case DragTarget::ENEMY_BOUND2:
|
||||||
|
highlight_rect = {.x = drag_.snap_x, .y = drag_.snap_y, .w = SZ, .h = SZ};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DragTarget::ITEM:
|
||||||
|
if (drag_.index >= 0 && drag_.index < room_->getItemManager()->getCount()) {
|
||||||
|
highlight_rect = room_->getItemManager()->getItem(drag_.index)->getCollider();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DragTarget::NONE:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,8 +370,7 @@ void MapEditor::renderSelectionHighlight() {
|
|||||||
.x = highlight_rect.x - 1,
|
.x = highlight_rect.x - 1,
|
||||||
.y = highlight_rect.y - 1,
|
.y = highlight_rect.y - 1,
|
||||||
.w = highlight_rect.w + 2,
|
.w = highlight_rect.w + 2,
|
||||||
.h = highlight_rect.h + 2
|
.h = highlight_rect.h + 2};
|
||||||
};
|
|
||||||
game_surface->drawRectBorder(&border, HIGHLIGHT_COLOR);
|
game_surface->drawRectBorder(&border, HIGHLIGHT_COLOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,25 +393,39 @@ void MapEditor::renderEnemyBoundaries() {
|
|||||||
const Uint8 COLOR_BOUND2 = stringToColor("bright_yellow");
|
const Uint8 COLOR_BOUND2 = stringToColor("bright_yellow");
|
||||||
const Uint8 COLOR_ROUTE = stringToColor("bright_white");
|
const Uint8 COLOR_ROUTE = stringToColor("bright_white");
|
||||||
|
|
||||||
for (const auto& enemy : room_data_.enemies) {
|
for (int i = 0; i < static_cast<int>(room_data_.enemies.size()); ++i) {
|
||||||
// Dibujar línea de ruta: boundary1 → posición inicial → boundary2
|
const auto& enemy = room_data_.enemies[i];
|
||||||
constexpr float HALF = Tile::SIZE / 2.0F;
|
constexpr float HALF = Tile::SIZE / 2.0F;
|
||||||
|
|
||||||
float init_cx = enemy.x + HALF;
|
// Posiciones base (pueden estar siendo arrastradas)
|
||||||
float init_cy = enemy.y + HALF;
|
float init_x = enemy.x;
|
||||||
float b1_cx = static_cast<float>(enemy.x1) + HALF;
|
float init_y = enemy.y;
|
||||||
float b1_cy = static_cast<float>(enemy.y1) + HALF;
|
float b1_x = static_cast<float>(enemy.x1);
|
||||||
float b2_cx = static_cast<float>(enemy.x2) + HALF;
|
float b1_y = static_cast<float>(enemy.y1);
|
||||||
float b2_cy = static_cast<float>(enemy.y2) + HALF;
|
float b2_x = static_cast<float>(enemy.x2);
|
||||||
|
float b2_y = static_cast<float>(enemy.y2);
|
||||||
|
|
||||||
// Línea de boundary1 a posición inicial
|
// Si estamos arrastrando una boundary de este enemigo, usar la posición snapped
|
||||||
game_surface->drawLine(b1_cx, b1_cy, init_cx, init_cy, COLOR_ROUTE);
|
if (drag_.index == i) {
|
||||||
// Línea de posición inicial a boundary2
|
if (drag_.target == DragTarget::ENEMY_BOUND1) {
|
||||||
game_surface->drawLine(init_cx, init_cy, b2_cx, b2_cy, COLOR_ROUTE);
|
b1_x = drag_.snap_x;
|
||||||
|
b1_y = drag_.snap_y;
|
||||||
|
} else if (drag_.target == DragTarget::ENEMY_BOUND2) {
|
||||||
|
b2_x = drag_.snap_x;
|
||||||
|
b2_y = drag_.snap_y;
|
||||||
|
} else if (drag_.target == DragTarget::ENEMY_INITIAL) {
|
||||||
|
init_x = drag_.snap_x;
|
||||||
|
init_y = drag_.snap_y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dibujar líneas de ruta
|
||||||
|
game_surface->drawLine(b1_x + HALF, b1_y + HALF, init_x + HALF, init_y + HALF, COLOR_ROUTE);
|
||||||
|
game_surface->drawLine(init_x + HALF, init_y + HALF, b2_x + HALF, b2_y + HALF, COLOR_ROUTE);
|
||||||
|
|
||||||
// Marcadores en las boundaries
|
// Marcadores en las boundaries
|
||||||
renderBoundaryMarker(static_cast<float>(enemy.x1), static_cast<float>(enemy.y1), COLOR_BOUND1);
|
renderBoundaryMarker(b1_x, b1_y, COLOR_BOUND1);
|
||||||
renderBoundaryMarker(static_cast<float>(enemy.x2), static_cast<float>(enemy.y2), COLOR_BOUND2);
|
renderBoundaryMarker(b2_x, b2_y, COLOR_BOUND2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,11 @@ class EditorStatusBar;
|
|||||||
|
|
||||||
class MapEditor {
|
class MapEditor {
|
||||||
public:
|
public:
|
||||||
static void init(); // [SINGLETON] Crea el objeto
|
static void init(); // [SINGLETON] Crea el objeto
|
||||||
static void destroy(); // [SINGLETON] Destruye el objeto
|
static void destroy(); // [SINGLETON] Destruye el objeto
|
||||||
static auto get() -> MapEditor*; // [SINGLETON] Obtiene el objeto
|
static auto get() -> MapEditor*; // [SINGLETON] Obtiene el objeto
|
||||||
|
|
||||||
void enter(std::shared_ptr<Room> room, std::shared_ptr<Player> player,
|
void enter(std::shared_ptr<Room> room, std::shared_ptr<Player> player, const std::string& room_path, std::shared_ptr<Scoreboard::Data> scoreboard_data);
|
||||||
const std::string& room_path, std::shared_ptr<Scoreboard::Data> scoreboard_data);
|
|
||||||
void exit();
|
void exit();
|
||||||
[[nodiscard]] auto isActive() const -> bool { return active_; }
|
[[nodiscard]] auto isActive() const -> bool { return active_; }
|
||||||
|
|
||||||
@@ -38,26 +37,31 @@ class MapEditor {
|
|||||||
~MapEditor(); // Destructor
|
~MapEditor(); // Destructor
|
||||||
|
|
||||||
// Tipos para drag & drop
|
// Tipos para drag & drop
|
||||||
enum class DragTarget { NONE, PLAYER, ENEMY_INITIAL, ENEMY_BOUND1, ENEMY_BOUND2, ITEM };
|
enum class DragTarget { NONE,
|
||||||
|
PLAYER,
|
||||||
|
ENEMY_INITIAL,
|
||||||
|
ENEMY_BOUND1,
|
||||||
|
ENEMY_BOUND2,
|
||||||
|
ITEM };
|
||||||
|
|
||||||
struct DragState {
|
struct DragState {
|
||||||
DragTarget target{DragTarget::NONE};
|
DragTarget target{DragTarget::NONE};
|
||||||
int index{-1}; // Índice del enemigo o item en room_data_
|
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_x{0.0F}; // Offset entre el cursor y el origen de la entidad al inicio del drag
|
||||||
float offset_y{0.0F};
|
float offset_y{0.0F};
|
||||||
float snap_x{0.0F}; // Posición snapped actual (para preview)
|
float snap_x{0.0F}; // Posición snapped actual (para preview)
|
||||||
float snap_y{0.0F};
|
float snap_y{0.0F};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Métodos internos
|
// Métodos internos
|
||||||
void updateMousePosition(); // Convierte coordenadas de ventana a coordenadas de juego y tile
|
void updateMousePosition(); // Convierte coordenadas de ventana a coordenadas de juego y tile
|
||||||
void renderEnemyBoundaries(); // Dibuja marcadores de boundaries y líneas de ruta
|
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 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 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 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 handleMouseUp(); // Procesa soltar el ratón (commit del drag)
|
||||||
void updateDrag(); // Actualiza la posición snapped durante el 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 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
|
static auto pointInRect(float px, float py, const SDL_FRect& rect) -> bool; // Hit test punto en rectángulo
|
||||||
|
|
||||||
// Estado del editor
|
// Estado del editor
|
||||||
|
|||||||
@@ -53,6 +53,20 @@ void Enemy::update(float delta_time) {
|
|||||||
void Enemy::updateAnimation(float delta_time) {
|
void Enemy::updateAnimation(float delta_time) {
|
||||||
sprite_->animate(delta_time);
|
sprite_->animate(delta_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resetea el enemigo a su posición inicial (para editor)
|
||||||
|
void Enemy::resetToInitialPosition(const Data& data) {
|
||||||
|
sprite_->setPosX(data.x);
|
||||||
|
sprite_->setPosY(data.y);
|
||||||
|
sprite_->setVelX(data.vx);
|
||||||
|
sprite_->setVelY(data.vy);
|
||||||
|
|
||||||
|
const int FLIP = (should_flip_ && data.vx < 0.0F) ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
|
||||||
|
const int MIRROR = should_mirror_ ? SDL_FLIP_VERTICAL : SDL_FLIP_NONE;
|
||||||
|
sprite_->setFlip(static_cast<SDL_FlipMode>(FLIP | MIRROR));
|
||||||
|
|
||||||
|
collider_ = getRect();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Comprueba si ha llegado al limite del recorrido para darse media vuelta
|
// Comprueba si ha llegado al limite del recorrido para darse media vuelta
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ class Enemy {
|
|||||||
void render(); // Pinta el enemigo en pantalla
|
void render(); // Pinta el enemigo en pantalla
|
||||||
void update(float delta_time); // Actualiza las variables del objeto
|
void update(float delta_time); // Actualiza las variables del objeto
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
void updateAnimation(float delta_time); // Solo actualiza la animación sin mover al enemigo
|
void updateAnimation(float delta_time); // Solo actualiza la animación sin mover al enemigo
|
||||||
|
void resetToInitialPosition(const Data& data); // Resetea el enemigo a su posición inicial (para editor)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto getRect() -> SDL_FRect; // Devuelve el rectangulo que contiene al enemigo
|
auto getRect() -> SDL_FRect; // Devuelve el rectangulo que contiene al enemigo
|
||||||
|
|||||||
@@ -41,6 +41,14 @@ auto Item::getPos() -> SDL_FPoint { // NOLINT(readability-convert-member-functi
|
|||||||
return P;
|
return P;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
// Establece la posición del item (para editor)
|
||||||
|
void Item::setPosition(float x, float y) {
|
||||||
|
sprite_->setPosition(x, y);
|
||||||
|
collider_ = sprite_->getRect();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Asigna los colores del objeto
|
// Asigna los colores del objeto
|
||||||
void Item::setColors(Uint8 col1, Uint8 col2) {
|
void Item::setColors(Uint8 col1, Uint8 col2) {
|
||||||
// Reinicializa el vector de colores
|
// Reinicializa el vector de colores
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ class Item {
|
|||||||
auto getCollider() -> SDL_FRect& { return collider_; } // Obtiene el rectangulo de colision del objeto
|
auto getCollider() -> SDL_FRect& { return collider_; } // Obtiene el rectangulo de colision del objeto
|
||||||
auto getPos() -> SDL_FPoint; // Obtiene su ubicación
|
auto getPos() -> SDL_FPoint; // Obtiene su ubicación
|
||||||
void setColors(Uint8 col1, Uint8 col2); // Asigna los colores del objeto
|
void setColors(Uint8 col1, Uint8 col2); // Asigna los colores del objeto
|
||||||
|
#ifdef _DEBUG
|
||||||
|
void setPosition(float x, float y); // Establece la posición del item (para editor)
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr float ITEM_SIZE = 8.0F; // Tamaño del item en pixels
|
static constexpr float ITEM_SIZE = 8.0F; // Tamaño del item en pixels
|
||||||
|
|||||||
@@ -48,6 +48,24 @@ void EnemyManager::updateAnimations(float delta_time) {
|
|||||||
enemy->updateAnimation(delta_time);
|
enemy->updateAnimation(delta_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resetea todos los enemigos a su posición inicial
|
||||||
|
void EnemyManager::resetPositions(const std::vector<Enemy::Data>& enemy_data) {
|
||||||
|
const int COUNT = std::min(static_cast<int>(enemies_.size()), static_cast<int>(enemy_data.size()));
|
||||||
|
for (int i = 0; i < COUNT; ++i) {
|
||||||
|
enemies_[i]->resetToInitialPosition(enemy_data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Número de enemigos
|
||||||
|
auto EnemyManager::getCount() const -> int {
|
||||||
|
return static_cast<int>(enemies_.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acceso a un enemigo por índice
|
||||||
|
auto EnemyManager::getEnemy(int index) -> std::shared_ptr<Enemy>& {
|
||||||
|
return enemies_.at(index);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Comprueba si hay colisión con algún enemigo
|
// Comprueba si hay colisión con algún enemigo
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <memory> // Para shared_ptr
|
#include <memory> // Para shared_ptr
|
||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
class Enemy;
|
#include "game/entities/enemy.hpp" // Para Enemy, Enemy::Data
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gestor de enemigos de una habitación
|
* @brief Gestor de enemigos de una habitación
|
||||||
@@ -41,7 +41,10 @@ class EnemyManager {
|
|||||||
auto checkCollision(SDL_FRect& rect) -> bool; // Comprueba si hay colisión con algún enemigo
|
auto checkCollision(SDL_FRect& rect) -> bool; // Comprueba si hay colisión con algún enemigo
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
void updateAnimations(float delta_time); // Solo actualiza animaciones sin mover enemigos
|
void updateAnimations(float delta_time); // Solo actualiza animaciones sin mover enemigos
|
||||||
|
void resetPositions(const std::vector<Enemy::Data>& enemy_data); // Resetea todos los enemigos a su posición inicial
|
||||||
|
[[nodiscard]] auto getCount() const -> int; // Número de enemigos
|
||||||
|
auto getEnemy(int index) -> std::shared_ptr<Enemy>&; // Acceso a un enemigo por índice
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -6,9 +6,8 @@
|
|||||||
#include <string> // Para string
|
#include <string> // Para string
|
||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
#include "scoreboard.hpp" // Para Scoreboard::Data
|
#include "game/entities/item.hpp" // Para Item, Item::Data
|
||||||
|
#include "scoreboard.hpp" // Para Scoreboard::Data
|
||||||
class Item;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gestor de items de una habitación
|
* @brief Gestor de items de una habitación
|
||||||
@@ -47,6 +46,11 @@ class ItemManager {
|
|||||||
// Estado
|
// Estado
|
||||||
void setPaused(bool paused); // Pausa/despausa todos los items
|
void setPaused(bool paused); // Pausa/despausa todos los items
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
[[nodiscard]] auto getCount() const -> int { return static_cast<int>(items_.size()); } // Número de items
|
||||||
|
auto getItem(int index) -> std::shared_ptr<Item>& { return items_.at(index); } // Acceso a un item por índice
|
||||||
|
#endif
|
||||||
|
|
||||||
// Detección de colisiones
|
// Detección de colisiones
|
||||||
/**
|
/**
|
||||||
* @brief Comprueba si hay colisión con algún item
|
* @brief Comprueba si hay colisión con algún item
|
||||||
|
|||||||
@@ -128,6 +128,11 @@ void Room::updateEditorMode(float delta_time) {
|
|||||||
enemy_manager_->updateAnimations(delta_time);
|
enemy_manager_->updateAnimations(delta_time);
|
||||||
item_manager_->update(delta_time);
|
item_manager_->update(delta_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resetea enemigos a posiciones iniciales (para editor de mapas)
|
||||||
|
void Room::resetEnemyPositions(const std::vector<Enemy::Data>& enemy_data) {
|
||||||
|
enemy_manager_->resetPositions(enemy_data);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Actualiza las variables y objetos de la habitación
|
// Actualiza las variables y objetos de la habitación
|
||||||
|
|||||||
@@ -69,8 +69,11 @@ class Room {
|
|||||||
void renderEnemies(); // Dibuja los enemigos en pantalla
|
void renderEnemies(); // Dibuja los enemigos en pantalla
|
||||||
void renderItems(); // Dibuja los objetos en pantalla
|
void renderItems(); // Dibuja los objetos en pantalla
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
void redrawMap(); // Redibuja el mapa (para actualizar modo debug)
|
void redrawMap(); // Redibuja el mapa (para actualizar modo debug)
|
||||||
void updateEditorMode(float delta_time); // Actualiza animaciones sin mover enemigos (para editor)
|
void updateEditorMode(float delta_time); // Actualiza animaciones sin mover enemigos (para editor)
|
||||||
|
void resetEnemyPositions(const std::vector<Enemy::Data>& enemy_data); // Resetea enemigos a posiciones iniciales
|
||||||
|
auto getEnemyManager() -> EnemyManager* { return enemy_manager_.get(); } // Acceso al gestor de enemigos (para editor)
|
||||||
|
auto getItemManager() -> ItemManager* { return item_manager_.get(); } // Acceso al gestor de items (para editor)
|
||||||
#endif
|
#endif
|
||||||
void update(float delta_time); // Actualiza las variables y objetos de la habitación
|
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
|
auto getRoom(Border border) -> std::string; // Devuelve la cadena del fichero de la habitación contigua segun el borde
|
||||||
|
|||||||
@@ -32,8 +32,8 @@
|
|||||||
#include "utils/utils.hpp" // Para PaletteColor, stringToColor
|
#include "utils/utils.hpp" // Para PaletteColor, stringToColor
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#include "core/system/debug.hpp" // Para Debug
|
#include "core/system/debug.hpp" // Para Debug
|
||||||
#include "game/editor/map_editor.hpp" // Para MapEditor
|
#include "game/editor/map_editor.hpp" // Para MapEditor
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
|
|||||||
Reference in New Issue
Block a user