feat(entities): afegeix stone i column com a muros decoratius

This commit is contained in:
JailDesigner committed 2026-05-12 13:03:35 +02:00
1 parent 1c49248b72
commit 6749780356
18 files changed
+448 -36

No files matched your search

@@ -395,6 +395,17 @@ namespace {
}
entity->setPixelRect({.x = rect_x, .y = rect_y, .w = sprite.width, .h = sprite.height});
// Variant del atlas: el spawn pot fixar un sub-sprite estàtic via
// `frame: N`. El render del manager ja sap clipar (col, row) a
// partir d'un índex lineal i la mida del frame; ací només cal
// muntar un `AnimationComponent` d'un sol frame i imposar-lo a la
// entitat. Cap entitat existent al joc emet aquest camp; només
// els muros decoratius amb variants (stone, column, ...) l'usen.
if (spawn.contains("frame")) {
const int FRAME = spawn["frame"].get_value<int>();
entity->setAnimation(AnimationComponent({FRAME}, 1.0F, false));
}
manager.add(std::move(entity));
return true;
}
@@ -459,31 +470,45 @@ void EntityManager::loadFromLevel(const std::string& level_yaml_path) {
if (addSpawn(spawn) != nullptr) { ++loaded; }
}
// Broadcast inicial: marca com a "pintats" tots els tiles ocupats per
// decals de sòl (Hole, i futurs pinchos plans, plaques, charcos...).
// Imprescindible perquè el jugador no pot trepitjar aquests tiles
// (cauria al forat) i els sarcòfags vecins no podrien completar el
// perímetre — la sala seria incompletable. Usa el canal semàntic
// `tile_painted` (lògica de joc), no `on_tile_entered` (presència
// física del jugador). Ho fem aquí, després del bucle de spawns,
// perquè tots els sarcòfags ja estan registrats al fan-out (la
// subscripció del manager és al ctor, anterior a qualsevol load).
// Broadcast inicial: marca com a "pintats" tots els tiles que el
// jugador no pot trepitjar mai, de manera que el perímetre dels
// sarcòfags vecins ja els consideri visitats i la sala sigui
// completable. Inclou dues famílies:
// - Decals de sòl (Hole, i futurs pinchos plans, plaques, charcos):
// trigger-on-overlap que mataria/atraparia al jugador en trepitjar.
// - Entitats sòlides genèriques (debris, columnes...): obstacles
// físics que `Map::collides` bloqueja, així `isPaintable` retorna
// false per als seus tiles i ningú els pot pintar.
// Usa el canal semàntic `tile_painted` (lògica de joc), no
// `on_tile_entered` (presència física). Es fa aquí, després del bucle
// de spawns, perquè tots els sarcòfags ja estan registrats al fan-out
// (la subscripció del manager és al ctor, anterior a qualsevol load).
int decal_broadcast = 0;
// Els decals de sòl (Hole, futurs pinchos plans...) són StaticHazards;
// iterem tot `entities_` i el filtre per `isFloorDecal()` els tria.
for (const auto& entity : entities_) {
if (!entity->isFloorDecal()) { continue; }
const bool IS_DECAL = entity->isFloorDecal();
const bool IS_SOLID = entity->blocksMovement();
if (!IS_DECAL && !IS_SOLID) { continue; }
const auto BOX = entity->getCollisionRect();
const auto [COL, ROW] = Map::pixelToTile(BOX.x, BOX.y);
bus_.publish(Event{
.name = "tile_painted",
.payload = TilePos{.col = COL, .row = ROW},
.player_id = -1,
});
++decal_broadcast;
// Per a entitats que ocupen més d'un tile (futurs murs 32×16,
// 16×32, etc.), iterem tota la zona coberta pel rect. Per a decals
// i blocs d'un sol tile cau a un sol broadcast (mateix comportament
// que abans).
const auto [COL0, ROW0] = Map::pixelToTile(BOX.x, BOX.y);
const int COLS = (Map::tile_size > 0) ? std::max(1, static_cast<int>(BOX.w) / Map::tile_size) : 1;
const int ROWS = (Map::tile_size > 0) ? std::max(1, static_cast<int>(BOX.h) / Map::tile_size) : 1;
for (int dr = 0; dr < ROWS; ++dr) {
for (int dc = 0; dc < COLS; ++dc) {
bus_.publish(Event{
.name = "tile_painted",
.payload = TilePos{.col = COL0 + dc, .row = ROW0 + dr},
.player_id = -1,
});
++decal_broadcast;
}
}
}
if (decal_broadcast > 0) {
Log::info("EntityManager", "{} tile_painted broadcast inicial (decals de sòl)", decal_broadcast);
Log::info("EntityManager", "{} tile_painted broadcast inicial (decals + murs)", decal_broadcast);
}
Log::info("EntityManager", "{} entitats + {} actors pending des de {}", loaded, pending_actors_.size(), level_yaml_path);