Files
aee-arcade/source/game/scenes/game_scene.cpp
T
JailDesigner e6c7f0dcfb HC-03: geometria del mapa traslladada de map.hpp al YAML de la piràmide
El bloc `geometry:` de pyramid.yaml porta les 9 constants base (grid, sarc,
pitch, HUD, murs); els derivats (corridor, board, origin, playfield) es
recalculen al `Map::loadFrom()`. `constexpr` passa a `const` on calia i
els membres estàtics adopten snake_case. Desbloqueja la iteració
"pirámide a pirámide" sense recompilar.
2026-04-20 17:32:56 +02:00

110 lines
4.4 KiB
C++

#include "game/scenes/game_scene.hpp"
#include <SDL3/SDL.h>
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <vector>
#include "core/audio/audio.hpp"
#include "core/input/global_inputs.hpp"
#include "core/rendering/notifier.hpp"
#include "core/rendering/render_info.hpp"
#include "core/rendering/screen.hpp"
#include "core/resources/resource_cache.hpp"
#include "game/entities/player.hpp"
#include "game/map/map.hpp"
#include "game/options.hpp"
#include "game/ui/ui_palette.hpp"
#include "utils/defaults.hpp"
#include "utils/defines.hpp"
namespace {
// La geometria ha de quedar inicialitzada abans que Tilemap parsejar el
// mateix YAML i abans que el ctor de Player consulte Map::PLAYFIELD_*.
// Cridar-la des d'una expressió que retorne la ruta permet encadenar-ho
// a l'init list sense fer Tilemap default-constructible.
auto loadMapGeometry(const char* yaml_path) -> const char* {
Map::loadFrom(yaml_path);
return yaml_path;
}
} // namespace
GameScene::GameScene()
: tilemap_(loadMapGeometry("data/maps/pyramid.yaml")) {
Resource::Cache::get().loadSurface("player.gif", "data/player/player.gif");
Resource::Cache::get().loadAnimation("player.yaml", "data/player/player.yaml");
// Jugador 0: fletxes del teclat (Defaults::KeysGame). Instanciar-ne un
// segon només requereix afegir una altra entrada amb uns Controls
// distints (p.ex. WASD).
const Player::Controls CONTROLS_P1{
.up = Defaults::KeysGame::UP,
.down = Defaults::KeysGame::DOWN,
.left = Defaults::KeysGame::LEFT,
.right = Defaults::KeysGame::RIGHT,
};
// Spawn centrat al passadís exterior superior: la caixa de col·lisió
// queda dins del passadís vertical del mig (entre columnes 1 i 2) i
// centrada en Y al passadís exterior superior. Així no naix dins de
// cap sarcòfag.
constexpr auto CORRIDOR_CENTER_X = static_cast<float>(GameCanvas::CENTER_X);
const auto CORRIDOR_CENTER_Y =
static_cast<float>(Map::playfield_y) + (static_cast<float>(Map::outer_corridor) / 2.0F);
constexpr auto SPAWN_X = CORRIDOR_CENTER_X - (static_cast<float>(Player::SPRITE_WIDTH) / 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>(SPAWN_X, SPAWN_Y, CONTROLS_P1));
// Música de fons de la piràmide 1 en bucle infinit. El track ja està al
// Resource::Cache (preload al Director), així que playMusic només mou el
// punter cap a jail_audio i obri l'stream.
if (Audio::get() != nullptr) {
Audio::get()->playMusic("pyramid_1.ogg", -1);
}
}
GameScene::~GameScene() = default;
void GameScene::update(int delta_ms) {
GlobalInputs::update(delta_ms);
if (GlobalInputs::wantsQuit()) { wants_quit_ = true; }
const float DT = static_cast<float>(delta_ms) / 1000.0F;
for (auto& player : players_) { player->update(DT); }
RenderInfo::get().update(delta_ms, Options::buildRenderInfoFrame(UiColor::RENDER_INFO_TEXT, UiColor::RENDER_INFO_SHADOW));
Notifier::get().update(delta_ms);
}
void GameScene::render() {
const auto BG_ARGB = Resource::Cache::get().getPalette("ui")[UiColor::CANVAS_BG];
Screen::get().fillRect(0, 0, GameCanvas::WIDTH, GameCanvas::HEIGHT, BG_ARGB);
// Mapa visual: textura prerenderitzada del tilemap. Els sarcòfags
// queden "foradats" (cel·les transparents) perquè passaran a ser
// actors independents; Map::collides encara els bloqueja per a les
// col·lisions del jugador.
tilemap_.render();
// Ordenem punters a jugadors per Y dels peus (ascendent = més al fons
// primer). Usem un vector auxiliar per no tocar l'ordre d'entrada de
// players_, que és el d'assignació de controls.
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();
});
// De moment els sarcòfags no es pinten (seran actors independents);
// dibuixem tots els jugadors sobre el tilemap ja ordenats per Y. Quan
// els sarcs siguen sprites, tornarem a interleave per al Z-order.
for (auto* player : sorted) { player->render(); }
Notifier::get().render();
RenderInfo::get().render();
Screen::get().present();
}