feat(editor): mou la porta i persisteix geometry.door_col

This commit is contained in:
JailDesigner committed 2026-05-02 13:35:01 +02:00
1 parent a254fdd669
commit c003e6665e
8 files changed
+214 -20

No files matched your search

+40 -12
View File
@@ -28,6 +28,7 @@
#include "game/entities/entity_writer.hpp"
#include "game/levels/level_manager.hpp"
#include "game/map/map.hpp"
#include "game/map/map_writer.hpp"
#include "game/map/tilemap.hpp"
#include "utils/defaults.hpp"
#include "utils/defines.hpp"
@@ -332,7 +333,11 @@ void Editor::exit(Tilemap& tilemap, const EntityManager& entities) {
const auto ABS_PATH = Resource::Helper::resolve(Levels::LevelManager::get().currentPath());
const bool TILES_OK = tilemap.save(ABS_PATH);
const bool ENTITIES_OK = EntityWriter::saveEntitiesBlock(ABS_PATH, gatherSpawns(entities));
const bool SAVED = TILES_OK && ENTITIES_OK;
// Persistim també `geometry.door_col`: l'editor permet canviar la
// columna de la porta, així que la geometry del YAML ha de
// reflectir-ho a la pròxima càrrega.
const bool GEO_OK = MapWriter::saveDoorCol(ABS_PATH, Map::door_col);
const bool SAVED = TILES_OK && ENTITIES_OK && GEO_OK;
Notification::notify(Locale::get().text(SAVED ? "input.editor_off" : "input.editor_save_error"));
}
@@ -430,7 +435,7 @@ void Editor::update(int /*delta_ms*/, Tilemap& tilemap, EntityManager& entities)
updateEntityBrush(entities, CX, CY);
break;
case Mode::HAND:
updateHand(entities, CX, CY);
updateHand(tilemap, entities, CX, CY);
break;
}
}
@@ -574,7 +579,7 @@ namespace {
} // namespace
void Editor::updateHand(EntityManager& entities, int canvas_x, int canvas_y) {
void Editor::updateHand(const Tilemap& tilemap, EntityManager& entities, int canvas_x, int canvas_y) {
const auto LIST = entities.getEntities();
hand_hover_idx_ = entityAtPixel(LIST, canvas_x, canvas_y);
if (hand_selected_idx_ >= static_cast<int>(LIST.size())) { hand_selected_idx_ = -1; }
@@ -582,7 +587,7 @@ void Editor::updateHand(EntityManager& entities, int canvas_x, int canvas_y) {
for (const auto& ev : EventBuffer::events) {
const bool IS_MOUSE_DOWN = (ev.type == SDL_EVENT_MOUSE_BUTTON_DOWN);
if (IS_MOUSE_DOWN && ev.button.button == SDL_BUTTON_LEFT) {
handleHandLeftClick(entities);
handleHandLeftClick(tilemap, entities);
} else if (IS_MOUSE_DOWN && ev.button.button == SDL_BUTTON_RIGHT) {
handleHandRightClick();
} else if (isDeleteKey(ev) && hand_selected_idx_ >= 0) {
@@ -591,7 +596,7 @@ void Editor::updateHand(EntityManager& entities, int canvas_x, int canvas_y) {
}
}
void Editor::handleHandLeftClick(EntityManager& entities) {
void Editor::handleHandLeftClick(const Tilemap& tilemap, EntityManager& entities) {
if (hand_selected_idx_ < 0) {
// Sense selecció: si pulsem sobre una entitat, seleccionem.
if (hand_hover_idx_ >= 0) { hand_selected_idx_ = hand_hover_idx_; }
@@ -608,7 +613,7 @@ void Editor::handleHandLeftClick(EntityManager& entities) {
return;
}
// Cel·la sense entitat: intenta moure-hi la seleccionada.
if (tryMoveSelected(entities)) { hand_selected_idx_ = -1; }
if (tryMoveSelected(tilemap, entities)) { hand_selected_idx_ = -1; }
}
void Editor::handleHandRightClick() {
@@ -619,7 +624,7 @@ void Editor::handleHandRightClick() {
}
}
auto Editor::tryMoveSelected(EntityManager& entities) const -> bool {
auto Editor::tryMoveSelected(const Tilemap& tilemap, EntityManager& entities) const -> bool {
if (hand_selected_idx_ < 0 || cursor_col_ < 0 || cursor_row_ < 0) { return false; }
auto list = entities.getEntities();
if (hand_selected_idx_ >= static_cast<int>(list.size())) { return false; }
@@ -627,12 +632,35 @@ auto Editor::tryMoveSelected(EntityManager& entities) const -> bool {
auto* target = list[hand_selected_idx_];
const std::string TYPE = target->getName();
// Construïm el nou spawn excloent l'entitat que mou del check de
// solapaments: si no, sempre xocaria amb ella mateixa. Per a la
// porta, el "moviment" actualment és no-op (no portem encara la
// columna a YAML), així que el descartem amb claredat.
if (TYPE == "door") { return false; }
if (TYPE == "door") {
// La porta viu sempre al mur trasser; només varia la columna.
// El sprite ocupa 3 cel·les (col-1, col, col+1), així que la
// columna central vàlida és [1, cols-2]. La fila no influeix
// (l'usuari pot clicar a qualsevol fila): només importa la
// columna del cursor.
const int COLS = tilemap.getCols();
if (cursor_col_ < 1 || cursor_col_ > COLS - 2) { return false; }
if (cursor_col_ == Map::door_col) { return false; }
// Recolocació: actualitzem `Map::door_col` (i el seu derivat
// `door_corridor_x`), borrem l'entitat porta actual i en
// creem una de nova: `placeDoor` la posicionarà segons el
// nou `Map::door_col`. La persistència al YAML
// (`geometry.door_col`) es fa a `Editor::exit` a banda dels
// blocs `data:` i `entities:`.
Map::door_col = cursor_col_;
Map::door_corridor_x = (Map::door_col * Map::tile_size) + Map::tilemap_origin_x;
if (!entities.removeEntity(target)) { return false; }
try {
const std::string STR = "type: door\n";
auto node = fkyaml::node::deserialize(STR.begin(), STR.end());
return entities.addSpawn(node) != nullptr;
} catch (const std::exception&) {
return false;
}
}
// Resta d'entitats: snap a cel·la del cursor amb check de
// solapaments excloent la pròpia.
std::vector<Entity*> filtered;
filtered.reserve(list.size() - 1);
std::ranges::copy_if(list, std::back_inserter(filtered), [target](const Entity* e) { return e != target; });