editar propietats del enemic
This commit is contained in:
@@ -13,6 +13,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/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
|
||||
@@ -77,8 +78,9 @@ void MapEditor::enter(std::shared_ptr<Room> room, std::shared_ptr<Player> player
|
||||
// Crear la barra de estado
|
||||
statusbar_ = std::make_unique<EditorStatusBar>(room_->getNumber(), room_->getName());
|
||||
|
||||
// Resetear estado de drag
|
||||
// Resetear estado
|
||||
drag_ = {};
|
||||
selected_enemy_ = -1;
|
||||
|
||||
active_ = true;
|
||||
std::cout << "MapEditor: ON (room " << room_path_ << ")\n";
|
||||
@@ -94,7 +96,9 @@ void MapEditor::exit() {
|
||||
Options::cheats.invincible = invincible_before_editor_;
|
||||
player_->setColor();
|
||||
|
||||
// Liberar recursos
|
||||
// Restaurar prompt de la consola y limpiar estado
|
||||
selected_enemy_ = -1;
|
||||
Console::get()->setPrompt("> ");
|
||||
drag_ = {};
|
||||
statusbar_.reset();
|
||||
room_.reset();
|
||||
@@ -161,34 +165,9 @@ void MapEditor::update(float delta_time) {
|
||||
updateDrag();
|
||||
}
|
||||
|
||||
// Actualizar la barra de estado con las coordenadas del ratón y la selección
|
||||
// Actualizar la barra de estado
|
||||
updateStatusBarInfo();
|
||||
if (statusbar_) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -235,6 +214,7 @@ void MapEditor::handleMouseDown(float game_x, float game_y) {
|
||||
drag_.offset_y = game_y - entity_y;
|
||||
drag_.snap_x = entity_x;
|
||||
drag_.snap_y = entity_y;
|
||||
drag_.moved = false;
|
||||
};
|
||||
|
||||
// 1. Hit test sobre el jugador (8x16)
|
||||
@@ -281,6 +261,9 @@ void MapEditor::handleMouseDown(float game_x, float game_y) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Click en el fondo: deseleccionar
|
||||
selected_enemy_ = -1;
|
||||
}
|
||||
|
||||
// Procesa soltar el ratón: commit del drag
|
||||
@@ -288,16 +271,29 @@ void MapEditor::handleMouseUp() {
|
||||
if (drag_.target == DragTarget::NONE) { return; }
|
||||
|
||||
const int IDX = drag_.index;
|
||||
|
||||
// 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_enemy_ = -1;
|
||||
}
|
||||
drag_ = {};
|
||||
return;
|
||||
}
|
||||
|
||||
// Hubo movimiento: commit del drag
|
||||
const int SNAP_X = static_cast<int>(drag_.snap_x);
|
||||
const int SNAP_Y = static_cast<int>(drag_.snap_y);
|
||||
|
||||
bool changed = false;
|
||||
|
||||
switch (drag_.target) {
|
||||
case DragTarget::PLAYER:
|
||||
player_->setDebugPosition(drag_.snap_x, drag_.snap_y);
|
||||
player_->finalizeDebugTeleport();
|
||||
// El jugador no se guarda en el YAML de la habitación (es dato de spawn global)
|
||||
break;
|
||||
|
||||
case DragTarget::ENEMY_INITIAL:
|
||||
@@ -305,6 +301,7 @@ void MapEditor::handleMouseUp() {
|
||||
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]);
|
||||
selected_enemy_ = IDX; // Seleccionar el enemigo arrastrado
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
@@ -313,6 +310,7 @@ void MapEditor::handleMouseUp() {
|
||||
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;
|
||||
selected_enemy_ = IDX;
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
@@ -321,6 +319,7 @@ void MapEditor::handleMouseUp() {
|
||||
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;
|
||||
selected_enemy_ = IDX;
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
@@ -328,6 +327,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_enemy_ = -1;
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
@@ -336,12 +336,7 @@ void MapEditor::handleMouseUp() {
|
||||
break;
|
||||
}
|
||||
|
||||
// Auto-guardar si hubo cambio
|
||||
if (changed) {
|
||||
autosave();
|
||||
}
|
||||
|
||||
// Resetear estado de drag
|
||||
if (changed) { autosave(); }
|
||||
drag_ = {};
|
||||
}
|
||||
|
||||
@@ -350,8 +345,16 @@ void MapEditor::updateDrag() {
|
||||
float raw_x = mouse_game_x_ - drag_.offset_x;
|
||||
float raw_y = mouse_game_y_ - drag_.offset_y;
|
||||
|
||||
drag_.snap_x = snapToGrid(raw_x);
|
||||
drag_.snap_y = snapToGrid(raw_y);
|
||||
float new_snap_x = snapToGrid(raw_x);
|
||||
float new_snap_y = snapToGrid(raw_y);
|
||||
|
||||
// Detectar si hubo movimiento real (el snap cambió respecto al inicio)
|
||||
if (new_snap_x != drag_.snap_x || new_snap_y != drag_.snap_y) {
|
||||
drag_.moved = true;
|
||||
}
|
||||
|
||||
drag_.snap_x = new_snap_x;
|
||||
drag_.snap_y = new_snap_y;
|
||||
|
||||
// Mientras arrastramos, mover la entidad visualmente a la posición snapped
|
||||
switch (drag_.target) {
|
||||
@@ -390,48 +393,56 @@ void MapEditor::updateDrag() {
|
||||
|
||||
// Dibuja highlight del elemento seleccionado/arrastrado
|
||||
void MapEditor::renderSelectionHighlight() {
|
||||
if (drag_.target == DragTarget::NONE) { return; }
|
||||
|
||||
auto game_surface = Screen::get()->getRendererSurface();
|
||||
if (!game_surface) { return; }
|
||||
|
||||
const Uint8 HIGHLIGHT_COLOR = stringToColor("bright_white");
|
||||
constexpr float SZ = static_cast<float>(Tile::SIZE);
|
||||
|
||||
// Highlight del enemigo seleccionado (persistente, color bright_green)
|
||||
if (selected_enemy_ >= 0 && selected_enemy_ < room_->getEnemyManager()->getCount()) {
|
||||
SDL_FRect enemy_rect = room_->getEnemyManager()->getEnemy(selected_enemy_)->getRect();
|
||||
SDL_FRect border = {
|
||||
.x = enemy_rect.x - 1,
|
||||
.y = enemy_rect.y - 1,
|
||||
.w = enemy_rect.w + 2,
|
||||
.h = enemy_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; }
|
||||
|
||||
const Uint8 DRAG_COLOR = stringToColor("bright_white");
|
||||
SDL_FRect highlight_rect{};
|
||||
|
||||
switch (drag_.target) {
|
||||
case DragTarget::PLAYER:
|
||||
highlight_rect = player_->getRect();
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Dibujar rectángulo de highlight alrededor de la entidad
|
||||
SDL_FRect border = {
|
||||
.x = highlight_rect.x - 1,
|
||||
.y = highlight_rect.y - 1,
|
||||
.w = highlight_rect.w + 2,
|
||||
.h = highlight_rect.h + 2};
|
||||
game_surface->drawRectBorder(&border, HIGHLIGHT_COLOR);
|
||||
game_surface->drawRectBorder(&border, DRAG_COLOR);
|
||||
}
|
||||
|
||||
// Alinea un valor a la cuadrícula de 8x8
|
||||
@@ -523,4 +534,131 @@ void MapEditor::updateMousePosition() {
|
||||
if (mouse_tile_y_ >= PlayArea::HEIGHT / Tile::SIZE) { mouse_tile_y_ = PlayArea::HEIGHT / Tile::SIZE - 1; }
|
||||
}
|
||||
|
||||
// Actualiza la información de la barra de estado
|
||||
void MapEditor::updateStatusBarInfo() {
|
||||
if (!statusbar_) { return; }
|
||||
|
||||
statusbar_->setMouseTile(mouse_tile_x_, mouse_tile_y_);
|
||||
|
||||
std::string sel_info;
|
||||
std::string sel_detail;
|
||||
|
||||
// Info de drag activo (prioridad)
|
||||
if (drag_.target != DragTarget::NONE && drag_.moved) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
// Info de enemigo seleccionado (persistente)
|
||||
else if (selected_enemy_ >= 0 && selected_enemy_ < static_cast<int>(room_data_.enemies.size())) {
|
||||
const auto& e = room_data_.enemies[selected_enemy_];
|
||||
// Extraer nombre corto de la animación (sin .yaml)
|
||||
std::string anim = e.animation_path;
|
||||
auto dot = anim.rfind('.');
|
||||
if (dot != std::string::npos) { anim = anim.substr(0, dot); }
|
||||
|
||||
sel_info = "enemy " + std::to_string(selected_enemy_) + ": " + anim;
|
||||
sel_detail = e.color + " vx:" + std::to_string(static_cast<int>(e.vx)) +
|
||||
" vy:" + std::to_string(static_cast<int>(e.vy));
|
||||
if (e.flip) { sel_detail += " flip"; }
|
||||
}
|
||||
|
||||
statusbar_->setSelectionInfo(sel_info);
|
||||
statusbar_->setSelectionDetail(sel_detail);
|
||||
|
||||
// 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 {
|
||||
Console::get()->setPrompt("> ");
|
||||
}
|
||||
}
|
||||
|
||||
// ¿Hay un enemigo seleccionado?
|
||||
auto MapEditor::hasSelectedEnemy() const -> bool {
|
||||
return selected_enemy_ >= 0 && selected_enemy_ < static_cast<int>(room_data_.enemies.size());
|
||||
}
|
||||
|
||||
// Modifica una propiedad del enemigo seleccionado
|
||||
auto MapEditor::setEnemyProperty(const std::string& property, const std::string& value) -> std::string {
|
||||
if (!active_) { return "Editor not active"; }
|
||||
if (!hasSelectedEnemy()) { return "No enemy selected"; }
|
||||
|
||||
auto& enemy = room_data_.enemies[selected_enemy_];
|
||||
|
||||
if (property == "ANIMATION") {
|
||||
std::string anim = toLower(value);
|
||||
if (anim.find('.') == std::string::npos) { anim += ".yaml"; }
|
||||
|
||||
// Intentar recrear el enemigo con la nueva animación
|
||||
std::string old_anim = enemy.animation_path;
|
||||
enemy.animation_path = anim;
|
||||
try {
|
||||
auto* enemy_mgr = room_->getEnemyManager();
|
||||
enemy_mgr->getEnemy(selected_enemy_) = std::make_shared<Enemy>(enemy);
|
||||
} catch (const std::exception& e) {
|
||||
enemy.animation_path = old_anim; // Restaurar si falla
|
||||
return std::string("Error: ") + e.what();
|
||||
}
|
||||
|
||||
autosave();
|
||||
return "animation: " + anim;
|
||||
}
|
||||
|
||||
if (property == "COLOR") {
|
||||
std::string color = toLower(value);
|
||||
|
||||
// Intentar recrear el enemigo con el nuevo color
|
||||
std::string old_color = enemy.color;
|
||||
enemy.color = color;
|
||||
try {
|
||||
auto* enemy_mgr = room_->getEnemyManager();
|
||||
enemy_mgr->getEnemy(selected_enemy_) = std::make_shared<Enemy>(enemy);
|
||||
} catch (const std::exception& e) {
|
||||
enemy.color = old_color;
|
||||
return std::string("Error: ") + e.what();
|
||||
}
|
||||
|
||||
autosave();
|
||||
return "color: " + color;
|
||||
}
|
||||
|
||||
if (property == "VX") {
|
||||
try {
|
||||
enemy.vx = std::stof(value);
|
||||
} catch (...) { return "Invalid value: " + value; }
|
||||
enemy.vy = 0.0F; // No se permiten velocidades en los dos ejes
|
||||
|
||||
room_->getEnemyManager()->getEnemy(selected_enemy_)->resetToInitialPosition(enemy);
|
||||
autosave();
|
||||
return "vx: " + std::to_string(static_cast<int>(enemy.vx)) + " vy: 0";
|
||||
}
|
||||
|
||||
if (property == "VY") {
|
||||
try {
|
||||
enemy.vy = std::stof(value);
|
||||
} catch (...) { return "Invalid value: " + value; }
|
||||
enemy.vx = 0.0F; // No se permiten velocidades en los dos ejes
|
||||
|
||||
room_->getEnemyManager()->getEnemy(selected_enemy_)->resetToInitialPosition(enemy);
|
||||
autosave();
|
||||
return "vy: " + std::to_string(static_cast<int>(enemy.vy)) + " vx: 0";
|
||||
}
|
||||
|
||||
if (property == "FLIP") {
|
||||
enemy.flip = (value == "ON" || value == "TRUE" || value == "1");
|
||||
|
||||
room_->getEnemyManager()->getEnemy(selected_enemy_)->resetToInitialPosition(enemy);
|
||||
autosave();
|
||||
return std::string("flip: ") + (enemy.flip ? "on" : "off");
|
||||
}
|
||||
|
||||
return "Unknown property: " + property + " (use: animation, color, vx, vy, flip)";
|
||||
}
|
||||
|
||||
#endif // _DEBUG
|
||||
|
||||
Reference in New Issue
Block a user