feat(entities): fase 4 - moviment de la momia amb col·lisió, z-order per peus i contacte amb el jugador

This commit is contained in:
JailDesigner committed 2026-04-21 20:14:47 +02:00
1 parent e6b612d164
commit ee8dc25181
17 files changed
+378 -66

No files matched your search

+39 -19
View File
@@ -17,6 +17,7 @@
#include "core/rendering/render_info.hpp"
#include "core/rendering/screen.hpp"
#include "core/resources/resource_cache.hpp"
#include "game/entities/entity.hpp"
#include "game/entities/event_bus.hpp"
#include "game/entities/player.hpp"
#include "game/map/map.hpp"
@@ -123,6 +124,17 @@ void GameScene::update(int delta_ms) {
// als sarcòfags via la subscripció del bus, i aquest `update` pot
// aplicar la transició OPENING → OPEN en el mateix frame.
entity_manager_.update(DT);
// Detecció de contacte player↔entitat després que totes les entitats
// hagin mogut aquest frame. La porta (si està oberta) emet
// `level_complete`; la momia/trampa emet `player_hit`. Els sarcs, encara
// que tinguen collides=true, tenen la caixa lògica fora del camí del
// jugador (gràcies a Map::collides al Player::update), així que aquí
// no generen falsos contactes.
std::vector<Player*> player_ptrs;
player_ptrs.reserve(players_.size());
std::ranges::transform(players_, std::back_inserter(player_ptrs), [](const auto& p) { return p.get(); });
entity_manager_.checkPlayerCollisions(player_ptrs);
RenderInfo::get().update(delta_ms, Options::buildRenderInfoFrame(UiColor::RENDER_INFO_TEXT, UiColor::RENDER_INFO_SHADOW));
Notifier::get().update(delta_ms);
}
@@ -137,25 +149,33 @@ void GameScene::render() {
// col·lisions del jugador.
tilemap_.render();
// Entitats (sarcòfags, porta, momia, antorxa...) dibuixades per sobre
// dels tiles però sota dels players. Z-order fi (interleaving per feetY
// amb els sarcs) queda per a una tasca posterior; "sin pulido".
entity_manager_.renderAll();
// Amb un sol jugador, l'ordre és irrellevant i ens estalviem el vector
// temporal. Quan n'hi haja més d'un (o quan els sarcs siguen sprites)
// caldrà ordenar per `getFeetY()` ascendent i interleaveing amb les
// files de sarcs — l'ordre ascendent manté els més al fons darrere.
if (players_.size() <= 1) {
for (auto& player : players_) { player->render(); }
} else {
std::vector<Player*> sorted;
sorted.reserve(players_.size());
std::ranges::transform(players_, std::back_inserter(sorted), [](const auto& p) { return p.get(); });
std::ranges::sort(sorted, [](const Player* a, const Player* b) {
return a->getFeetY() < b->getFeetY();
});
for (auto* player : sorted) { player->render(); }
// Z-order interleaving entitats ↔ players per `getFeetY()` ascendent:
// els actors amb els peus més amunt queden dibuixats primer (al fons),
// els més avall al davant. Així un sarc situat per darrere d'un player
// queda tapat per ell, i un sarc a davant el tapa a ell.
struct Renderable {
float feet_y;
Entity* entity; // nullable; si és nullptr, s'usa `player`.
Player* player; // nullable; si és nullptr, s'usa `entity`.
};
std::vector<Renderable> order;
order.reserve(entity_manager_.entityCount() + players_.size());
const auto ENTITIES = entity_manager_.getEntities();
std::ranges::transform(ENTITIES, std::back_inserter(order), [](Entity* e) {
return Renderable{.feet_y = e->getFeetY(), .entity = e, .player = nullptr};
});
std::ranges::transform(players_, std::back_inserter(order), [](const auto& p) {
return Renderable{.feet_y = p->getFeetY(), .entity = nullptr, .player = p.get()};
});
std::ranges::stable_sort(order, [](const Renderable& a, const Renderable& b) {
return a.feet_y < b.feet_y;
});
for (const auto& r : order) {
if (r.entity != nullptr) {
EntityManager::renderEntity(*r.entity);
} else if (r.player != nullptr) {
r.player->render();
}
}
Notifier::get().render();