treballant en editor de items i tile_picker
This commit is contained in:
@@ -13,13 +13,13 @@
|
||||
#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/ui/console.hpp" // Para Console
|
||||
#include "game/editor/room_saver.hpp" // Para RoomSaver
|
||||
#include "game/entities/player.hpp" // Para Player
|
||||
#include "game/gameplay/enemy_manager.hpp" // Para EnemyManager
|
||||
#include "game/gameplay/item_manager.hpp" // Para ItemManager
|
||||
#include "game/gameplay/room.hpp" // Para Room
|
||||
#include "game/options.hpp" // Para Options
|
||||
#include "game/ui/console.hpp" // Para Console
|
||||
#include "utils/defines.hpp" // Para Tile::SIZE, PlayArea
|
||||
#include "utils/utils.hpp" // Para stringToColor
|
||||
|
||||
@@ -193,6 +193,11 @@ void MapEditor::render() {
|
||||
// Renderizar highlight de selección (encima de los sprites)
|
||||
renderSelectionHighlight();
|
||||
|
||||
// Tile picker (encima de todo en el play area)
|
||||
if (tile_picker_.isOpen()) {
|
||||
tile_picker_.render();
|
||||
}
|
||||
|
||||
// Renderizar barra de estado del editor (reemplaza al scoreboard)
|
||||
if (statusbar_) {
|
||||
statusbar_->render();
|
||||
@@ -201,6 +206,12 @@ void MapEditor::render() {
|
||||
|
||||
// Maneja eventos del editor
|
||||
void MapEditor::handleEvent(const SDL_Event& event) {
|
||||
// Si el tile picker está abierto, los eventos van a él
|
||||
if (tile_picker_.isOpen()) {
|
||||
tile_picker_.handleEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -268,8 +279,9 @@ void MapEditor::handleMouseDown(float game_x, float game_y) {
|
||||
}
|
||||
}
|
||||
|
||||
// Click en el fondo: deseleccionar
|
||||
// Click en el fondo: deseleccionar todo
|
||||
selected_enemy_ = -1;
|
||||
selected_item_ = -1;
|
||||
}
|
||||
|
||||
// Procesa soltar el ratón: commit del drag
|
||||
@@ -281,11 +293,14 @@ void MapEditor::handleMouseUp() {
|
||||
// Si no se movió: fue un click → seleccionar/deseleccionar
|
||||
if (!drag_.moved) {
|
||||
if (drag_.target == DragTarget::ENEMY_INITIAL) {
|
||||
// Toggle selección: si ya estaba seleccionado, deseleccionar
|
||||
selected_enemy_ = (selected_enemy_ == IDX) ? -1 : IDX;
|
||||
} else {
|
||||
// Click en otro tipo de entidad: deseleccionar enemigo
|
||||
selected_item_ = -1;
|
||||
} else if (drag_.target == DragTarget::ITEM) {
|
||||
selected_item_ = (selected_item_ == IDX) ? -1 : IDX;
|
||||
selected_enemy_ = -1;
|
||||
} else {
|
||||
selected_enemy_ = -1;
|
||||
selected_item_ = -1;
|
||||
}
|
||||
drag_ = {};
|
||||
return;
|
||||
@@ -333,6 +348,7 @@ void MapEditor::handleMouseUp() {
|
||||
case DragTarget::ITEM:
|
||||
if (IDX >= 0 && IDX < room_->getItemManager()->getCount()) {
|
||||
room_->getItemManager()->getItem(IDX)->setPosition(drag_.snap_x, drag_.snap_y);
|
||||
selected_item_ = IDX;
|
||||
selected_enemy_ = -1;
|
||||
changed = true;
|
||||
}
|
||||
@@ -415,6 +431,17 @@ void MapEditor::renderSelectionHighlight() {
|
||||
game_surface->drawRectBorder(&border, stringToColor("bright_green"));
|
||||
}
|
||||
|
||||
// Highlight del item seleccionado (persistente, color bright_green)
|
||||
if (selected_item_ >= 0 && selected_item_ < room_->getItemManager()->getCount()) {
|
||||
SDL_FRect item_rect = room_->getItemManager()->getItem(selected_item_)->getCollider();
|
||||
SDL_FRect border = {
|
||||
.x = item_rect.x - 1,
|
||||
.y = item_rect.y - 1,
|
||||
.w = item_rect.w + 2,
|
||||
.h = item_rect.h + 2};
|
||||
game_surface->drawRectBorder(&border, stringToColor("bright_green"));
|
||||
}
|
||||
|
||||
// Highlight del drag activo (temporal, color bright_white)
|
||||
if (drag_.target == DragTarget::NONE || !drag_.moved) { return; }
|
||||
|
||||
@@ -559,12 +586,23 @@ void MapEditor::updateStatusBarInfo() {
|
||||
// Info de drag activo (línea 5, junto a tile coords)
|
||||
if (drag_.target != DragTarget::NONE && drag_.moved) {
|
||||
switch (drag_.target) {
|
||||
case DragTarget::PLAYER: line5 = "dragging: player"; break;
|
||||
case DragTarget::ENEMY_INITIAL: line5 = "dragging: enemy " + std::to_string(drag_.index); break;
|
||||
case DragTarget::ENEMY_BOUND1: line5 = "dragging: e" + std::to_string(drag_.index) + " bound1"; break;
|
||||
case DragTarget::ENEMY_BOUND2: line5 = "dragging: e" + std::to_string(drag_.index) + " bound2"; break;
|
||||
case DragTarget::ITEM: line5 = "dragging: item " + std::to_string(drag_.index); break;
|
||||
case DragTarget::NONE: break;
|
||||
case DragTarget::PLAYER:
|
||||
line5 = "dragging: player";
|
||||
break;
|
||||
case DragTarget::ENEMY_INITIAL:
|
||||
line5 = "dragging: enemy " + std::to_string(drag_.index);
|
||||
break;
|
||||
case DragTarget::ENEMY_BOUND1:
|
||||
line5 = "dragging: e" + std::to_string(drag_.index) + " bound1";
|
||||
break;
|
||||
case DragTarget::ENEMY_BOUND2:
|
||||
line5 = "dragging: e" + std::to_string(drag_.index) + " bound2";
|
||||
break;
|
||||
case DragTarget::ITEM:
|
||||
line5 = "dragging: item " + std::to_string(drag_.index);
|
||||
break;
|
||||
case DragTarget::NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,29 +616,40 @@ void MapEditor::updateStatusBarInfo() {
|
||||
|
||||
line2 = "enemy " + std::to_string(selected_enemy_) + ": " + anim + " " + e.color;
|
||||
line3 = "vx:" + std::to_string(static_cast<int>(e.vx)) +
|
||||
" vy:" + std::to_string(static_cast<int>(e.vy));
|
||||
" vy:" + std::to_string(static_cast<int>(e.vy));
|
||||
if (e.flip) { line3 += " flip"; }
|
||||
if (e.mirror) { line3 += " mirror"; }
|
||||
} else if (selected_item_ >= 0 && selected_item_ < static_cast<int>(room_data_.items.size())) {
|
||||
// Item seleccionado
|
||||
const auto& it = room_data_.items[selected_item_];
|
||||
line2 = "item " + std::to_string(selected_item_) + ": tile=" + std::to_string(it.tile) +
|
||||
" counter=" + std::to_string(it.counter);
|
||||
line3 = "tileset: " + it.tile_set_file;
|
||||
} else {
|
||||
// Propiedades de la habitación
|
||||
std::string conv = "none";
|
||||
if (room_data_.conveyor_belt_direction < 0) { conv = "left"; }
|
||||
else if (room_data_.conveyor_belt_direction > 0) { conv = "right"; }
|
||||
if (room_data_.conveyor_belt_direction < 0) {
|
||||
conv = "left";
|
||||
} else if (room_data_.conveyor_belt_direction > 0) {
|
||||
conv = "right";
|
||||
}
|
||||
|
||||
line2 = "bg:" + room_data_.bg_color + " brd:" + room_data_.border_color + " conv:" + conv;
|
||||
line3 = "u:" + conn(room_data_.upper_room) + " d:" + conn(room_data_.lower_room) +
|
||||
" l:" + conn(room_data_.left_room) + " r:" + conn(room_data_.right_room) +
|
||||
" itm:" + room_data_.item_color1 + "/" + room_data_.item_color2;
|
||||
" l:" + conn(room_data_.left_room) + " r:" + conn(room_data_.right_room) +
|
||||
" itm:" + room_data_.item_color1 + "/" + room_data_.item_color2;
|
||||
}
|
||||
|
||||
statusbar_->setLine2(line2);
|
||||
statusbar_->setLine3(line3);
|
||||
statusbar_->setLine4(""); // Disponible para uso futuro
|
||||
statusbar_->setLine4("");
|
||||
statusbar_->setLine5(line5);
|
||||
|
||||
// Actualizar el prompt de la consola según la selección
|
||||
if (selected_enemy_ >= 0) {
|
||||
Console::get()->setPrompt("enemy " + std::to_string(selected_enemy_) + "> ");
|
||||
} else if (selected_item_ >= 0) {
|
||||
Console::get()->setPrompt("item " + std::to_string(selected_item_) + "> ");
|
||||
} else {
|
||||
Console::get()->setPrompt("room> ");
|
||||
}
|
||||
@@ -826,9 +875,14 @@ auto MapEditor::setRoomProperty(const std::string& property, const std::string&
|
||||
}
|
||||
|
||||
if (property == "CONVEYOR") {
|
||||
if (val == "left") { room_data_.conveyor_belt_direction = -1; }
|
||||
else if (val == "right") { room_data_.conveyor_belt_direction = 1; }
|
||||
else { room_data_.conveyor_belt_direction = 0; val = "none"; }
|
||||
if (val == "left") {
|
||||
room_data_.conveyor_belt_direction = -1;
|
||||
} else if (val == "right") {
|
||||
room_data_.conveyor_belt_direction = 1;
|
||||
} else {
|
||||
room_data_.conveyor_belt_direction = 0;
|
||||
val = "none";
|
||||
}
|
||||
autosave();
|
||||
return "conveyor: " + val;
|
||||
}
|
||||
@@ -858,10 +912,15 @@ auto MapEditor::setRoomProperty(const std::string& property, const std::string&
|
||||
}
|
||||
}
|
||||
|
||||
if (property == "UP") { room_data_.upper_room = connection; }
|
||||
else if (property == "DOWN") { room_data_.lower_room = connection; }
|
||||
else if (property == "LEFT") { room_data_.left_room = connection; }
|
||||
else { room_data_.right_room = connection; }
|
||||
if (property == "UP") {
|
||||
room_data_.upper_room = connection;
|
||||
} else if (property == "DOWN") {
|
||||
room_data_.lower_room = connection;
|
||||
} else if (property == "LEFT") {
|
||||
room_data_.left_room = connection;
|
||||
} else {
|
||||
room_data_.right_room = connection;
|
||||
}
|
||||
|
||||
autosave();
|
||||
return toLower(property) + ": " + connection;
|
||||
@@ -870,4 +929,113 @@ auto MapEditor::setRoomProperty(const std::string& property, const std::string&
|
||||
return "Unknown property: " + property + " (use: bgcolor, border, itemcolor1, itemcolor2, conveyor, tileset, up, down, left, right)";
|
||||
}
|
||||
|
||||
// ¿Hay un item seleccionado?
|
||||
auto MapEditor::hasSelectedItem() const -> bool {
|
||||
return selected_item_ >= 0 && selected_item_ < static_cast<int>(room_data_.items.size());
|
||||
}
|
||||
|
||||
// Modifica una propiedad del item seleccionado
|
||||
auto MapEditor::setItemProperty(const std::string& property, const std::string& value) -> std::string {
|
||||
if (!active_) { return "Editor not active"; }
|
||||
if (!hasSelectedItem()) { return "No item selected"; }
|
||||
|
||||
auto& item = room_data_.items[selected_item_];
|
||||
|
||||
if (property == "TILE") {
|
||||
// Abrir el tile picker visual
|
||||
openTilePicker(item.tile_set_file, item.tile);
|
||||
return "Select tile...";
|
||||
}
|
||||
|
||||
if (property == "COUNTER") {
|
||||
try {
|
||||
item.counter = std::stoi(value);
|
||||
} catch (...) { return "Invalid value: " + value; }
|
||||
autosave();
|
||||
return "counter: " + std::to_string(item.counter);
|
||||
}
|
||||
|
||||
return "Unknown property: " + property + " (use: tile, counter)";
|
||||
}
|
||||
|
||||
// Abre el tile picker para seleccionar un tile
|
||||
void MapEditor::openTilePicker(const std::string& tileset_name, int current_tile) {
|
||||
// Cerrar la consola si está abierta (para que el primer click vaya al picker)
|
||||
if (Console::get()->isActive()) {
|
||||
Console::get()->toggle();
|
||||
}
|
||||
|
||||
tile_picker_.on_select = [this](int tile) {
|
||||
if (!hasSelectedItem()) { return; }
|
||||
room_data_.items[selected_item_].tile = tile;
|
||||
room_->getItemManager()->getItem(selected_item_)->setTile(tile);
|
||||
autosave();
|
||||
};
|
||||
// Pasar color de fondo de la habitación + color de sustitución del item
|
||||
int bg = stringToColor(room_data_.bg_color);
|
||||
int item_color = stringToColor(room_data_.item_color1);
|
||||
tile_picker_.open(tileset_name, current_tile, bg, 1, item_color);
|
||||
}
|
||||
|
||||
// Crea un nuevo item con valores por defecto, centrado en la habitación
|
||||
auto MapEditor::addItem() -> std::string {
|
||||
if (!active_) { return "Editor not active"; }
|
||||
|
||||
Item::Data new_item;
|
||||
new_item.tile_set_file = "items.gif";
|
||||
new_item.tile = 42; // Tile por defecto
|
||||
new_item.x = PlayArea::CENTER_X;
|
||||
new_item.y = PlayArea::CENTER_Y;
|
||||
new_item.counter = 0;
|
||||
new_item.color1 = stringToColor(room_data_.item_color1);
|
||||
new_item.color2 = stringToColor(room_data_.item_color2);
|
||||
|
||||
room_data_.items.push_back(new_item);
|
||||
room_->getItemManager()->addItem(std::make_shared<Item>(new_item));
|
||||
|
||||
selected_item_ = static_cast<int>(room_data_.items.size()) - 1;
|
||||
selected_enemy_ = -1;
|
||||
|
||||
autosave();
|
||||
return "Added item " + std::to_string(selected_item_);
|
||||
}
|
||||
|
||||
// Elimina el item seleccionado
|
||||
auto MapEditor::deleteItem() -> std::string {
|
||||
if (!active_) { return "Editor not active"; }
|
||||
if (!hasSelectedItem()) { return "No item selected"; }
|
||||
|
||||
const int IDX = selected_item_;
|
||||
room_data_.items.erase(room_data_.items.begin() + IDX);
|
||||
|
||||
// Recrear todos los items (los índices cambian al borrar)
|
||||
auto* item_mgr = room_->getItemManager();
|
||||
item_mgr->clear();
|
||||
for (const auto& item_data : room_data_.items) {
|
||||
item_mgr->addItem(std::make_shared<Item>(item_data));
|
||||
}
|
||||
|
||||
selected_item_ = -1;
|
||||
autosave();
|
||||
return "Deleted item " + std::to_string(IDX);
|
||||
}
|
||||
|
||||
// Duplica el item seleccionado (lo pone un tile a la derecha)
|
||||
auto MapEditor::duplicateItem() -> std::string {
|
||||
if (!active_) { return "Editor not active"; }
|
||||
if (!hasSelectedItem()) { return "No item selected"; }
|
||||
|
||||
Item::Data copy = room_data_.items[selected_item_];
|
||||
copy.x += Tile::SIZE;
|
||||
|
||||
room_data_.items.push_back(copy);
|
||||
room_->getItemManager()->addItem(std::make_shared<Item>(copy));
|
||||
|
||||
selected_item_ = static_cast<int>(room_data_.items.size()) - 1;
|
||||
selected_enemy_ = -1;
|
||||
|
||||
autosave();
|
||||
return "Duplicated as item " + std::to_string(selected_item_);
|
||||
}
|
||||
|
||||
#endif // _DEBUG
|
||||
|
||||
Reference in New Issue
Block a user