refactor de l'editor
This commit is contained in:
@@ -72,7 +72,6 @@ enemies:
|
|||||||
boundaries:
|
boundaries:
|
||||||
position1: {x: 3, y: 2}
|
position1: {x: 3, y: 2}
|
||||||
position2: {x: 19, y: 2}
|
position2: {x: 19, y: 2}
|
||||||
color: 12
|
|
||||||
|
|
||||||
# Objetos en esta habitación
|
# Objetos en esta habitación
|
||||||
items:
|
items:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -10,15 +10,28 @@
|
|||||||
#include "external/fkyaml_node.hpp" // Para fkyaml::node
|
#include "external/fkyaml_node.hpp" // Para fkyaml::node
|
||||||
#include "game/editor/mini_map.hpp" // Para MiniMap
|
#include "game/editor/mini_map.hpp" // Para MiniMap
|
||||||
#include "game/editor/tile_picker.hpp" // Para TilePicker
|
#include "game/editor/tile_picker.hpp" // Para TilePicker
|
||||||
#include "game/entities/enemy.hpp" // Para Enemy::Data
|
#include "game/entities/enemy.hpp" // Para Enemy::Data
|
||||||
#include "game/entities/item.hpp" // Para Item::Data
|
#include "game/entities/item.hpp" // Para Item::Data
|
||||||
#include "game/entities/player.hpp" // Para Player::SpawnData
|
#include "game/entities/moving_platform.hpp" // Para MovingPlatform::Data
|
||||||
#include "game/gameplay/room.hpp" // Para Room::Data
|
#include "game/entities/player.hpp" // Para Player::SpawnData
|
||||||
#include "game/gameplay/scoreboard.hpp" // Para Scoreboard::Data
|
#include "game/gameplay/room.hpp" // Para Room::Data
|
||||||
#include "game/options.hpp" // Para Options::Cheat
|
#include "game/gameplay/scoreboard.hpp" // Para Scoreboard::Data
|
||||||
|
#include "game/options.hpp" // Para Options::Cheat
|
||||||
|
|
||||||
class EditorStatusBar;
|
class EditorStatusBar;
|
||||||
|
|
||||||
|
// Tipo de entidad editable en el editor
|
||||||
|
enum class EntityType { NONE, ENEMY, ITEM, PLATFORM };
|
||||||
|
|
||||||
|
// Seleccion unificada: una sola entidad seleccionada a la vez
|
||||||
|
struct Selection {
|
||||||
|
EntityType type{EntityType::NONE};
|
||||||
|
int index{-1};
|
||||||
|
void clear() { type = EntityType::NONE; index = -1; }
|
||||||
|
[[nodiscard]] auto isNone() const -> bool { return type == EntityType::NONE; }
|
||||||
|
[[nodiscard]] auto is(EntityType t) const -> bool { return type == t && index >= 0; }
|
||||||
|
};
|
||||||
|
|
||||||
class MapEditor {
|
class MapEditor {
|
||||||
public:
|
public:
|
||||||
static void init(); // [SINGLETON] Crea el objeto
|
static void init(); // [SINGLETON] Crea el objeto
|
||||||
@@ -39,7 +52,7 @@ class MapEditor {
|
|||||||
auto addEnemy() -> std::string;
|
auto addEnemy() -> std::string;
|
||||||
auto deleteEnemy() -> std::string;
|
auto deleteEnemy() -> std::string;
|
||||||
auto duplicateEnemy() -> std::string;
|
auto duplicateEnemy() -> std::string;
|
||||||
[[nodiscard]] auto hasSelectedEnemy() const -> bool;
|
[[nodiscard]] auto hasSelectedEnemy() const -> bool { return selection_.is(EntityType::ENEMY); }
|
||||||
[[nodiscard]] auto getSetCompletions() const -> std::vector<std::string>;
|
[[nodiscard]] auto getSetCompletions() const -> std::vector<std::string>;
|
||||||
|
|
||||||
// Comandos para propiedades de la habitación
|
// Comandos para propiedades de la habitación
|
||||||
@@ -62,9 +75,19 @@ class MapEditor {
|
|||||||
auto addItem() -> std::string;
|
auto addItem() -> std::string;
|
||||||
auto deleteItem() -> std::string;
|
auto deleteItem() -> std::string;
|
||||||
auto duplicateItem() -> std::string;
|
auto duplicateItem() -> std::string;
|
||||||
[[nodiscard]] auto hasSelectedItem() const -> bool;
|
[[nodiscard]] auto hasSelectedItem() const -> bool { return selection_.is(EntityType::ITEM); }
|
||||||
void openTilePicker(const std::string& tileset_name, int current_tile);
|
void openTilePicker(const std::string& tileset_name, int current_tile);
|
||||||
|
|
||||||
|
// Comandos para plataformas
|
||||||
|
auto setPlatformProperty(const std::string& property, const std::string& value) -> std::string;
|
||||||
|
auto addPlatform() -> std::string;
|
||||||
|
auto deletePlatform() -> std::string;
|
||||||
|
auto duplicatePlatform() -> std::string;
|
||||||
|
[[nodiscard]] auto hasSelectedPlatform() const -> bool { return selection_.is(EntityType::PLATFORM); }
|
||||||
|
|
||||||
|
// Seleccion unificada
|
||||||
|
[[nodiscard]] auto getSelectionType() const -> EntityType { return selection_.type; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static MapEditor* instance_; // NOLINT(readability-identifier-naming) [SINGLETON] Objeto privado
|
static MapEditor* instance_; // NOLINT(readability-identifier-naming) [SINGLETON] Objeto privado
|
||||||
|
|
||||||
@@ -82,16 +105,16 @@ class MapEditor {
|
|||||||
void loadSettings();
|
void loadSettings();
|
||||||
void saveSettings() const;
|
void saveSettings() const;
|
||||||
|
|
||||||
// Tipos para drag & drop y selección
|
// Tipos para drag & drop
|
||||||
enum class DragTarget { NONE,
|
enum class DragTarget { NONE,
|
||||||
PLAYER,
|
PLAYER,
|
||||||
ENEMY_INITIAL,
|
ENTITY_INITIAL,
|
||||||
ENEMY_BOUND1,
|
ENTITY_BOUND1,
|
||||||
ENEMY_BOUND2,
|
ENTITY_BOUND2 };
|
||||||
ITEM };
|
|
||||||
|
|
||||||
struct DragState {
|
struct DragState {
|
||||||
DragTarget target{DragTarget::NONE};
|
DragTarget target{DragTarget::NONE};
|
||||||
|
EntityType entity_type{EntityType::NONE};
|
||||||
int index{-1};
|
int index{-1};
|
||||||
float offset_x{0.0F};
|
float offset_x{0.0F};
|
||||||
float offset_y{0.0F};
|
float offset_y{0.0F};
|
||||||
@@ -102,23 +125,34 @@ class MapEditor {
|
|||||||
|
|
||||||
// Métodos internos
|
// Métodos internos
|
||||||
void updateMousePosition();
|
void updateMousePosition();
|
||||||
void renderEnemyBoundaries();
|
void renderEntityBoundaries();
|
||||||
static void renderBoundaryMarker(float x, float y, Uint8 color);
|
static void renderBoundaryMarker(float x, float y, Uint8 color);
|
||||||
void renderSelectionHighlight();
|
void renderSelectionHighlight();
|
||||||
void renderGrid() const;
|
void renderGrid() const;
|
||||||
void handleMouseDown(float game_x, float game_y);
|
void handleMouseDown(float game_x, float game_y);
|
||||||
void handleMouseUp();
|
void handleMouseUp();
|
||||||
void updateDrag();
|
void updateDrag();
|
||||||
|
auto commitEntityDrag() -> bool;
|
||||||
|
void moveEntityVisual();
|
||||||
void autosave();
|
void autosave();
|
||||||
void updateStatusBarInfo();
|
void updateStatusBarInfo();
|
||||||
static auto snapToGrid(float value) -> float;
|
static auto snapToGrid(float value) -> float;
|
||||||
static auto pointInRect(float px, float py, const SDL_FRect& rect) -> bool;
|
static auto pointInRect(float px, float py, const SDL_FRect& rect) -> bool;
|
||||||
|
|
||||||
|
// Entity helpers: acceso abstracto a datos de entidad por tipo
|
||||||
|
struct BoundaryData { int x1, y1, x2, y2; };
|
||||||
|
auto entityCount(EntityType type) const -> int;
|
||||||
|
auto entityRect(EntityType type, int index) -> SDL_FRect;
|
||||||
|
static auto entityHasBoundaries(EntityType type) -> bool;
|
||||||
|
auto entityBoundaries(EntityType type, int index) const -> BoundaryData;
|
||||||
|
auto entityPosition(EntityType type, int index) const -> std::pair<float, float>;
|
||||||
|
auto entityDataCount(EntityType type) const -> int;
|
||||||
|
static auto entityLabel(EntityType type) -> const char*;
|
||||||
|
|
||||||
// Estado del editor
|
// Estado del editor
|
||||||
bool active_{false};
|
bool active_{false};
|
||||||
DragState drag_;
|
DragState drag_;
|
||||||
int selected_enemy_{-1}; // Índice del enemigo seleccionado (-1 = ninguno)
|
Selection selection_; // Entidad seleccionada (unificada: enemy, item o platform)
|
||||||
int selected_item_{-1}; // Índice del item seleccionado (-1 = ninguno)
|
|
||||||
static constexpr int NO_BRUSH = -2; // Sin brush activo
|
static constexpr int NO_BRUSH = -2; // Sin brush activo
|
||||||
static constexpr int ERASER_BRUSH = -1; // Brush borrador (pinta tile vacío = -1)
|
static constexpr int ERASER_BRUSH = -1; // Brush borrador (pinta tile vacío = -1)
|
||||||
int brush_tile_{NO_BRUSH}; // Tile activo para pintar
|
int brush_tile_{NO_BRUSH}; // Tile activo para pintar
|
||||||
|
|||||||
@@ -728,7 +728,7 @@ static auto cmdEdit(const std::vector<std::string>& args) -> std::string { // N
|
|||||||
return "usage: edit [on|off|revert|show|hide|mapbg|mapconn] [...]";
|
return "usage: edit [on|off|revert|show|hide|mapbg|mapconn] [...]";
|
||||||
}
|
}
|
||||||
|
|
||||||
// SET <property> <value> — modifica propiedad del enemigo seleccionado o de la habitación
|
// SET <property> <value> — modifica propiedad de la entidad seleccionada o de la habitación
|
||||||
static auto cmdSet(const std::vector<std::string>& args) -> std::string {
|
static auto cmdSet(const std::vector<std::string>& args) -> std::string {
|
||||||
if ((MapEditor::get() == nullptr) || !MapEditor::get()->isActive()) { return "Editor not active"; }
|
if ((MapEditor::get() == nullptr) || !MapEditor::get()->isActive()) { return "Editor not active"; }
|
||||||
if (args.empty()) { return "usage: set <property> <value>"; }
|
if (args.empty()) { return "usage: set <property> <value>"; }
|
||||||
@@ -740,18 +740,12 @@ static auto cmdSet(const std::vector<std::string>& args) -> std::string {
|
|||||||
|
|
||||||
if (args.size() < 2) { return "usage: set <property> <value>"; }
|
if (args.size() < 2) { return "usage: set <property> <value>"; }
|
||||||
|
|
||||||
// Si hay enemigo seleccionado, aplicar a enemigo
|
switch (MapEditor::get()->getSelectionType()) {
|
||||||
if (MapEditor::get()->hasSelectedEnemy()) {
|
case EntityType::ENEMY: return MapEditor::get()->setEnemyProperty(args[0], args[1]);
|
||||||
return MapEditor::get()->setEnemyProperty(args[0], args[1]);
|
case EntityType::ITEM: return MapEditor::get()->setItemProperty(args[0], args[1]);
|
||||||
|
case EntityType::PLATFORM: return MapEditor::get()->setPlatformProperty(args[0], args[1]);
|
||||||
|
default: return MapEditor::get()->setRoomProperty(args[0], args[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si hay item seleccionado, aplicar a item
|
|
||||||
if (MapEditor::get()->hasSelectedItem()) {
|
|
||||||
return MapEditor::get()->setItemProperty(args[0], args[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Si no, aplicar a la habitación
|
|
||||||
return MapEditor::get()->setRoomProperty(args[0], args[1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ENEMY [ADD|DELETE|DUPLICATE]
|
// ENEMY [ADD|DELETE|DUPLICATE]
|
||||||
@@ -785,6 +779,22 @@ static auto cmdItem(const std::vector<std::string>& args) -> std::string {
|
|||||||
}
|
}
|
||||||
return "usage: item <add|delete|duplicate>";
|
return "usage: item <add|delete|duplicate>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PLATFORM [ADD|DELETE|DUPLICATE]
|
||||||
|
static auto cmdPlatform(const std::vector<std::string>& args) -> std::string {
|
||||||
|
if ((MapEditor::get() == nullptr) || !MapEditor::get()->isActive()) { return "Editor not active"; }
|
||||||
|
if (args.empty()) { return "usage: platform <add|delete|duplicate>"; }
|
||||||
|
if (args[0] == "ADD") { return MapEditor::get()->addPlatform(); }
|
||||||
|
if (args[0] == "DELETE") {
|
||||||
|
if (!MapEditor::get()->hasSelectedPlatform()) { return "No platform selected"; }
|
||||||
|
return MapEditor::get()->deletePlatform();
|
||||||
|
}
|
||||||
|
if (args[0] == "DUPLICATE") {
|
||||||
|
if (!MapEditor::get()->hasSelectedPlatform()) { return "No platform selected"; }
|
||||||
|
return MapEditor::get()->duplicatePlatform();
|
||||||
|
}
|
||||||
|
return "usage: platform <add|delete|duplicate>";
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// SHOW [INFO|NOTIFICATION|CHEEVO]
|
// SHOW [INFO|NOTIFICATION|CHEEVO]
|
||||||
@@ -933,6 +943,7 @@ void CommandRegistry::registerHandlers() { // NOLINT(readability-function-cogni
|
|||||||
handlers_["cmd_set"] = cmdSet;
|
handlers_["cmd_set"] = cmdSet;
|
||||||
handlers_["cmd_enemy"] = cmdEnemy;
|
handlers_["cmd_enemy"] = cmdEnemy;
|
||||||
handlers_["cmd_item"] = cmdItem;
|
handlers_["cmd_item"] = cmdItem;
|
||||||
|
handlers_["cmd_platform"] = cmdPlatform;
|
||||||
#endif
|
#endif
|
||||||
// HELP se registra en load() como lambda que captura this
|
// HELP se registra en load() como lambda que captura this
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user