Tilemap YAML: sala piràmide renderitzada amb tiles reals de tomb.gif i caixa de debug llevada (v0.13.0)
This commit is contained in:
1 parent
c921833537
commit
46a578fd86
12 files changed
+501
-45
No files matched your search
@@ -56,6 +56,7 @@ set(APP_SOURCES
|
|||||||
source/game/scenes/game_scene.cpp
|
source/game/scenes/game_scene.cpp
|
||||||
source/game/entities/player.cpp
|
source/game/entities/player.cpp
|
||||||
source/game/map/map.cpp
|
source/game/map/map.cpp
|
||||||
|
source/game/map/tilemap.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3)
|
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3)
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# Mapa de la piràmide: graella 21×15 de tiles 16×16 sobre tomb.gif.
|
||||||
|
# Overscan horitzontal: 8 px per banda (les parets laterals ocupen 2 tiles
|
||||||
|
# en el tilemap però només 1.5 visibles al canvas, així que la textura es
|
||||||
|
# dibuixa amb un origen de x=-8). Vertical no cal overscan: 15·16 = 240.
|
||||||
|
#
|
||||||
|
# Símbols del grid:
|
||||||
|
# W = paret (tile 99 del tileset, o (3,3) en 0-indexed)
|
||||||
|
# F = sòl (llista = un tile aleatori entre aquests per cada casella)
|
||||||
|
# . = cap tile (els sarcòfags seran actors, ací deixem transparent)
|
||||||
|
#
|
||||||
|
# Índexs lineals: els tiles van d'esquerra a dreta, de dalt a baix. Amb un
|
||||||
|
# tileset de 512×256 i tiles de 16×16 hi ha 32 tiles per fila.
|
||||||
|
|
||||||
|
tileset: data/tilesets/tomb.gif
|
||||||
|
tile_size: 16
|
||||||
|
origin: [-8, 0]
|
||||||
|
|
||||||
|
legend:
|
||||||
|
W: 292
|
||||||
|
X: 169
|
||||||
|
Y: 1
|
||||||
|
Z: 202
|
||||||
|
T: 200
|
||||||
|
R: 262
|
||||||
|
G: 263
|
||||||
|
H: 230
|
||||||
|
I: 231
|
||||||
|
J: 233
|
||||||
|
A: 2
|
||||||
|
B: 34
|
||||||
|
C: 33
|
||||||
|
D: 32
|
||||||
|
|
||||||
|
data: |
|
||||||
|
YYYYYYYYYYYYYYYYYYYYY
|
||||||
|
YHJJJJJJJJJJJJJJJJJIY
|
||||||
|
YZWWWWWWWWWWWWWWWWWTY
|
||||||
|
YZDDADDBBDDADDDDBDDTY
|
||||||
|
YZD...D...D...B...DTY
|
||||||
|
YZDDDCCDDDDDADDDBDDTY
|
||||||
|
YZD...D...A...D...DTY
|
||||||
|
YZDDCCDDDDDADDBDDDDTY
|
||||||
|
YZD...D...D...D...DTY
|
||||||
|
YZDDDDCCDDDDADDDDDDTY
|
||||||
|
YZD...D...D...D...DTY
|
||||||
|
YZDDDABDDDDADCDDBDDTY
|
||||||
|
YZD...D...D...D...DTY
|
||||||
|
YZDDBBDDADDDBCDDDDDTY
|
||||||
|
YRXXXXXXXXXXXXXXXXXGY
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
JASC-PAL
|
||||||
|
0100
|
||||||
|
256
|
||||||
|
255 255 255
|
||||||
|
247 247 247
|
||||||
|
239 239 239
|
||||||
|
231 231 231
|
||||||
|
223 223 223
|
||||||
|
215 215 215
|
||||||
|
207 207 207
|
||||||
|
199 199 199
|
||||||
|
191 191 191
|
||||||
|
183 183 183
|
||||||
|
175 175 175
|
||||||
|
167 167 167
|
||||||
|
159 159 159
|
||||||
|
151 151 151
|
||||||
|
143 143 143
|
||||||
|
135 135 135
|
||||||
|
127 127 127
|
||||||
|
119 119 119
|
||||||
|
111 111 111
|
||||||
|
103 103 103
|
||||||
|
95 95 95
|
||||||
|
87 87 87
|
||||||
|
79 79 79
|
||||||
|
71 71 71
|
||||||
|
63 63 63
|
||||||
|
55 55 55
|
||||||
|
47 47 47
|
||||||
|
39 39 39
|
||||||
|
31 31 31
|
||||||
|
23 23 23
|
||||||
|
15 15 15
|
||||||
|
7 7 7
|
||||||
|
0 0 0
|
||||||
|
191 167 143
|
||||||
|
183 160 136
|
||||||
|
175 152 128
|
||||||
|
167 144 120
|
||||||
|
159 137 113
|
||||||
|
150 129 105
|
||||||
|
142 121 97
|
||||||
|
134 114 90
|
||||||
|
126 106 82
|
||||||
|
117 98 74
|
||||||
|
109 90 66
|
||||||
|
101 83 59
|
||||||
|
93 75 51
|
||||||
|
84 67 43
|
||||||
|
76 60 36
|
||||||
|
67 51 27
|
||||||
|
191 123 75
|
||||||
|
179 115 71
|
||||||
|
171 111 67
|
||||||
|
163 107 63
|
||||||
|
155 99 59
|
||||||
|
143 95 55
|
||||||
|
135 87 51
|
||||||
|
127 83 47
|
||||||
|
119 79 43
|
||||||
|
107 71 39
|
||||||
|
95 67 35
|
||||||
|
83 63 31
|
||||||
|
75 55 27
|
||||||
|
63 47 23
|
||||||
|
51 43 19
|
||||||
|
43 35 15
|
||||||
|
255 235 223
|
||||||
|
255 227 211
|
||||||
|
255 219 199
|
||||||
|
255 211 187
|
||||||
|
255 207 179
|
||||||
|
255 199 167
|
||||||
|
255 191 155
|
||||||
|
255 187 147
|
||||||
|
255 179 131
|
||||||
|
247 171 123
|
||||||
|
239 163 115
|
||||||
|
231 155 107
|
||||||
|
223 147 99
|
||||||
|
215 139 91
|
||||||
|
207 131 83
|
||||||
|
203 127 79
|
||||||
|
255 238 220
|
||||||
|
255 220 185
|
||||||
|
255 203 151
|
||||||
|
255 185 117
|
||||||
|
255 168 85
|
||||||
|
255 151 54
|
||||||
|
255 134 25
|
||||||
|
255 117 0
|
||||||
|
243 109 0
|
||||||
|
229 101 0
|
||||||
|
216 93 0
|
||||||
|
203 85 0
|
||||||
|
190 77 0
|
||||||
|
177 69 0
|
||||||
|
164 61 0
|
||||||
|
151 54 0
|
||||||
|
255 255 239
|
||||||
|
255 255 207
|
||||||
|
255 255 175
|
||||||
|
255 255 143
|
||||||
|
255 255 111
|
||||||
|
255 255 79
|
||||||
|
255 255 47
|
||||||
|
255 255 15
|
||||||
|
255 255 0
|
||||||
|
207 207 0
|
||||||
|
175 175 0
|
||||||
|
143 143 0
|
||||||
|
111 111 0
|
||||||
|
79 79 0
|
||||||
|
47 47 0
|
||||||
|
15 15 0
|
||||||
|
255 255 115
|
||||||
|
235 219 87
|
||||||
|
215 187 67
|
||||||
|
195 155 47
|
||||||
|
175 123 31
|
||||||
|
155 91 19
|
||||||
|
135 67 7
|
||||||
|
115 43 0
|
||||||
|
255 223 223
|
||||||
|
255 191 191
|
||||||
|
255 159 159
|
||||||
|
255 127 127
|
||||||
|
255 95 95
|
||||||
|
255 63 63
|
||||||
|
255 31 31
|
||||||
|
255 0 0
|
||||||
|
239 0 0
|
||||||
|
223 0 0
|
||||||
|
207 0 0
|
||||||
|
191 0 0
|
||||||
|
175 0 0
|
||||||
|
159 0 0
|
||||||
|
143 0 0
|
||||||
|
127 0 0
|
||||||
|
111 0 0
|
||||||
|
95 0 0
|
||||||
|
79 0 0
|
||||||
|
63 0 0
|
||||||
|
47 0 0
|
||||||
|
31 0 0
|
||||||
|
15 0 0
|
||||||
|
255 183 183
|
||||||
|
243 163 163
|
||||||
|
231 143 143
|
||||||
|
219 123 123
|
||||||
|
203 107 107
|
||||||
|
191 91 91
|
||||||
|
179 79 79
|
||||||
|
167 63 63
|
||||||
|
142 46 0
|
||||||
|
134 39 0
|
||||||
|
126 32 0
|
||||||
|
117 25 0
|
||||||
|
109 18 0
|
||||||
|
101 11 0
|
||||||
|
93 5 0
|
||||||
|
85 0 0
|
||||||
|
119 255 79
|
||||||
|
112 240 75
|
||||||
|
105 224 70
|
||||||
|
97 208 65
|
||||||
|
90 192 60
|
||||||
|
82 176 55
|
||||||
|
75 160 50
|
||||||
|
67 144 45
|
||||||
|
60 128 40
|
||||||
|
53 112 35
|
||||||
|
45 96 30
|
||||||
|
38 80 25
|
||||||
|
30 64 20
|
||||||
|
23 48 15
|
||||||
|
15 32 10
|
||||||
|
7 15 4
|
||||||
|
222 255 168
|
||||||
|
199 228 148
|
||||||
|
173 200 128
|
||||||
|
149 173 107
|
||||||
|
124 146 88
|
||||||
|
100 119 68
|
||||||
|
74 90 48
|
||||||
|
50 63 29
|
||||||
|
0 255 0
|
||||||
|
0 223 0
|
||||||
|
0 191 0
|
||||||
|
0 159 0
|
||||||
|
0 127 0
|
||||||
|
0 95 0
|
||||||
|
0 63 0
|
||||||
|
0 31 0
|
||||||
|
255 111 255
|
||||||
|
255 0 255
|
||||||
|
223 0 223
|
||||||
|
191 0 191
|
||||||
|
159 0 159
|
||||||
|
127 0 127
|
||||||
|
95 0 95
|
||||||
|
63 0 63
|
||||||
|
233 233 243
|
||||||
|
196 196 225
|
||||||
|
157 157 206
|
||||||
|
119 119 187
|
||||||
|
84 84 167
|
||||||
|
65 65 131
|
||||||
|
46 46 92
|
||||||
|
27 27 52
|
||||||
|
213 241 255
|
||||||
|
191 235 255
|
||||||
|
170 227 255
|
||||||
|
149 221 255
|
||||||
|
128 214 255
|
||||||
|
106 207 255
|
||||||
|
85 200 255
|
||||||
|
63 191 255
|
||||||
|
55 157 223
|
||||||
|
47 143 191
|
||||||
|
39 119 159
|
||||||
|
31 95 127
|
||||||
|
0 191 191
|
||||||
|
0 127 127
|
||||||
|
0 95 95
|
||||||
|
0 63 63
|
||||||
|
231 231 255
|
||||||
|
198 198 255
|
||||||
|
173 173 255
|
||||||
|
140 140 255
|
||||||
|
115 115 255
|
||||||
|
82 82 255
|
||||||
|
49 49 255
|
||||||
|
24 24 255
|
||||||
|
0 0 255
|
||||||
|
0 0 231
|
||||||
|
0 0 206
|
||||||
|
0 0 181
|
||||||
|
0 0 156
|
||||||
|
0 0 132
|
||||||
|
0 0 107
|
||||||
|
0 0 82
|
||||||
|
0 0 79
|
||||||
|
0 0 63
|
||||||
|
0 0 55
|
||||||
|
0 0 39
|
||||||
|
0 0 31
|
||||||
|
0 0 15
|
||||||
|
0 0 7
|
||||||
|
0 255 255
|
||||||
|
207 127 207
|
||||||
|
183 111 183
|
||||||
|
159 95 159
|
||||||
|
135 79 135
|
||||||
|
111 63 111
|
||||||
|
87 47 87
|
||||||
|
63 31 63
|
||||||
|
39 15 39
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
@@ -4,9 +4,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
#include "core/rendering/screen.hpp"
|
|
||||||
#include "core/resources/resource_cache.hpp"
|
#include "core/resources/resource_cache.hpp"
|
||||||
#include "game/map/map.hpp"
|
#include "game/map/map.hpp"
|
||||||
|
|
||||||
@@ -16,10 +14,6 @@ namespace {
|
|||||||
// es pot convertir en un membre modificable.
|
// es pot convertir en un membre modificable.
|
||||||
constexpr float SPEED_PX_PER_S = 60.0F;
|
constexpr float SPEED_PX_PER_S = 60.0F;
|
||||||
|
|
||||||
// Color de debug per a la caixa de col·lisió (ARGB opac). S'elimina
|
|
||||||
// quan el joc estiga afinat.
|
|
||||||
constexpr std::uint32_t DEBUG_COLLISION_ARGB = 0xFF00FFFFU;
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Player::Player(float x, float y, const Controls& controls)
|
Player::Player(float x, float y, const Controls& controls)
|
||||||
@@ -94,18 +88,6 @@ void Player::update(float delta_time) {
|
|||||||
setPosY(std::clamp(getPosY(), MIN_Y, MAX_Y));
|
setPosY(std::clamp(getPosY(), MIN_Y, MAX_Y));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::render() {
|
|
||||||
// Debug: pinta la caixa de col·lisió (16×16) per sota del sprite perquè
|
|
||||||
// es vegen els límits del mapa de colisions alineats amb els passadissos.
|
|
||||||
Screen::get().fillRect(
|
|
||||||
static_cast<int>(getPosX()) + COLLISION_X_OFFSET,
|
|
||||||
static_cast<int>(getPosY()) + COLLISION_Y_OFFSET,
|
|
||||||
COLLISION_SIZE,
|
|
||||||
COLLISION_SIZE,
|
|
||||||
DEBUG_COLLISION_ARGB);
|
|
||||||
AnimatedSprite::render();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Player::baseBox() const -> SDL_FRect {
|
auto Player::baseBox() const -> SDL_FRect {
|
||||||
return {
|
return {
|
||||||
.x = getPosX() + static_cast<float>(COLLISION_X_OFFSET),
|
.x = getPosX() + static_cast<float>(COLLISION_X_OFFSET),
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ class Player : public AnimatedSprite {
|
|||||||
Player(float x, float y, const Controls& controls);
|
Player(float x, float y, const Controls& controls);
|
||||||
|
|
||||||
void update(float delta_time) override;
|
void update(float delta_time) override;
|
||||||
void render() override;
|
|
||||||
|
|
||||||
// Y de la base del jugador (cara inferior de la caixa de colisió). Usada
|
// Y de la base del jugador (cara inferior de la caixa de colisió). Usada
|
||||||
// per al Z-order contra els sarcs: peus per sobre d'un sarc → darrere;
|
// per al Z-order contra els sarcs: peus per sobre d'un sarc → darrere;
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ class Map {
|
|||||||
// Graella portada tal qual de l'AEE (4×4 sarcòfags, pitch 65×35).
|
// Graella portada tal qual de l'AEE (4×4 sarcòfags, pitch 65×35).
|
||||||
static constexpr int GRID_COLS = 4;
|
static constexpr int GRID_COLS = 4;
|
||||||
static constexpr int GRID_ROWS = 5;
|
static constexpr int GRID_ROWS = 5;
|
||||||
static constexpr int SARC_W = 50;
|
static constexpr int SARC_W = 48;
|
||||||
static constexpr int SARC_H = 16;
|
static constexpr int SARC_H = 16;
|
||||||
static constexpr int PITCH_X = 66;
|
static constexpr int PITCH_X = 64;
|
||||||
static constexpr int PITCH_Y = 32;
|
static constexpr int PITCH_Y = 32;
|
||||||
|
|
||||||
// El pas entre sarcòfags (15×15) és exactament el que ha de cabre el
|
// El pas entre sarcòfags (15×15) és exactament el que ha de cabre el
|
||||||
@@ -39,7 +39,7 @@ class Map {
|
|||||||
// pas de 320×200 → 320×240 i reforçar la falsa perspectiva.
|
// pas de 320×200 → 320×240 i reforçar la falsa perspectiva.
|
||||||
static constexpr int HUD_H = 24;
|
static constexpr int HUD_H = 24;
|
||||||
static constexpr int BACK_WALL_H = 24;
|
static constexpr int BACK_WALL_H = 24;
|
||||||
static constexpr int SIDE_WALL_W = 20;
|
static constexpr int SIDE_WALL_W = 24;
|
||||||
|
|
||||||
// Origen del tauler dins del canvas (cantó superior-esquerra del primer
|
// Origen del tauler dins del canvas (cantó superior-esquerra del primer
|
||||||
// sarcòfag). Derivat: mur + passadís en cada eix.
|
// sarcòfag). Derivat: mur + passadís en cada eix.
|
||||||
|
|||||||
@@ -0,0 +1,138 @@
|
|||||||
|
#include "game/map/tilemap.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "core/rendering/screen.hpp"
|
||||||
|
#include "core/rendering/surface.hpp"
|
||||||
|
#include "core/resources/resource_cache.hpp"
|
||||||
|
#include "external/fkyaml_node.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Cada símbol del grid es mapeja a (col, fila) dins del tileset.
|
||||||
|
using TileCoord = std::pair<int, int>;
|
||||||
|
using Legend = std::unordered_map<char, TileCoord>;
|
||||||
|
|
||||||
|
auto splitLines(const std::string& text) -> std::vector<std::string> {
|
||||||
|
std::vector<std::string> lines;
|
||||||
|
std::istringstream iss(text);
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(iss, line)) {
|
||||||
|
if (!line.empty()) { lines.push_back(line); }
|
||||||
|
}
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
// La llegenda usa índexs lineals del tileset (esq→dre, dalt→baix).
|
||||||
|
// Els convertim a (col, fila) amb el nombre de tiles per fila del tileset.
|
||||||
|
auto parseLegend(const fkyaml::node& node, int tileset_cols) -> Legend {
|
||||||
|
Legend legend;
|
||||||
|
for (auto it = node.begin(); it != node.end(); ++it) {
|
||||||
|
const auto KEY_STR = it.key().get_value<std::string>();
|
||||||
|
if (KEY_STR.empty()) { continue; }
|
||||||
|
const auto INDEX = it.value().get_value<int>();
|
||||||
|
const int COL = INDEX % tileset_cols;
|
||||||
|
const int ROW = INDEX / tileset_cols;
|
||||||
|
legend[KEY_STR.front()] = {COL, ROW};
|
||||||
|
}
|
||||||
|
return legend;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copia un tile (col, fila) del tileset al buffer ARGB a la posició de
|
||||||
|
// destí (dest_x, dest_y). Els píxels amb l'índex de transparència del
|
||||||
|
// tileset es deixen com estan al buffer (alpha=0 per defecte).
|
||||||
|
void blitTile(const Surface& tileset, int tile_size, int src_col, int src_row, std::vector<std::uint32_t>& dest, int dest_w, int dest_x, int dest_y) {
|
||||||
|
const int SRC_X0 = src_col * tile_size;
|
||||||
|
const int SRC_Y0 = src_row * tile_size;
|
||||||
|
const auto TRANSPARENT = tileset.getTransparentColor();
|
||||||
|
for (int y = 0; y < tile_size; ++y) {
|
||||||
|
for (int x = 0; x < tile_size; ++x) {
|
||||||
|
const auto IDX = tileset.getPixel(SRC_X0 + x, SRC_Y0 + y);
|
||||||
|
if (IDX == TRANSPARENT) { continue; }
|
||||||
|
const auto ARGB = tileset.getPaletteColor(IDX);
|
||||||
|
const auto DST_OFFSET =
|
||||||
|
(static_cast<std::size_t>(dest_y + y) * static_cast<std::size_t>(dest_w)) + static_cast<std::size_t>(dest_x + x);
|
||||||
|
dest[DST_OFFSET] = ARGB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Tilemap::Tilemap(const std::string& yaml_path) {
|
||||||
|
std::ifstream file(yaml_path);
|
||||||
|
if (!file.is_open()) {
|
||||||
|
throw std::runtime_error("Tilemap: no s'ha pogut obrir " + yaml_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto yaml = fkyaml::node::deserialize(file);
|
||||||
|
|
||||||
|
const auto TILESET_PATH = yaml["tileset"].get_value<std::string>();
|
||||||
|
const auto TILE_SIZE = yaml["tile_size"].get_value<int>();
|
||||||
|
if (yaml.contains("origin")) {
|
||||||
|
origin_x_ = yaml["origin"][0].get_value<int>();
|
||||||
|
origin_y_ = yaml["origin"][1].get_value<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carreguem el tileset al cache (idempotent) i el pillem per accedir
|
||||||
|
// als seus píxels i paleta. La paleta del tileset ve del GIF mateix.
|
||||||
|
// Ens cal abans de la llegenda per saber quants tiles per fila té.
|
||||||
|
const auto& cache_name = TILESET_PATH;
|
||||||
|
Resource::Cache::get().loadSurface(cache_name, TILESET_PATH);
|
||||||
|
const auto TILESET = Resource::Cache::get().getSurface(cache_name);
|
||||||
|
const int TILESET_COLS = TILESET->getWidth() / TILE_SIZE;
|
||||||
|
|
||||||
|
const auto LEGEND = parseLegend(yaml["legend"], TILESET_COLS);
|
||||||
|
const auto LINES = splitLines(yaml["data"].get_value<std::string>());
|
||||||
|
|
||||||
|
const int ROWS = static_cast<int>(LINES.size());
|
||||||
|
const int COLS = ROWS > 0 ? static_cast<int>(LINES.front().size()) : 0;
|
||||||
|
width_px_ = COLS * TILE_SIZE;
|
||||||
|
height_px_ = ROWS * TILE_SIZE;
|
||||||
|
pixels_.assign(
|
||||||
|
static_cast<std::size_t>(width_px_) * static_cast<std::size_t>(height_px_),
|
||||||
|
0U);
|
||||||
|
|
||||||
|
for (int row = 0; row < ROWS; ++row) {
|
||||||
|
const auto& line = LINES[row];
|
||||||
|
for (int col = 0; col < COLS && col < static_cast<int>(line.size()); ++col) {
|
||||||
|
const char SYMBOL = line[col];
|
||||||
|
const auto IT = LEGEND.find(SYMBOL);
|
||||||
|
if (IT == LEGEND.end()) { continue; }
|
||||||
|
blitTile(*TILESET, TILE_SIZE, IT->second.first, IT->second.second, pixels_, width_px_, col * TILE_SIZE, row * TILE_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Tilemap: " << COLS << "x" << ROWS << " tiles ("
|
||||||
|
<< width_px_ << "x" << height_px_ << " px) des de " << yaml_path << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tilemap::render() const {
|
||||||
|
auto& screen = Screen::get();
|
||||||
|
auto* canvas = screen.getCanvasArgb();
|
||||||
|
const int CANVAS_W = screen.getCanvasWidth();
|
||||||
|
const int CANVAS_H = screen.getCanvasHeight();
|
||||||
|
|
||||||
|
// Clipping de files: només pintem les que cauen dins del canvas.
|
||||||
|
const int Y_START = std::max(0, -origin_y_);
|
||||||
|
const int Y_END = std::min(height_px_, CANVAS_H - origin_y_);
|
||||||
|
const int X_START = std::max(0, -origin_x_);
|
||||||
|
const int X_END = std::min(width_px_, CANVAS_W - origin_x_);
|
||||||
|
|
||||||
|
for (int y = Y_START; y < Y_END; ++y) {
|
||||||
|
const auto* src_row = &pixels_[static_cast<std::size_t>(y) * static_cast<std::size_t>(width_px_)];
|
||||||
|
auto* dst_row =
|
||||||
|
&canvas[(static_cast<std::size_t>(origin_y_ + y) * static_cast<std::size_t>(CANVAS_W)) + static_cast<std::size_t>(origin_x_)];
|
||||||
|
for (int x = X_START; x < X_END; ++x) {
|
||||||
|
const auto PIXEL = src_row[x];
|
||||||
|
if ((PIXEL & 0xFF000000U) != 0U) { dst_row[x] = PIXEL; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Tilemap basat en tiles 16×16 (o la mida que indique el yaml). El mapa es
|
||||||
|
// prerenderitza una sola vegada a un buffer ARGB propi a la construcció; a
|
||||||
|
// partir d'aquí, cada render és una simple còpia de píxels clipada sobre el
|
||||||
|
// canvas del joc. Això evita recórrer la graella de tiles cada frame.
|
||||||
|
//
|
||||||
|
// Les cel·les sense tile (p.ex. les caselles dels sarcòfags, que es faran
|
||||||
|
// actors independents) es deixen transparents (alpha=0) i el canvas
|
||||||
|
// subjacent hi queda visible.
|
||||||
|
class Tilemap {
|
||||||
|
public:
|
||||||
|
// Carrega el yaml (camí relatiu o absolut), el tileset referenciat i
|
||||||
|
// prerenderitza la graella a memòria.
|
||||||
|
explicit Tilemap(const std::string& yaml_path);
|
||||||
|
|
||||||
|
// Dibuixa la textura prerenderitzada al canvas a l'origen del yaml.
|
||||||
|
// Offsets negatius permeten overscan (textura més gran que el canvas).
|
||||||
|
void render() const;
|
||||||
|
|
||||||
|
[[nodiscard]] auto getWidth() const -> int { return width_px_; }
|
||||||
|
[[nodiscard]] auto getHeight() const -> int { return height_px_; }
|
||||||
|
[[nodiscard]] auto getOriginX() const -> int { return origin_x_; }
|
||||||
|
[[nodiscard]] auto getOriginY() const -> int { return origin_y_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int width_px_{0};
|
||||||
|
int height_px_{0};
|
||||||
|
int origin_x_{0};
|
||||||
|
int origin_y_{0};
|
||||||
|
std::vector<std::uint32_t> pixels_;
|
||||||
|
};
|
||||||
@@ -18,7 +18,8 @@
|
|||||||
#include "utils/defaults.hpp"
|
#include "utils/defaults.hpp"
|
||||||
#include "utils/defines.hpp"
|
#include "utils/defines.hpp"
|
||||||
|
|
||||||
GameScene::GameScene() {
|
GameScene::GameScene()
|
||||||
|
: tilemap_("data/maps/pyramid.yaml") {
|
||||||
Resource::Cache::get().loadSurface("player.gif", "data/player/player.gif");
|
Resource::Cache::get().loadSurface("player.gif", "data/player/player.gif");
|
||||||
Resource::Cache::get().loadAnimation("player.yaml", "data/player/player.yaml");
|
Resource::Cache::get().loadAnimation("player.yaml", "data/player/player.yaml");
|
||||||
|
|
||||||
@@ -59,9 +60,11 @@ void GameScene::render() {
|
|||||||
const auto BG_ARGB = Resource::Cache::get().getPalette("ui")[UiColor::CANVAS_BG];
|
const auto BG_ARGB = Resource::Cache::get().getPalette("ui")[UiColor::CANVAS_BG];
|
||||||
Screen::get().fillRect(0, 0, GameCanvas::WIDTH, GameCanvas::HEIGHT, BG_ARGB);
|
Screen::get().fillRect(0, 0, GameCanvas::WIDTH, GameCanvas::HEIGHT, BG_ARGB);
|
||||||
|
|
||||||
// Fons del mapa (marcador, muros, sòl). Els sarcòfags es pinten després
|
// Mapa visual: textura prerenderitzada del tilemap. Els sarcòfags
|
||||||
// fila a fila entrellaçats amb els jugadors per al Z-order.
|
// queden "foradats" (cel·les transparents) perquè passaran a ser
|
||||||
Map::renderBackground();
|
// 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
|
// 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
|
// primer). Usem un vector auxiliar per no tocar l'ordre d'entrada de
|
||||||
@@ -73,24 +76,10 @@ void GameScene::render() {
|
|||||||
return a->getFeetY() < b->getFeetY();
|
return a->getFeetY() < b->getFeetY();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Interleaving: per cada fila de sarcòfags, primer pintem els jugadors
|
// De moment els sarcòfags no es pinten (seran actors independents);
|
||||||
// que hi queden "darrere" (peus per sobre de la cara inferior de la fila)
|
// dibuixem tots els jugadors sobre el tilemap ja ordenats per Y. Quan
|
||||||
// i després la fila. Un jugador amb els peus davall d'una fila es pinta
|
// els sarcs siguen sprites, tornarem a interleave per al Z-order.
|
||||||
// sobre d'ella (el seu cap tapa la fila superior si s'hi encavalca).
|
for (auto* player : sorted) { player->render(); }
|
||||||
std::size_t p = 0;
|
|
||||||
for (int row = 0; row < Map::GRID_ROWS; ++row) {
|
|
||||||
const auto ROW_BOTTOM = static_cast<float>(Map::getSarcRowBottomY(row));
|
|
||||||
while (p < sorted.size() && sorted[p]->getFeetY() <= ROW_BOTTOM) {
|
|
||||||
sorted[p]->render();
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
Map::renderSarcsRow(row);
|
|
||||||
}
|
|
||||||
// Jugadors que queden per davall de l'última fila de sarcòfags.
|
|
||||||
while (p < sorted.size()) {
|
|
||||||
sorted[p]->render();
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
|
|
||||||
Notifier::get().render();
|
Notifier::get().render();
|
||||||
RenderInfo::get().render();
|
RenderInfo::get().render();
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "core/scene/scene.hpp"
|
#include "core/scene/scene.hpp"
|
||||||
|
#include "game/map/tilemap.hpp"
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
|
|
||||||
@@ -16,6 +17,8 @@ class GameScene : public Scene {
|
|||||||
void render() override;
|
void render() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Tilemap tilemap_;
|
||||||
|
|
||||||
// Vector des del principi: AEE suportarà multijugador local; cada Player
|
// Vector des del principi: AEE suportarà multijugador local; cada Player
|
||||||
// té els seus propis Controls i entra al vector amb una crida extra.
|
// té els seus propis Controls i entra al vector amb una crida extra.
|
||||||
std::vector<std::unique_ptr<Player>> players_;
|
std::vector<std::unique_ptr<Player>> players_;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace Texts {
|
namespace Texts {
|
||||||
constexpr const char* WINDOW_TITLE = "© 2026 Aventures en Egipte — JailDesigner";
|
constexpr const char* WINDOW_TITLE = "© 2026 Aventures en Egipte — JailDesigner";
|
||||||
constexpr const char* COPYRIGHT = "© 2026 JailDesigner";
|
constexpr const char* COPYRIGHT = "© 2026 JailDesigner";
|
||||||
constexpr const char* VERSION = "0.12.0"; // Single source of truth — Makefile el grep
|
constexpr const char* VERSION = "0.13.0"; // Single source of truth — Makefile el grep
|
||||||
} // namespace Texts
|
} // namespace Texts
|
||||||
|
|
||||||
namespace GameCanvas {
|
namespace GameCanvas {
|
||||||
|
|||||||
Reference in new issue
Block a user