feat(player): resol el solapament en aterrar damunt d'un altre jugador

This commit is contained in:
JailDesigner committed 2026-04-25 11:55:04 +02:00
1 parent a64f33fe43
commit c4caa9021e
2 files changed
+82 -2

No files matched your search

+71 -2
View File
@@ -502,12 +502,81 @@ auto Player::integrateJump(float delta_time) -> bool {
return false;
}
void Player::resolveLandingOverlap() {
if (all_players_ == nullptr) { return; }
for (Player* other : *all_players_) {
if (other == nullptr || other == this) { continue; }
const SDL_FRect MY_HIT = getHitBox();
const SDL_FRect OT_HIT = other->getHitBox();
SDL_FRect inter;
if (!SDL_GetRectIntersectionFloat(&MY_HIT, &OT_HIT, &inter)) { continue; }
// Eix de separació: el que té els centres més separats. És
// l'axis-aligned MTV "natural" — equivalent a empentar l'altre
// cap a fora seguint la direcció centre→centre, projectada al
// costat dominant. Coincideix amb la intuïció: si el saltador
// li cau una mica per sobre i a la dreta, l'altre va cap a la
// dreta-baix; si li cau directament al damunt (dx≈0), l'altre
// s'aparta verticalment.
const float MCX = MY_HIT.x + (MY_HIT.w * 0.5F);
const float MCY = MY_HIT.y + (MY_HIT.h * 0.5F);
const float OCX = OT_HIT.x + (OT_HIT.w * 0.5F);
const float OCY = OT_HIT.y + (OT_HIT.h * 0.5F);
const float DX = OCX - MCX;
const float DY = OCY - MCY;
float push_x = 0.0F;
float push_y = 0.0F;
if (std::fabs(DX) >= std::fabs(DY)) {
push_x = (DX >= 0.0F ? 1.0F : -1.0F) * inter.w;
} else {
push_y = (DY >= 0.0F ? 1.0F : -1.0F) * inter.h;
}
// 1r intent: empentar l'altre. Si la nova posició no col·lisiona
// amb res (mur, sarc, tercer jugador), commit i marquem-lo com
// a empentat per coherència de l'animació de l'altre frame.
const float OSX = other->getPosX();
const float OSY = other->getPosY();
other->setPosX(OSX + push_x);
other->setPosY(OSY + push_y);
if (!other->collidesWithWorld(other->getBaseBox())) {
other->setBeingPushed(true);
continue;
}
// L'altre xocaria amb un mur: revertim i provem d'apartar el
// saltador cap al sentit oposat. Així respectem la regla "mai
// ficar ningú dins d'un mur": si no hi ha camí per a l'altre,
// qui es desplaça és el qui ha triat saltar.
other->setPosX(OSX);
other->setPosY(OSY);
const float MSX = getPosX();
const float MSY = getPosY();
setPosX(MSX - push_x);
setPosY(MSY - push_y);
if (!collidesWithWorld(getBaseBox())) {
continue;
}
// Cap dels dos pot apartar-se sense xocar amb un mur. Cas
// degenerat (jugador encaixonat entre obstacles); el deixem com
// estava i acceptem el solapament residual fins al pròxim frame
// amb input.
setPosX(MSX);
setPosY(MSY);
}
}
void Player::applyMovement(float delta_time) {
// Integració del salt: si estem AIRBORNE, avança jump_z_/jump_vz_.
// El facing i intended_v* es mantenen del moment del despegue (no es
// recalculen). Si toquem el sòl aquest frame, transicionem a
// LANDING_STUN ja al final d'`integrateJump`.
integrateJump(delta_time);
// LANDING_STUN i resolem el possible solapament amb un altre
// jugador que estigués sota — apartem-lo (o, si no es pot, ens
// apartem nosaltres).
if (integrateJump(delta_time)) {
resolveLandingOverlap();
}
// En LANDING_STUN no movem el jugador horitzontalment (la velocitat
// ja s'ha posat a 0 al `tick`). Encara així animem (per estar al