refactor(player): divideix update en tick+applyMovement i exposa velocitat intencionada
This commit is contained in:
1 parent
820b9f2d21
commit
1cc2e28b1b
2 files changed
+88
-23
No files matched your search
@@ -241,6 +241,21 @@ Player::Player(const std::string& anim_key, int id, float x, float y, const Cont
|
||||
}
|
||||
|
||||
void Player::update(float delta_time) {
|
||||
tick(delta_time);
|
||||
applyMovement(delta_time);
|
||||
}
|
||||
|
||||
auto Player::collidesWithWorld(const SDL_FRect& box) const -> bool {
|
||||
if (map_.collides(box)) { return true; }
|
||||
if (all_players_ == nullptr) { return false; }
|
||||
return std::ranges::any_of(*all_players_, [this, &box](const Player* p) {
|
||||
if (p == nullptr || p == this) { return false; }
|
||||
const auto OTHER = p->getBaseBox();
|
||||
return SDL_HasRectIntersectionFloat(&box, &OTHER);
|
||||
});
|
||||
}
|
||||
|
||||
void Player::tick(float delta_time) {
|
||||
// Via `InputState` en lloc de `SDL_GetKeyboardState` directe: quan el
|
||||
// service menu (o qualsevol UI modal) està obert, el wrapper retorna
|
||||
// un buffer tot-a-zero perquè el jugador no es mogui mentre l'usuari
|
||||
@@ -253,31 +268,32 @@ void Player::update(float delta_time) {
|
||||
if (keys[controls_.up]) { vy -= SPEED_PX_PER_S; }
|
||||
if (keys[controls_.down]) { vy += SPEED_PX_PER_S; }
|
||||
|
||||
// Cruceta i stick esquerre del primer gamepad (si n'hi ha). També
|
||||
// Cruceta i stick esquerre del mando assignat (si n'hi ha). També
|
||||
// respecten el bloqueig d'`InputState`, així que amb el menú obert
|
||||
// els botons tornen false/0 i no contribueixen a la velocitat.
|
||||
// Direccions oposades (teclat left + d-pad right) es cancel·len de
|
||||
// forma natural; premuda simultània en la mateixa direcció no duplica
|
||||
// la velocitat perquè cada branca només resta/suma una vegada.
|
||||
accumulateGamepadMovement(id_, vx, vy);
|
||||
|
||||
intended_vx_ = vx;
|
||||
intended_vy_ = vy;
|
||||
setVelX(vx);
|
||||
setVelY(vy);
|
||||
|
||||
updateFacingAndTurn(delta_time, vx, vy);
|
||||
}
|
||||
|
||||
void Player::applyMovement(float delta_time) {
|
||||
// El resolver del GameScene pot haver escalat `intended_vx_/vy_`
|
||||
// (cas push: velocitat * push_factor) o haver-les anul·lat (cas
|
||||
// head-on). Consumim-les aquí com a velocitat definitiva del frame.
|
||||
const float VX = intended_vx_;
|
||||
const float VY = intended_vy_;
|
||||
|
||||
// Snap al passadís: si només hi ha moviment horitzontal (o vertical) i
|
||||
// la caixa està prou prop d'una lane perpendicular (≤ mitja caixa), la
|
||||
// Y (o X) es corregeix gradualment per enfilar el passadís. Amb
|
||||
// moviment diagonal no es fa snap — l'usuari pilota manualment.
|
||||
const bool ONLY_H = (vx != 0.0F) && (vy == 0.0F);
|
||||
const bool ONLY_V = (vy != 0.0F) && (vx == 0.0F);
|
||||
// Y (o X) es corregeix gradualment per enfilar el passadís.
|
||||
const bool ONLY_H = (VX != 0.0F) && (VY == 0.0F);
|
||||
const bool ONLY_V = (VY != 0.0F) && (VX == 0.0F);
|
||||
|
||||
// Pos d'inici de frame (abans de snap i integració): si en acabar el
|
||||
// frame coincideix amb la posició final, el jugador no s'ha mogut
|
||||
// realment (ni per input, ni per snap, ni ha superat la col·lisió) i cal
|
||||
// forçar l'animació `stand` corresponent al facing — així s'atura el
|
||||
// caminat quan xoca contra un mur o un sarcòfag.
|
||||
const float FRAME_START_X = getPosX();
|
||||
const float FRAME_START_Y = getPosY();
|
||||
|
||||
@@ -288,20 +304,19 @@ void Player::update(float delta_time) {
|
||||
}
|
||||
|
||||
// Animació del frame + moviment col·lisió-aware. `tryMove` aplica els
|
||||
// deltes per eix i reverteix l'eix que col·lisiona, així el jugador
|
||||
// llisca contra sarcòfags i murs en compte de quedar-se bloquejat en
|
||||
// sec. La caixa que s'envia al callback és `collisionBox()` (override
|
||||
// a Player retornant `getBaseBox()`), no el sprite sencer.
|
||||
// deltes per eix i reverteix l'eix que col·lisiona; així el jugador
|
||||
// llisca contra sarcòfags, murs i altres jugadors en compte de quedar
|
||||
// bloquejat en sec. La callback tracta els altres jugadors com a
|
||||
// sòlids per evitar overlaps (el resolver del GameScene deixa les
|
||||
// velocitats "segures", i aquesta comprovació és la xarxa de
|
||||
// seguretat davant de casos d'ordre d'aplicació).
|
||||
animate(delta_time);
|
||||
tryMove(vx * delta_time, vy * delta_time, [this](const SDL_FRect& box) { return map_.collides(box); });
|
||||
tryMove(VX * delta_time, VY * delta_time, [this](const SDL_FRect& box) {
|
||||
return collidesWithWorld(box);
|
||||
});
|
||||
|
||||
clampToPlayfield();
|
||||
|
||||
// Animació basada en moviment real: si la col·lisió (o l'absència
|
||||
// d'input) ha deixat el jugador al mateix lloc que al principi del
|
||||
// frame, queda en `stand` del facing actual. Durant un gir de 180°
|
||||
// forcem també `stand` encara que el jugador s'estiga movent — la
|
||||
// pose intermèdia és sempre estàtica per disseny.
|
||||
const bool MOVED = (getPosX() != FRAME_START_X) || (getPosY() != FRAME_START_Y);
|
||||
const bool ANIM_AS_MOVING = MOVED && (turning_remaining_ms_ <= 0.0F);
|
||||
setCurrentAnimation(animationName(ANIM_AS_MOVING));
|
||||
|
||||
Reference in new issue
Block a user