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:
1 parent
e6b612d164
commit
ee8dc25181
17 files changed
+378
-66
No files matched your search
@@ -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();
|
||||
|
||||
Reference in new issue
Block a user