feat(player): estat EXITED i porta oberta despawna jugadors via player_exited

This commit is contained in:
JailDesigner committed 2026-04-26 10:20:13 +02:00
1 parent 377e5d0b97
commit 5c5cd1d5da
5 files changed
+93 -22

No files matched your search

+33
View File
@@ -328,6 +328,10 @@ void Player::update(float delta_time) {
}
auto Player::collidesWithWorld(const SDL_FRect& box) const -> bool {
// EXITED: jugador despawnat. No xoca amb res ni res xoca amb ell.
// També salta jugadors EXITED del check actor↔actor més avall via
// el filtre de `isExited` (vegeu el predicat any_of).
if (state_ == State::EXITED) { return false; }
if (map_.collides(box)) { return true; }
if (all_players_ == nullptr) { return false; }
// Per al contacte actor-actor usem la hit-box petita a banda i banda:
@@ -353,6 +357,7 @@ auto Player::collidesWithWorld(const SDL_FRect& box) const -> bool {
const float MY_Z = jump_z_;
return std::ranges::any_of(*all_players_, [this, &PROPOSED_HIT, MY_AIR, MY_HURT, MY_Z](const Player* p) {
if (p == nullptr || p == this) { return false; }
if (p->isExited()) { return false; }
if (MY_HURT || p->isHurt()) { return false; }
if (MY_AIR != p->isAirborne()) { return false; }
// Aquí els dos estats coincideixen. Si tots dos volen, el filtre
@@ -398,7 +403,15 @@ void Player::integrateAxis(float& phys, float input, float delta_time, float mot
}
}
// Pipeline d'estats i input separats; extracció a helpers empitjoraria la
// llegibilitat. La complexitat puja 1 per la guarda EXITED.
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void Player::tick(float delta_time) {
// EXITED: jugador despawnat, no fa res. Cap input, cap física, cap
// bus event. Continua sent al vector de jugadors per simplicitat
// (no s'esborra) però queda completament inert fins al respawn.
if (state_ == State::EXITED) { return; }
// Reset per frame: el resolver del GameScene el tornarà a posar a
// true si aquest frame hi ha push actiu. Així quan el push acaba
// (un deixa d'empentar, l'altre comença a caminar), l'animació torna
@@ -740,6 +753,9 @@ void Player::resolveLandingOverlap() {
}
void Player::applyMovement(float delta_time) {
// EXITED: cap moviment ni col·lisió. Idèntic al gating de `tick`.
if (state_ == State::EXITED) { return; }
// 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
@@ -859,6 +875,10 @@ void Player::publishTileEnteredIfChanged() {
}
void Player::render() {
// EXITED: invisible. La crida al render base es salta sencera; el
// jugador no apareix al z-sort tot i seguir vivint al vector.
if (state_ == State::EXITED) { return; }
// Mentre el jugador està enlaire, el sprite es desplaça visualment
// cap amunt `jump_z_` píxels. Modifiquem `pos_.y` (la posició entera
// de render) abans de cridar el render base, i la restaurem després
@@ -1010,6 +1030,19 @@ void Player::clampToPlayfield() {
setPosY(std::clamp(getPosY(), min_y, MAX_Y));
}
void Player::respawn(float x, float y) {
state_ = State::GROUNDED;
intended_vx_ = 0.0F;
intended_vy_ = 0.0F;
being_pushed_ = false;
jump_z_ = 0.0F;
jump_vz_ = 0.0F;
landing_stun_remaining_ms_ = 0.0F;
turning_remaining_ms_ = 0.0F;
setPosX(x);
setPosY(y);
}
auto Player::getBaseBox() const -> SDL_FRect {
return {
.x = getPosX() + static_cast<float>(collision_x_offset),