feat(editor): mou la porta i persisteix geometry.door_col
This commit is contained in:
1 parent
a254fdd669
commit
c003e6665e
8 files changed
+214
-20
No files matched your search
@@ -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; });
|
||||
|
||||
@@ -97,7 +97,7 @@ class Editor {
|
||||
// des d'`update`.
|
||||
void updateTileBrush(Tilemap& tilemap, int canvas_x, int canvas_y);
|
||||
void updateEntityBrush(EntityManager& entities, int canvas_x, int canvas_y);
|
||||
void updateHand(EntityManager& entities, int canvas_x, int canvas_y);
|
||||
void updateHand(const Tilemap& tilemap, EntityManager& entities, int canvas_x, int canvas_y);
|
||||
void updateTilePicker(const Tilemap& tilemap, int canvas_x, int canvas_y);
|
||||
void updateEntityPicker(int canvas_x, int canvas_y);
|
||||
|
||||
@@ -111,12 +111,15 @@ class Editor {
|
||||
// Mou l'entitat seleccionada a la cel·la del cursor: borra l'antiga
|
||||
// i crida `addSpawn` amb la nova posició. Reusa la mateixa lògica
|
||||
// de snap/solapament que la col·locació nova, excloent l'entitat
|
||||
// que es mou del check de solapament.
|
||||
auto tryMoveSelected(EntityManager& entities) const -> bool;
|
||||
// que es mou del check de solapament. Cas especial per a la porta:
|
||||
// el sprite ocupa 3 cols (col-1, col, col+1) sobre el mur superior;
|
||||
// per tant la columna central vàlida és [1, cols-2] — `tilemap` és
|
||||
// necessari per saber `cols`.
|
||||
auto tryMoveSelected(const Tilemap& tilemap, EntityManager& entities) const -> bool;
|
||||
|
||||
// Sub-handlers de `updateHand`. Aïllats per mantenir baixa la
|
||||
// complexitat cognitiva del bucle d'esdeveniments.
|
||||
void handleHandLeftClick(EntityManager& entities);
|
||||
void handleHandLeftClick(const Tilemap& tilemap, EntityManager& entities);
|
||||
void handleHandRightClick();
|
||||
|
||||
// Borra l'entitat seleccionada. La validació de constraints
|
||||
|
||||
Reference in new issue
Block a user