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:
JailDesigner committed 2026-04-28 18:28:19 +02:00
1 parent 121558b1fd
commit 8f66961c7b
15 files changed
+353 -127

No files matched your search

+23 -30
View File
@@ -660,47 +660,36 @@ void Player::enterAttacking(Cardinal facing) {
// p.ex. just després d'un canvi d'input).
applyCardinal(facing);
// Geometria de spawn de la hitbox: alineada al rectangle de
// col·lisió del jugador, no al sprite (que té perspectiva falsa amb
// el cap dalt). La hitbox és `range_px × tile_size` (E/W) o
// `tile_size × range_px` (N/S); el GameScene la consumeix per
// crear el WhipAttack amb la mida adequada per direcció.
const auto BOX = getBaseBox();
const float RANGE_PX = whip_config.range_tiles * static_cast<float>(Map::tile_size);
float spawn_x = 0.0F;
float spawn_y = 0.0F;
if (facing == Cardinal::NONE) { return; }
// Mapa de Cardinal → int al payload (vegeu `WhipSpawnPayload`).
int dir_int = 0;
switch (facing) {
case Cardinal::EAST:
spawn_x = BOX.x + BOX.w;
spawn_y = BOX.y;
dir_int = 3;
break;
case Cardinal::WEST:
spawn_x = BOX.x - RANGE_PX;
spawn_y = BOX.y;
dir_int = 4;
break;
case Cardinal::NORTH:
spawn_x = BOX.x;
spawn_y = BOX.y - RANGE_PX;
dir_int = 1;
break;
case Cardinal::SOUTH:
spawn_x = BOX.x;
spawn_y = BOX.y + BOX.h;
dir_int = 2;
break;
case Cardinal::EAST:
dir_int = 3;
break;
case Cardinal::WEST:
dir_int = 4;
break;
case Cardinal::NONE:
return;
}
// Passem el pixel_rect (16×32 a sam/morcus) al payload; el WhipAttack
// en deriva tant la draw_rect (sprite del látigo, més gran) com la
// damage_rect (al nivell dels peus, retallada per bloquejadors).
if (bus_ != nullptr) {
const float RANGE_PX = whip_config.range_tiles * static_cast<float>(Map::tile_size);
bus_->publish("whip_spawn", WhipSpawnPayload{
.owner = this,
.direction = dir_int,
.spawn_x = spawn_x,
.spawn_y = spawn_y,
.owner_box = getPosition(),
.range_px = RANGE_PX,
});
}
@@ -1141,8 +1130,12 @@ auto Player::animationName(bool moving) const -> const char* {
}
// ATTACKING té dues sub-fases: durant `swing_ms` el sprite és
// `attack_*` (animació del braç llançant el látigo); durant
// `cooldown_ms` posterior tornem al `stand_*` de la direcció. Fem
// la decisió comparant el remaining_ms_ amb el cooldown configurat.
// `cooldown_ms` posterior canviem a `recover_*` per a frames
// pròpis de recuperació. Mentre l'art no estiga dibuixat, els
// YAMLs apunten `recover_*` als mateixos frames que `stand_*` —
// visualment és idèntic, però la separació deixa l'arquitectura
// preparada perquè en afegir frames reals només calga tocar el
// YAML, no el codi.
if (state_ == State::ATTACKING) {
const bool IN_SWING = (attacking_remaining_ms_ > static_cast<float>(whip_config.cooldown_ms));
if (IN_SWING) {
@@ -1158,13 +1151,13 @@ auto Player::animationName(bool moving) const -> const char* {
}
switch (facing_) {
case Facing::UP:
return "stand_up";
return "recover_up";
case Facing::DOWN:
return "stand_down";
return "recover_down";
case Facing::SIDE:
break;
}
return "stand";
return "recover";
}
switch (facing_) {
case Facing::UP: