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

+33 -31
View File
@@ -126,44 +126,46 @@ auto Player::baseBox() const -> SDL_FRect {
};
}
void Player::snapToHorizontalLane(float delta_time) {
// Lanes en posY: base + i·pitch_y per a i ∈ [0, grid_rows]. Correspon a
// la caixa de col·lisió ocupant exactament un passadís horitzontal.
const auto BASE = static_cast<float>(Map::playfield_y - collision_y_offset);
const auto PITCH = static_cast<float>(Map::pitch_y);
void Player::snapToLane(
float delta_time,
float base,
float pitch,
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 IDX = std::clamp(
static_cast<int>(std::round((getPosY() - BASE) / PITCH)),
static_cast<int>(std::round(((this->*get_pos)() - base) / pitch)),
0,
Map::grid_rows);
const float LANE = BASE + (static_cast<float>(IDX) * PITCH);
const float DY = LANE - getPosY();
max_idx);
const float LANE = base + (static_cast<float>(IDX) * pitch);
const float DELTA = LANE - (this->*get_pos)();
if (std::abs(DY) > 0.0F && std::abs(DY) <= THRESHOLD) {
const float STEP = std::min(std::abs(DY), SPEED_PX_PER_S * delta_time);
const float SAVED = getPosY();
setPosY(getPosY() + std::copysign(STEP, DY));
if (Map::collides(baseBox())) { setPosY(SAVED); }
if (std::abs(DELTA) > 0.0F && std::abs(DELTA) <= THRESHOLD) {
const float STEP = std::min(std::abs(DELTA), SPEED_PX_PER_S * delta_time);
const float SAVED = (this->*get_pos)();
(this->*set_pos)(SAVED + std::copysign(STEP, DELTA));
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) {
const auto BASE = static_cast<float>(Map::playfield_x - collision_x_offset);
const auto PITCH = static_cast<float>(Map::pitch_x);
const auto THRESHOLD = static_cast<float>(collision_size) / 2.0F;
const auto IDX = std::clamp(
static_cast<int>(std::round((getPosX() - BASE) / PITCH)),
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); }
}
snapToLane(delta_time,
static_cast<float>(Map::playfield_x - collision_x_offset),
static_cast<float>(Map::pitch_x),
Map::grid_cols,
&Player::getPosX,
&Player::setPosX);
}
+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
// de col·lisió està a ≤ collision_size/2 d'una lane, s'hi aproxima
// 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 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_;
};