feat(player): saltar travessa el caminant; rebot mid-aire entre dos saltadors
This commit is contained in:
1 parent
3646e6a4aa
commit
188f035333
4 files changed
+78
-32
No files matched your search
@@ -103,22 +103,22 @@ namespace {
|
||||
auto* b = ps[1];
|
||||
if (a == nullptr || b == nullptr) { return; }
|
||||
|
||||
// Filtre per altura: si un dels dos està en l'aire per damunt
|
||||
// del cos de l'altre, no hi ha contacte possible — el saltador
|
||||
// sobrevola. Saltar fa de "moviment lliure" per al resolver.
|
||||
// `body_height` és estàtic carregat des del YAML; cppcheck el llig
|
||||
// com a sempre-zero perquè no veu la inicialització en runtime.
|
||||
const auto BODY_H = static_cast<float>(Player::body_height);
|
||||
// cppcheck-suppress knownConditionTrueFalse
|
||||
if (BODY_H > 0.0F && a->isAirborne() && a->getJumpZ() > BODY_H) { return; }
|
||||
// cppcheck-suppress knownConditionTrueFalse
|
||||
if (BODY_H > 0.0F && b->isAirborne() && b->getJumpZ() > BODY_H) { return; }
|
||||
const bool A_AIR = a->isAirborne();
|
||||
const bool B_AIR = b->isAirborne();
|
||||
|
||||
// Aire ↔ tierra: el saltador es travessa net del caminant. Sense
|
||||
// resolver, sense head-on, sense push. Els dos continuen amb la
|
||||
// velocitat que portaven. Important: això NO és el filtre per
|
||||
// altura del cos — és binari. Coincideix amb la regla d'`Player::
|
||||
// collidesWithWorld`: durant un salt no hi ha mai col·lisió amb
|
||||
// un caminant, ni baix ni alt.
|
||||
if (A_AIR != B_AIR) { return; }
|
||||
|
||||
// Calculem l'overlap previst en l'espai de la hit-box petita:
|
||||
// els jugadors han de poder acostar-se molt (caixes de moviment
|
||||
// 16×16 quasi tocant) sense disparar el resolver; només quan el
|
||||
// contacte real (hit-box 8×8) s'activaria, neutralitzem o apliquem
|
||||
// push.
|
||||
// push (a terra) o invertim velocitats (en l'aire).
|
||||
const SDL_FRect BOX_A = a->getHitBox();
|
||||
const SDL_FRect BOX_B = b->getHitBox();
|
||||
const SDL_FRect NEXT_A{
|
||||
@@ -135,6 +135,32 @@ namespace {
|
||||
};
|
||||
if (!rectsOverlap(NEXT_A, NEXT_B)) { return; }
|
||||
|
||||
// Tots dos en l'aire (A_AIR == B_AIR == true aquí, ja descartat
|
||||
// l'altre cas a dalt): rebot mid-aire si els rangs verticals
|
||||
// [z, z+body_height] solapen. Si la diferència d'alçades és
|
||||
// massa gran, ja no hi ha contacte real (un està molt més amunt
|
||||
// que l'altre) i no fem res. Si solapen, invertim ambdues
|
||||
// velocitats horitzontals i els deixem rebotar fins a aterrar
|
||||
// — els dos cauen en stun, com a càstig per abusar del salt.
|
||||
if (A_AIR) {
|
||||
// cppcheck-suppress knownConditionTrueFalse
|
||||
const auto BODY_H = static_cast<float>(Player::body_height);
|
||||
// cppcheck-suppress knownConditionTrueFalse
|
||||
if (BODY_H <= 0.0F) { return; }
|
||||
if (std::fabs(a->getJumpZ() - b->getJumpZ()) >= BODY_H) { return; }
|
||||
// Saltadors estàtics horitzontalment (cas degenerat: tots dos
|
||||
// jumpejant verticals al mateix x): no hi ha velocitat a
|
||||
// invertir, deixem-los — el predictiu no tornarà a disparar
|
||||
// perquè en el següent frame ja no hi haurà velocitat
|
||||
// d'acostament.
|
||||
const float REL_VX = a->getIntendedVX() - b->getIntendedVX();
|
||||
const float REL_VY = a->getIntendedVY() - b->getIntendedVY();
|
||||
if (REL_VX == 0.0F && REL_VY == 0.0F) { return; }
|
||||
a->setIntendedVelocity(-a->getIntendedVX(), -a->getIntendedVY());
|
||||
b->setIntendedVelocity(-b->getIntendedVX(), -b->getIntendedVY());
|
||||
return;
|
||||
}
|
||||
|
||||
const bool MOVING_A = (a->getInputVX() != 0.0F) || (a->getInputVY() != 0.0F);
|
||||
const bool MOVING_B = (b->getInputVX() != 0.0F) || (b->getInputVY() != 0.0F);
|
||||
|
||||
|
||||
Reference in new issue
Block a user