feat(entities): andamiatge del sistema d'entitats (classes, factory, bus, YAML, placeholders, smoke tests)

This commit is contained in:
JailDesigner committed 2026-04-21 12:35:19 +02:00
1 parent 984cc820c0
commit 96b71b0f65
48 files changed
+1957

No files matched your search

@@ -0,0 +1,86 @@
#pragma once
#include <cstdint>
#include <functional>
#include <unordered_set>
#include "external/fkyaml_node.hpp"
#include "game/entities/animation_component.hpp"
#include "game/entities/interactable.hpp"
// Sarcòfag: rectangle de tiles que el jugador ha de rodar completament pel
// perímetre per "obrir". Tres estats (com la porta):
// CLOSED → inicial; `visited_` s'acumula amb les notificacions.
// OPENING → `visited_ == perimeter_tiles_`; reprodueix animació d'obertura.
// OPEN → emitit l'event `sarcophagus_opened`.
//
// El càlcul de `perimeter_tiles_` es fa al ctor a partir de la posició del
// sarcòfag a la graella del Map (`anchor_col`, `anchor_row`) i de les
// dimensions en tiles (`tile_size_w_`, `tile_size_h_`, llegits del YAML
// plantilla). Es recorren els tiles adjacents per N/S/E/O; els que
// cauen dins d'un altre sarcòfag es descarten (predicat opcional). Si no
// s'aporta el predicat, s'inclouen tots.
class Sarcophagus : public Interactable {
public:
enum class State : std::uint8_t { CLOSED,
OPENING,
OPEN };
// `is_blocked` rep un (col,row) i retorna true si el tile està ocupat
// per un altre sarcòfag o és fora del playfield (és a dir, NO és un
// tile de corredor vàlid). L'usa `EntityManager` passant-li
// `Map::collides` traduït a tiles. Si és nullptr, cap tile es descarta
// i el perímetre es computa purament geomètric (útil als tests).
using BlockedPredicate = std::function<bool(int col, int row)>;
Sarcophagus(const fkyaml::node& yaml, int anchor_col, int anchor_row, const BlockedPredicate& is_blocked);
explicit Sarcophagus(const fkyaml::node& yaml); // variant sense ancoratge (usat pel factory)
// Configura ancoratge i (re)calcula perímetre. Útil quan el factory
// crea l'instància abans de conèixer la posició; el `EntityLoader`
// invoca aquesta funció amb les coordenades del spawn.
void place(int anchor_col, int anchor_row, const BlockedPredicate& is_blocked);
void update(float delta_time) override;
void notifyTileEntered(int col, int row) override;
[[nodiscard]] auto getState() const -> State { return state_; }
[[nodiscard]] auto getPerimeterSize() const -> std::size_t { return perimeter_tiles_.size(); }
[[nodiscard]] auto getVisitedCount() const -> std::size_t { return visited_.size(); }
// Dimensions del rectangle en tiles (p.ex. 3×1 per al sarcòfag
// estàndard). Exposat per al smoke test i per al render futur.
[[nodiscard]] auto getTileWidth() const -> int { return tile_size_w_; }
[[nodiscard]] auto getTileHeight() const -> int { return tile_size_h_; }
private:
struct TileKey {
int col;
int row;
auto operator==(const TileKey& o) const -> bool { return col == o.col && row == o.row; }
};
struct TileKeyHash {
auto operator()(const TileKey& k) const -> std::size_t {
// Combinació simple; els valors són petits (<100) i el set no és gran.
return (static_cast<std::size_t>(k.col) * 131U) ^ static_cast<std::size_t>(k.row);
}
};
void computePerimeter(const BlockedPredicate& is_blocked);
int tile_size_w_{1};
int tile_size_h_{1};
int anchor_col_{0};
int anchor_row_{0};
std::unordered_set<TileKey, TileKeyHash> perimeter_tiles_;
std::unordered_set<TileKey, TileKeyHash> visited_;
State state_{State::CLOSED};
AnimationComponent anim_closed_;
AnimationComponent anim_opening_;
AnimationComponent anim_open_;
bool opened_event_emitted_{false};
};