feat(whip): separa draw_rect i damage_rect; sprites 80×32 / 16×96; feet_y delegat a l'owner; recover_* per al cooldown
This commit is contained in:
1 parent
121558b1fd
commit
8f66961c7b
15 files changed
+353
-127
No files matched your search
@@ -89,18 +89,81 @@ WhipAttack::WhipAttack(const fkyaml::node& yaml) {
|
||||
anim_ = anim_swing_;
|
||||
}
|
||||
|
||||
void WhipAttack::configure(Direction dir, float spawn_x, float spawn_y, float range_px) {
|
||||
void WhipAttack::configure(Direction dir, const SDL_FRect& owner_box, float range_px) {
|
||||
direction_ = dir;
|
||||
range_px_ = range_px;
|
||||
|
||||
// Draw rect (= pixel_rect_): cobreix tot el sprite del látigo segons
|
||||
// la taula d'offsets del disseny:
|
||||
// E: (player.x - 16, player.y ), 80×32
|
||||
// W: (player.x - 48, player.y ), 80×32
|
||||
// N: (player.x, player.y - 48 ), 16×96
|
||||
// S: (player.x, player.y - 16 ), 16×96
|
||||
const auto& chosen = spriteFor(dir);
|
||||
setPixelRect({.x = spawn_x, .y = spawn_y, .w = chosen.frame_w, .h = chosen.frame_h});
|
||||
SDL_FRect draw{0.0F, 0.0F, chosen.frame_w, chosen.frame_h};
|
||||
switch (dir) {
|
||||
case Direction::EAST:
|
||||
draw.x = owner_box.x - 16.0F;
|
||||
draw.y = owner_box.y;
|
||||
break;
|
||||
case Direction::WEST:
|
||||
draw.x = owner_box.x - 48.0F;
|
||||
draw.y = owner_box.y;
|
||||
break;
|
||||
case Direction::NORTH:
|
||||
draw.x = owner_box.x;
|
||||
draw.y = owner_box.y - 48.0F;
|
||||
break;
|
||||
case Direction::SOUTH:
|
||||
draw.x = owner_box.x;
|
||||
draw.y = owner_box.y - 16.0F;
|
||||
break;
|
||||
}
|
||||
setPixelRect(draw);
|
||||
|
||||
// Damage rect: 48×16 (E/W) o 16×48 (N/S) al nivell dels peus del
|
||||
// jugador (els últims 16 px del seu pixel_rect — convenció estàndard
|
||||
// del player AEE), pegat al borde en la direcció d'atac.
|
||||
// computeDamageRect rep la cantonada del rect MÀXIM (sense retallar)
|
||||
// i recorre internament la línia per topar amb el primer bloquejador.
|
||||
const float COLLISION_TOP_Y = owner_box.y + owner_box.h - 16.0F;
|
||||
const float OWNER_RIGHT = owner_box.x + owner_box.w;
|
||||
const float OWNER_BOTTOM = owner_box.y + owner_box.h;
|
||||
float spawn_x = 0.0F;
|
||||
float spawn_y = 0.0F;
|
||||
switch (dir) {
|
||||
case Direction::EAST:
|
||||
spawn_x = OWNER_RIGHT;
|
||||
spawn_y = COLLISION_TOP_Y;
|
||||
break;
|
||||
case Direction::WEST:
|
||||
spawn_x = owner_box.x - range_px;
|
||||
spawn_y = COLLISION_TOP_Y;
|
||||
break;
|
||||
case Direction::NORTH:
|
||||
spawn_x = owner_box.x;
|
||||
spawn_y = COLLISION_TOP_Y - range_px;
|
||||
break;
|
||||
case Direction::SOUTH:
|
||||
spawn_x = owner_box.x;
|
||||
spawn_y = OWNER_BOTTOM;
|
||||
break;
|
||||
}
|
||||
computeDamageRect(dir, spawn_x, spawn_y, range_px);
|
||||
|
||||
// Snapshot del feet_y del jugador. La convenció estàndard del Player
|
||||
// AEE té el seu feet_y a la base inferior del pixel_rect (collision
|
||||
// 16×16 als últims 16 px del sprite 16×32), així que owner_box.y +
|
||||
// owner_box.h reprodueix `Player::getFeetY()` exactament.
|
||||
owner_feet_y_ = owner_box.y + owner_box.h;
|
||||
|
||||
if (anim_.has_value()) { anim_->reset(); }
|
||||
}
|
||||
|
||||
auto WhipAttack::getFeetY() const -> float {
|
||||
return owner_feet_y_;
|
||||
}
|
||||
|
||||
void WhipAttack::setWorldContext(EntityManager* manager, const std::vector<Player*>* players) {
|
||||
entity_manager_ = manager;
|
||||
players_ = players;
|
||||
|
||||
@@ -18,16 +18,27 @@ class Player;
|
||||
// Atac de látigo: spawnejat pel jugador en entrar a `ATTACKING`. Viu la
|
||||
// durada de la seua animació (`swing`) i s'autoelimina al final.
|
||||
//
|
||||
// Sprites: 4 fitxers GIF distints, un per cardinal. La mida del frame
|
||||
// canvia entre direccions (E/W: 48×16, N/S: 16×48), cosa que el sistema
|
||||
// d'animació actual no permet expressar amb una sola surface (una entitat
|
||||
// = una graella). Per això el YAML llista les 4 entrades sota `sprites:`
|
||||
// Sprites: 4 fitxers GIF distints, un per cardinal (sense flips). La
|
||||
// mida del frame canvia entre direccions (E/W: 80×32, N/S: 16×96),
|
||||
// cosa que el sistema d'animació actual no permet expressar amb una
|
||||
// sola surface. Per això el YAML llista les 4 entrades sota `sprites:`
|
||||
// i `configure()` tria la que toca segons direcció.
|
||||
//
|
||||
// Hitbox de dany: el rectangle de dany és el `pixel_rect_` retallat al
|
||||
// primer bloquejador en la línia d'atac (mur extern del playfield o
|
||||
// sarcòfag). Aquesta lògica viu a la fase de damage application; en
|
||||
// aquest skeleton només viu la part visual i de cicle de vida.
|
||||
// Dos rectangles distints, intencionadament diferenciats:
|
||||
// - `pixel_rect_` (heretat d'`Entity`) = `draw_rect`. Cobreix tot el
|
||||
// sprite del látigo: 16 px de wind-up darrere del jugador, 16 px
|
||||
// de solapament amb el jugador, i 48 px d'atac frontal (per E/W;
|
||||
// proporcions equivalents per N/S amb 32 px de solapament). NO es
|
||||
// retalla per bloquejadors — només render visual.
|
||||
// - `damage_rect_` = caixa de dany al nivell dels peus del jugador
|
||||
// (centrada sobre la base 16×16). 48×16 (E/W) o 16×48 (N/S),
|
||||
// pegada al borde del jugador en la direcció d'atac. SÍ es retalla
|
||||
// pel primer bloquejador (mur extern del playfield o sarcòfag).
|
||||
//
|
||||
// Z-order: `getFeetY()` delega al `owner_` per garantir que el látigo
|
||||
// quede al mateix bucket d'y-sort que el jugador que l'ha llançat. Si
|
||||
// no, l'altura física del sprite (esp. en N/S, que té 96 px) crearia
|
||||
// solapaments raros amb mòmies a la trajectòria.
|
||||
class WhipAttack : public Attack {
|
||||
public:
|
||||
// Direcció cardinal del swing. Coincideix valors amb
|
||||
@@ -53,12 +64,16 @@ class WhipAttack : public Attack {
|
||||
explicit WhipAttack(const fkyaml::node& yaml);
|
||||
|
||||
// Configura l'estat runtime de la instància. Cal cridar-lo abans del
|
||||
// primer `update`. Selecciona la surface i la mida del pixel_rect_
|
||||
// segons direcció, i posa la cantonada superior-esquerra de la
|
||||
// hitbox a (spawn_x, spawn_y). També calcula la `damage_rect_`
|
||||
// retallada contra murs i sarcs (mai sortiria del playfield ni
|
||||
// travessaria un sarc).
|
||||
void configure(Direction dir, float spawn_x, float spawn_y, float range_px);
|
||||
// primer `update`. A partir del `owner_box` (pixel_rect del jugador,
|
||||
// típicament 16×32) i la direcció d'atac, deriva:
|
||||
// - `pixel_rect_` (= draw_rect): cantonada i mida del sprite del
|
||||
// látigo segons la taula d'offsets (E: -16, 0, 80×32; etc.).
|
||||
// - `damage_rect_`: caixa de dany 48×16 (o 16×48) pegada al
|
||||
// borde del jugador, retallada contra murs i sarcs.
|
||||
// Convenció implícita: el jugador té collision rect 16×16 als
|
||||
// últims 16 px del seu pixel_rect (els "peus"); aquesta funció
|
||||
// n'usa la geometria per al damage_rect i el feet_y delegat.
|
||||
void configure(Direction dir, const SDL_FRect& owner_box, float range_px);
|
||||
|
||||
// Injecta el context que necessita la fase de dany: punter a
|
||||
// l'`EntityManager` (per iterar Hazards) i a la llista de jugadors
|
||||
@@ -90,6 +105,14 @@ class WhipAttack : public Attack {
|
||||
// consumeix la pròpia `applyDamage`.
|
||||
[[nodiscard]] auto getDamageRect() const -> SDL_FRect { return damage_rect_; }
|
||||
|
||||
// Y dels peus delegada al `owner_box` capturat a `configure()`: el
|
||||
// látigo es z-ordena al mateix bucket que el jugador que l'ha
|
||||
// llançat (= base inferior del seu pixel_rect, que coincideix amb
|
||||
// el feet_y del jugador a la convenció estàndard del player AEE).
|
||||
// Snapshot, no consulta dinàmica: el jugador queda quiet durant
|
||||
// ATTACKING, així que snapshot ≡ live per a la vida del whip.
|
||||
[[nodiscard]] auto getFeetY() const -> float override;
|
||||
|
||||
// Clau al `Resource::Cache` per a la surface de la direcció actual
|
||||
// (la que ha triat `configure()`). El caller (típicament `GameScene`)
|
||||
// resol la surface i la passa via `setSurface()`. Aquesta separació
|
||||
@@ -123,6 +146,12 @@ class WhipAttack : public Attack {
|
||||
float range_px_{0.0F};
|
||||
SDL_FRect damage_rect_{0.0F, 0.0F, 0.0F, 0.0F};
|
||||
|
||||
// Snapshot del feet_y de l'owner pres a `configure()` (= base
|
||||
// inferior del seu pixel_rect, que coincideix amb el `getFeetY()`
|
||||
// del Player en la convenció estàndard d'AEE). El retornem des
|
||||
// del nostre `getFeetY()` per delegar el bucket d'y-sort al jugador.
|
||||
float owner_feet_y_{0.0F};
|
||||
|
||||
EntityManager* entity_manager_{nullptr};
|
||||
const std::vector<Player*>* players_{nullptr};
|
||||
|
||||
|
||||
Reference in new issue
Block a user