feat(entities): caja-peus concèntrica i animacions direccionals a la momia, còpia de data/ sempre sincronitzada; v0.19.0
This commit is contained in:
1 parent
a3592d6c73
commit
32dcf264c4
9 files changed
+251
-58
No files matched your search
@@ -51,7 +51,7 @@ void EntityManager::renderEntity(const Entity& e) {
|
||||
.w = RECT.w,
|
||||
.h = RECT.h,
|
||||
};
|
||||
surface->render(static_cast<int>(RECT.x), static_cast<int>(RECT.y), &SRC);
|
||||
surface->render(static_cast<int>(RECT.x), static_cast<int>(RECT.y), &SRC, e.getFlip());
|
||||
}
|
||||
|
||||
void EntityManager::renderAll() {
|
||||
@@ -105,9 +105,16 @@ namespace {
|
||||
return info;
|
||||
}
|
||||
|
||||
// Bloc `collision: { size: [w, h], offset: [x, y] }` de la plantilla
|
||||
// d'entitat. `offset` és opcional: si no apareix, s'entén "la caixa
|
||||
// queda bottom-center del sprite" (convenció de falsa perspectiva).
|
||||
// Bloc `collision: { size: [w, h], base_size: [bw, bh]?, offset: [x, y]? }`
|
||||
// de la plantilla d'entitat.
|
||||
// - Sense `base_size` ni `offset`: la caja queda alineada a la vora
|
||||
// inferior del sprite i centrada horitzontalment (convenció antiga).
|
||||
// - Amb `base_size: [bw, bh]`: la caja queda concèntrica amb el
|
||||
// rectangle inferior bw×bh del sprite (els "peus" visuals), igual
|
||||
// que fa el Player. Pot sobresortir per sobre/sota/costats del
|
||||
// rectangle-base simètricament — així la caja representa el volum
|
||||
// sòlid al voltant dels peus, no la silueta de tot el sprite.
|
||||
// - `offset: [x, y]`: si apareix, sobreescriu el càlcul anterior.
|
||||
// Retorna nullopt si no hi ha bloc, i l'entitat es queda sense caixa
|
||||
// explícita (getCollisionRect torna tot el sprite).
|
||||
auto readCollisionBox(const fkyaml::node& tmpl, float sprite_w, float sprite_h) -> std::optional<Entity::CollisionBox> {
|
||||
@@ -120,6 +127,16 @@ namespace {
|
||||
const int H = sz[1].get_value<int>();
|
||||
int off_x = static_cast<int>((sprite_w - static_cast<float>(W)) / 2.0F);
|
||||
int off_y = static_cast<int>(sprite_h - static_cast<float>(H));
|
||||
if (c.contains("base_size")) {
|
||||
const auto& bs = c["base_size"];
|
||||
if (bs.is_sequence() && bs.size() == 2) {
|
||||
const int BH = bs[1].get_value<int>();
|
||||
// Centre vertical del rectangle-base (alineat a la vora
|
||||
// inferior del sprite): sprite_h − bh/2. Caja centrada hi:
|
||||
// off_y = sprite_h − bh/2 − H/2 = sprite_h − (bh + H)/2.
|
||||
off_y = static_cast<int>(sprite_h) - ((BH + H) / 2);
|
||||
}
|
||||
}
|
||||
if (c.contains("offset")) {
|
||||
const auto& o = c["offset"];
|
||||
if (o.is_sequence() && o.size() == 2) {
|
||||
@@ -258,16 +275,26 @@ namespace {
|
||||
const auto& p = spawn["position"];
|
||||
const auto PX = tileToPixel(p[0].get_value<int>(), p[1].get_value<int>());
|
||||
|
||||
// Anchor "feet": el tile [col,row] és el tile dels peus. El sprite
|
||||
// es centra horitzontalment sobre el tile i la seua vora inferior
|
||||
// s'alinea amb la vora inferior del tile. Els píxels que sobresurten
|
||||
// (alçada del sprite per damunt del tile dels peus) queden "per
|
||||
// sobre" sense afectar cap col·lisió — falsa perspectiva.
|
||||
// Anchor "feet": el tile [col,row] és el tile dels peus de l'actor.
|
||||
// Si l'entitat té caixa de col·lisió explícita, la caixa s'alinea
|
||||
// exactament amb el tile (el sprite queda col·locat per als offsets
|
||||
// que la caja defineix — típicament sobresurt cap amunt per falsa
|
||||
// perspectiva). Això és coherent amb el jugador, que també centra
|
||||
// la seua 16×16 sobre el rectangle-base; la caja del tile i la del
|
||||
// mapeig són la mateixa. Sense caixa, fallback històric: sprite
|
||||
// centrat horitzontalment i amb la vora inferior a la vora inferior
|
||||
// del tile.
|
||||
float rect_x = PX.x;
|
||||
float rect_y = PX.y;
|
||||
if (anchor == "feet") {
|
||||
rect_x = PX.x + (static_cast<float>(Map::tile_size) - sprite.width) / 2.0F;
|
||||
rect_y = PX.y + static_cast<float>(Map::tile_size) - sprite.height;
|
||||
const auto& box_opt = entity->getCollisionBox();
|
||||
if (box_opt.has_value()) {
|
||||
rect_x = PX.x - static_cast<float>(box_opt->offset_x);
|
||||
rect_y = PX.y - static_cast<float>(box_opt->offset_y);
|
||||
} else {
|
||||
rect_x = PX.x + (static_cast<float>(Map::tile_size) - sprite.width) / 2.0F;
|
||||
rect_y = PX.y + static_cast<float>(Map::tile_size) - sprite.height;
|
||||
}
|
||||
}
|
||||
entity->setPixelRect({.x = rect_x, .y = rect_y, .w = sprite.width, .h = sprite.height});
|
||||
|
||||
|
||||
Reference in new issue
Block a user