feat(game_scene): integra PaintLayer i llegeix paint_tile del YAML del mapa

This commit is contained in:
JailDesigner committed 2026-04-23 13:31:13 +02:00
1 parent e3cf2eb773
commit d0503ff8b1
2 files changed
+47 -3

No files matched your search

+37 -3
View File
@@ -21,7 +21,9 @@
#include "core/rendering/screen.hpp"
#include "core/rendering/text.hpp"
#include "core/resources/resource_cache.hpp"
#include "core/resources/resource_helper.hpp"
#include "core/system/event_buffer.hpp"
#include "external/fkyaml_node.hpp"
#include "game/entities/entity.hpp"
#include "game/entities/event_bus.hpp"
#include "game/entities/player.hpp"
@@ -42,6 +44,21 @@ namespace {
return Tilemap(yaml_path);
}
// Llegeix un camp sencer opcional del YAML del mapa. Si no hi és,
// retorna `fallback` (per defecte -1, que al Player indica "no pinta").
// S'usa per `player1_paint_tile` i `player2_paint_tile`: cada jugador
// pinta amb l'índex declarat al mapa, i un mapa sense aquests camps
// simplement no deixa rastre visual.
auto readOptionalInt(const std::string& yaml_path, const std::string& key, int fallback = -1) -> int {
auto bytes = Resource::Helper::loadFile(yaml_path);
if (bytes.empty()) { return fallback; }
const auto* begin = reinterpret_cast<const char*>(bytes.data());
const auto* end = begin + bytes.size();
auto yaml = fkyaml::node::deserialize(begin, end);
if (!yaml.contains(key)) { return fallback; }
return yaml[key].get_value<int>();
}
} // namespace
auto GameScene::defaultConfig() -> Config {
@@ -103,10 +120,23 @@ GameScene::GameScene(Config config)
static_cast<float>(Map::playfield_y) + (static_cast<float>(Map::outer_corridor) / 2.0F);
const auto SPAWN_X = CORRIDOR_CENTER_X - (static_cast<float>(Player::sprite_w) / 2.0F);
const auto SPAWN_Y = CORRIDOR_CENTER_Y - static_cast<float>(Player::collision_y_offset) - (static_cast<float>(Player::collision_size) / 2.0F);
players_.emplace_back(std::make_unique<Player>(ANIM_KEY, SPAWN_X, SPAWN_Y, CONTROLS_P1, Map::makeInfo()));
// Índex de tile amb què pinta cada jugador — llegit del YAML del mapa
// (camps opcionals `player1_paint_tile` / `player2_paint_tile`). Si no
// hi són, `paint_tile_index_ = -1` i el Player no deixa rastre.
const int P1_PAINT = readOptionalInt(config_.map_yaml, "player1_paint_tile", -1);
players_.emplace_back(std::make_unique<Player>(ANIM_KEY, SPAWN_X, SPAWN_Y, CONTROLS_P1, Map::makeInfo(), P1_PAINT));
// Connectem el Player al bus perquè emeti `on_tile_entered` i els
// sarcòfags rebin les notificacions de pas per tile.
// PaintLayer: font única del pintat del nivell. Es crea després de
// `loadFromLevel` perquè l'EntityManager ja ha de tenir els sarcòfags
// registrats (tot i que el sarc escolta via fan-out, no directament
// al bus; l'ordre de subscripcions aquí és irrellevant per la
// correcció, però sí pel log d'arrencada). Connectat al bus del
// manager per subscriure's a `on_tile_entered` i publicar `tile_painted`.
paint_layer_ = std::make_unique<PaintLayer>(tilemap_, &entity_manager_.getBus());
// Connectem el Player al bus perquè emeti `on_tile_entered` i el
// PaintLayer (subscrit ja) processe el pintat; el fan-out cap als
// sarcòfags passa per `tile_painted`.
players_.back()->setEventBus(&entity_manager_.getBus());
// Música de fons en bucle infinit. El track ja està al Resource::Cache
@@ -228,6 +258,10 @@ void GameScene::render() {
#else
constexpr bool SKIP_ACTORS = false;
#endif
// Capa de pintat: va entre el tilemap base i els actors, perquè els
// sarcòfags i el jugador la tapen. S'amaga al mode editor (decisió
// explícita: l'editor edita el tilemap, no la capa de pintat).
if (!SKIP_ACTORS && paint_layer_) { paint_layer_->render(); }
if (!SKIP_ACTORS) {
// Z-order interleaving entitats ↔ players per `getFeetY()` ascendent:
// els actors amb els peus més amunt queden dibuixats primer (al fons),
+10
View File
@@ -6,6 +6,7 @@
#include "core/scene/scene.hpp"
#include "game/entities/entity_manager.hpp"
#include "game/map/paint_layer.hpp"
#include "game/map/tilemap.hpp"
#ifdef _DEBUG
@@ -53,6 +54,15 @@ class GameScene : public Scene {
// té els seus propis Controls i entra al vector amb una crida extra.
std::vector<std::unique_ptr<Player>> players_;
// Capa de "pintat" del terra. Escolta `on_tile_entered` al bus,
// filtra pintabilitat (sòl transitable) i re-publica `tile_painted`
// per als sarcòfags. `unique_ptr` per controlar l'ordre de
// construcció/destrucció: es crea al ctor un cop `entity_manager_` i
// `tilemap_` estan llestos, i es destrueix abans que `entity_manager_`
// (on viu el bus al qual està subscrit). Declarat després d'aquests
// dos membres per garantir l'ordre invers a la destrucció.
std::unique_ptr<PaintLayer> paint_layer_;
// Pausa de gameplay. Quan `paused_` és true, l'update de jugadors i
// entitats es salta (el món es congela); l'input d'UI (GlobalInputs,
// Notifier, RenderInfo) continua per no perdre hotkeys ni l'overlay de