feat: estat DISABLED i spawn aeri al començar la sala — v0.25.0
This commit is contained in:
1 parent
645db217fa
commit
580c13e854
8 files changed
+280
-104
No files matched your search
@@ -328,10 +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; }
|
||||
// EXITED/DISABLED: jugador fora del joc. No xoca amb res ni res
|
||||
// xoca amb ell. També es filtren els altres jugadors fora de joc
|
||||
// al check actor↔actor més avall via el predicat `isOutOfPlay`.
|
||||
if (isOutOfPlay()) { 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:
|
||||
@@ -357,7 +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 (p->isOutOfPlay()) { 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
|
||||
@@ -407,10 +407,11 @@ void Player::integrateAxis(float& phys, float input, float delta_time, float mot
|
||||
// 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; }
|
||||
// EXITED/DISABLED: jugador fora del joc, 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
|
||||
// que GameScene el reactiva (respawn / spawnFromAir).
|
||||
if (isOutOfPlay()) { 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
|
||||
@@ -719,6 +720,9 @@ void Player::resolveLandingOverlap() {
|
||||
if (all_players_ == nullptr) { return; }
|
||||
for (Player* other : *all_players_) {
|
||||
if (other == nullptr || other == this) { continue; }
|
||||
// Salta jugadors fora del joc: un caigut sobre un slot DISABLED
|
||||
// (o sobre un EXITED encara al vector) no els ha de projectar.
|
||||
if (other->isOutOfPlay()) { continue; }
|
||||
// Test amb la hit-box (8×8 de contacte precís), no la base-box.
|
||||
// Coherent amb la resta de col·lisions actor-actor del joc:
|
||||
// momies, fuetades futures, resolver PvP… tots usen hit-box. Un
|
||||
@@ -753,8 +757,8 @@ 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; }
|
||||
// EXITED/DISABLED: cap moviment ni col·lisió. Idèntic al gating de `tick`.
|
||||
if (isOutOfPlay()) { 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
|
||||
@@ -875,9 +879,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; }
|
||||
// EXITED/DISABLED: invisible. La crida al render base es salta
|
||||
// sencera; el jugador no apareix al z-sort tot i seguir vivint al
|
||||
// vector.
|
||||
if (isOutOfPlay()) { return; }
|
||||
|
||||
// Mentre el jugador està enlaire, el sprite es desplaça visualment
|
||||
// cap amunt `jump_z_` píxels. Modifiquem `pos_.y` (la posició entera
|
||||
@@ -1054,6 +1059,54 @@ void Player::respawn(float x, float y) {
|
||||
setPosY(y);
|
||||
}
|
||||
|
||||
void Player::disable() {
|
||||
if (state_ == State::DISABLED) { return; }
|
||||
state_ = State::DISABLED;
|
||||
intended_vx_ = 0.0F;
|
||||
intended_vy_ = 0.0F;
|
||||
input_vx_ = 0.0F;
|
||||
input_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;
|
||||
pending_cardinal_ = Cardinal::NONE;
|
||||
intermediate_cardinal_ = Cardinal::NONE;
|
||||
last_input_cardinal_ = Cardinal::NONE;
|
||||
}
|
||||
|
||||
void Player::spawnFromAir(float x, float y) {
|
||||
// Net total: equival a un `respawn` seguit d'una entrada en l'aire.
|
||||
// Així el flag de gir, l'animació, els flancs del salt i les
|
||||
// velocitats residuals queden a un estat conegut abans de promocionar
|
||||
// a AIRBORNE. Si hi havia un cardinal d'input penjat de la sessió
|
||||
// anterior, no contamina la pròxima caiguda.
|
||||
respawn(x, y);
|
||||
|
||||
// Altura derivada de la geometria: prou per arrencar amb el sprite
|
||||
// sencer per damunt del bord superior del canvas (recordem que
|
||||
// visualment es pinta a `pos_.y - jump_z_`). Afegim un xicotet marge
|
||||
// perquè el primer frame ja siga clarament off-screen, no just al ras.
|
||||
constexpr float OFFSCREEN_MARGIN_PX = 8.0F;
|
||||
const float SPAWN_HEIGHT = y + static_cast<float>(sprite_h) + OFFSCREEN_MARGIN_PX;
|
||||
|
||||
state_ = State::AIRBORNE;
|
||||
jump_z_ = SPAWN_HEIGHT;
|
||||
// Caiguda recta: sense impuls inicial, deixem que la gravetat (la
|
||||
// mateixa que la del salt normal) faça la feina. Velocitat horitzontal
|
||||
// a zero perquè no es desviï del passadís d'spawn.
|
||||
jump_vz_ = 0.0F;
|
||||
intended_vx_ = 0.0F;
|
||||
intended_vy_ = 0.0F;
|
||||
|
||||
// Mirant cap avall durant la caiguda — `animationName(AIRBORNE)` amb
|
||||
// facing DOWN ja resol a `jump_down`. `respawn` ja ha posat facing a
|
||||
// DOWN; ho deixem explícit ací per claredat de la cinemàtica.
|
||||
facing_ = Facing::DOWN;
|
||||
setCurrentAnimation("jump_down");
|
||||
}
|
||||
|
||||
auto Player::getBaseBox() const -> SDL_FRect {
|
||||
return {
|
||||
.x = getPosX() + static_cast<float>(collision_x_offset),
|
||||
@@ -1144,6 +1197,7 @@ auto Player::tryPushSnapBlockers(
|
||||
const SDL_FRect MY_HIT = getHitBox();
|
||||
for (Player* p : *all_players_) {
|
||||
if (p == nullptr || p == this) { continue; }
|
||||
if (p->isOutOfPlay()) { continue; }
|
||||
const SDL_FRect OTHER_HIT = p->getHitBox();
|
||||
if (SDL_HasRectIntersectionFloat(&MY_HIT, &OTHER_HIT)) {
|
||||
blockers.push_back(p);
|
||||
|
||||
Reference in new issue
Block a user