DUP-02: snapToHorizontalLane/VerticalLane unificats en snapToLane

Les dues funcions compartien l'algorisme complet — només canvien l'eix
actiu (getPosY/setPosY vs getPosX/setPosX) i els paràmetres del Map.
`snapToLane` pren base, pitch, max_idx i dos member-fn pointers i és
cridat pels dos wrappers amb els valors corresponents.
This commit is contained in:
JailDesigner committed 2026-04-20 17:59:05 +02:00
1 parent 53bf3a1ff2
commit 206ba07a6f
3 files changed
+43 -33

No files matched your search

+1 -1
View File
@@ -31,7 +31,7 @@ Els IDs es mantenen estables una vegada assignats. Cada entrada apunta al fitxer
| ID | Fitxer:línia | Troballa | Severitat | Estat | Notes | | ID | Fitxer:línia | Troballa | Severitat | Estat | Notes |
|----|--------------|----------|-----------|-------|-------| |----|--------------|----------|-----------|-------|-------|
| DUP-01 | `options.cpp:152-335,443-547` | PostFX i CrtPi tenen `default*Presets/parse*Preset/write*Preset/load*FromFile/save*ToFile/set*File` duplicats | Importante | DONE | Afegits `loadPresetsFromFile<T>` i `savePresetsToFile<T>` a l'anonymous namespace; els 4 entry-points passen a ser one-liners que injecten parse/write/defaults per tipus. Els fitxers `postfx.yaml`/`crtpi.yaml` regenerats són idèntics a l'anterior. `std::cerr` manté el comportament — INCONS-02 el corregirà | | DUP-01 | `options.cpp:152-335,443-547` | PostFX i CrtPi tenen `default*Presets/parse*Preset/write*Preset/load*FromFile/save*ToFile/set*File` duplicats | Importante | DONE | Afegits `loadPresetsFromFile<T>` i `savePresetsToFile<T>` a l'anonymous namespace; els 4 entry-points passen a ser one-liners que injecten parse/write/defaults per tipus. Els fitxers `postfx.yaml`/`crtpi.yaml` regenerats són idèntics a l'anterior. `std::cerr` manté el comportament — INCONS-02 el corregirà |
| DUP-02 | `player.cpp:100-140` | `snapToHorizontalLane` i `snapToVerticalLane` són el mateix algorisme amb eixos permutats | Importante | PENDING | Unificar en `snapToLane(Axis, delta_time)` | | DUP-02 | `player.cpp:100-140` | `snapToHorizontalLane` i `snapToVerticalLane` són el mateix algorisme amb eixos permutats | Importante | DONE | `snapToLane(dt, base, pitch, max_idx, get_pos, set_pos)` pren member-fn pointers; els dos wrappers deleguen només amb `Map::pitch_*`/`grid_*` distints |
| DUP-03 | `options.cpp:14-62` | Tres parelles `enumToString`/`enumFromString` amb la mateixa forma | Menor | PENDING | Taula `constexpr` + helpers genèrics | | DUP-03 | `options.cpp:14-62` | Tres parelles `enumToString`/`enumFromString` amb la mateixa forma | Menor | PENDING | Taula `constexpr` + helpers genèrics |
| DUP-04 | `options.cpp:79-149` | Cada `parse*` repeteix `if (node.contains) { ... get_value<T> }` | Menor | PENDING | Helper `readField<T>(node, key, dst)` | | DUP-04 | `options.cpp:79-149` | Cada `parse*` repeteix `if (node.contains) { ... get_value<T> }` | Menor | PENDING | Helper `readField<T>(node, key, dst)` |
| DUP-05 | `player.cpp:81-88` | Càlcul `MIN_/MAX_` + `clamp` per eix és la mateixa fórmula que el snap | Menor | PENDING | Fold en helper | | DUP-05 | `player.cpp:81-88` | Càlcul `MIN_/MAX_` + `clamp` per eix és la mateixa fórmula que el snap | Menor | PENDING | Fold en helper |
+33 -31
View File
@@ -126,44 +126,46 @@ auto Player::baseBox() const -> SDL_FRect {
}; };
} }
void Player::snapToHorizontalLane(float delta_time) { void Player::snapToLane(
// Lanes en posY: base + i·pitch_y per a i ∈ [0, grid_rows]. Correspon a float delta_time,
// la caixa de col·lisió ocupant exactament un passadís horitzontal. float base,
const auto BASE = static_cast<float>(Map::playfield_y - collision_y_offset); float pitch,
const auto PITCH = static_cast<float>(Map::pitch_y); int max_idx,
float (Player::*get_pos)() const,
void (Player::*set_pos)(float)) {
// Lanes en pos_axis: base + i·pitch per a i ∈ [0, max_idx]. Correspon a
// la caixa de col·lisió ocupant exactament un passadís perpendicular.
const auto THRESHOLD = static_cast<float>(collision_size) / 2.0F; const auto THRESHOLD = static_cast<float>(collision_size) / 2.0F;
const auto IDX = std::clamp( const auto IDX = std::clamp(
static_cast<int>(std::round((getPosY() - BASE) / PITCH)), static_cast<int>(std::round(((this->*get_pos)() - base) / pitch)),
0, 0,
Map::grid_rows); max_idx);
const float LANE = BASE + (static_cast<float>(IDX) * PITCH); const float LANE = base + (static_cast<float>(IDX) * pitch);
const float DY = LANE - getPosY(); const float DELTA = LANE - (this->*get_pos)();
if (std::abs(DY) > 0.0F && std::abs(DY) <= THRESHOLD) { if (std::abs(DELTA) > 0.0F && std::abs(DELTA) <= THRESHOLD) {
const float STEP = std::min(std::abs(DY), SPEED_PX_PER_S * delta_time); const float STEP = std::min(std::abs(DELTA), SPEED_PX_PER_S * delta_time);
const float SAVED = getPosY(); const float SAVED = (this->*get_pos)();
setPosY(getPosY() + std::copysign(STEP, DY)); (this->*set_pos)(SAVED + std::copysign(STEP, DELTA));
if (Map::collides(baseBox())) { setPosY(SAVED); } if (Map::collides(baseBox())) { (this->*set_pos)(SAVED); }
} }
} }
void Player::snapToHorizontalLane(float delta_time) {
snapToLane(delta_time,
static_cast<float>(Map::playfield_y - collision_y_offset),
static_cast<float>(Map::pitch_y),
Map::grid_rows,
&Player::getPosY,
&Player::setPosY);
}
void Player::snapToVerticalLane(float delta_time) { void Player::snapToVerticalLane(float delta_time) {
const auto BASE = static_cast<float>(Map::playfield_x - collision_x_offset); snapToLane(delta_time,
const auto PITCH = static_cast<float>(Map::pitch_x); static_cast<float>(Map::playfield_x - collision_x_offset),
const auto THRESHOLD = static_cast<float>(collision_size) / 2.0F; static_cast<float>(Map::pitch_x),
Map::grid_cols,
const auto IDX = std::clamp( &Player::getPosX,
static_cast<int>(std::round((getPosX() - BASE) / PITCH)), &Player::setPosX);
0,
Map::grid_cols);
const float LANE = BASE + (static_cast<float>(IDX) * PITCH);
const float DX = LANE - getPosX();
if (std::abs(DX) > 0.0F && std::abs(DX) <= THRESHOLD) {
const float STEP = std::min(std::abs(DX), SPEED_PX_PER_S * delta_time);
const float SAVED = getPosX();
setPosX(getPosX() + std::copysign(STEP, DX));
if (Map::collides(baseBox())) { setPosX(SAVED); }
}
} }
+9 -1
View File
@@ -55,9 +55,17 @@ class Player : public AnimatedSprite {
// Snap cap al passadís perpendicular a la direcció premuda. Si la caixa // Snap cap al passadís perpendicular a la direcció premuda. Si la caixa
// de col·lisió està a ≤ collision_size/2 d'una lane, s'hi aproxima // de col·lisió està a ≤ collision_size/2 d'una lane, s'hi aproxima
// gradualment (a velocitat de moviment). Permet canviar de direcció // gradualment (a velocitat de moviment). Permet canviar de direcció
// sense haver d'alinear-se píxel-perfect en l'encreuament. // sense haver d'alinear-se píxel-perfect en l'encreuament. Els dos
// wrappers deleguen a `snapToLane` només canviant l'eix actiu.
void snapToHorizontalLane(float delta_time); void snapToHorizontalLane(float delta_time);
void snapToVerticalLane(float delta_time); void snapToVerticalLane(float delta_time);
void snapToLane(
float delta_time,
float base,
float pitch,
int max_idx,
float (Player::*get_pos)() const,
void (Player::*set_pos)(float));
Controls controls_; Controls controls_;
}; };