feat(player): inèrcia de frenada amb acumulador de moviment
This commit is contained in:
1 parent
291cbdc957
commit
ea0f6d98a9
5 files changed
+153
-7
No files matched your search
@@ -84,6 +84,8 @@ class Player : public AnimatedSprite {
|
||||
// GameScene els toca entre `tick` i `applyMovement` per implementar
|
||||
// col·lisions jugador↔jugador (escalar a push_factor, anul·lar en
|
||||
// head-on). Expressades en píxels/segon, no en píxels/frame.
|
||||
// Amb inèrcia activada, `intended_v*` pot ser no-zero encara que
|
||||
// l'usuari no estiga prement res (coast residual).
|
||||
[[nodiscard]] auto getIntendedVX() const -> float { return intended_vx_; }
|
||||
[[nodiscard]] auto getIntendedVY() const -> float { return intended_vy_; }
|
||||
void setIntendedVelocity(float vx, float vy) {
|
||||
@@ -91,6 +93,15 @@ class Player : public AnimatedSprite {
|
||||
intended_vy_ = vy;
|
||||
}
|
||||
|
||||
// Velocitat crua d'input d'aquest frame (-SPEED, 0 o +SPEED per eix).
|
||||
// A diferència de `intended_v*`, no té en compte la inèrcia: un jugador
|
||||
// que coasta sense prémer res té `input_v* == 0`. El resolver PvP del
|
||||
// GameScene l'usa per decidir "parat vs en moviment" (criteri: un
|
||||
// coast sense input compta com parat — l'empenta i el head-on només
|
||||
// es disparen quan hi ha intenció explícita del jugador).
|
||||
[[nodiscard]] auto getInputVX() const -> float { return input_vx_; }
|
||||
[[nodiscard]] auto getInputVY() const -> float { return input_vy_; }
|
||||
|
||||
// Llista de tots els jugadors del nivell (incloent-se ell mateix —
|
||||
// la callback ignora `this`). La caixa del jugador es considera un
|
||||
// sòlid a la callback de col·lisió: així `tryMove` no permet que un
|
||||
@@ -186,9 +197,26 @@ class Player : public AnimatedSprite {
|
||||
// Velocitat intencionada calculada a `tick` i aplicada a
|
||||
// `applyMovement`. El GameScene pot sobreescriure-la entremig per
|
||||
// resoldre interaccions jugador↔jugador (empentes, head-on).
|
||||
// També actua com a estat físic persistent entre frames: amb inèrcia
|
||||
// activada, si l'usuari solta l'input, aquí queda la velocitat
|
||||
// residual que `tick` anirà decaient linealment cap a 0.
|
||||
float intended_vx_{0.0F};
|
||||
float intended_vy_{0.0F};
|
||||
|
||||
// Velocitat desitjada per input aquest frame (teclat + gamepad). Cada
|
||||
// eix és -SPEED, 0 o +SPEED. És la "intenció del jugador"; la física
|
||||
// resultant viu a `intended_v*` i pot diferir (coast sense input).
|
||||
float input_vx_{0.0F};
|
||||
float input_vy_{0.0F};
|
||||
|
||||
// Acumulador de temps en moviment continu. Creix cada frame amb
|
||||
// `|input_v*| > 0` o `|intended_v*| > 0`, i es reseteja a 0 només
|
||||
// quan NO hi ha ni input ni velocitat residual. Activa la inèrcia
|
||||
// quan passa el llindar configurat al YAML (`threshold_ms`); no es
|
||||
// buida mai enmig d'un coast, ni tan sols en canvis de direcció,
|
||||
// així un toc curt en sentit oposat no "frena en sec" un coast llarg.
|
||||
float motion_time_ms_{0.0F};
|
||||
|
||||
// Punter a la llista de tots els jugadors del nivell (propietat del
|
||||
// GameScene). `nullptr` = jugador aïllat, sense col·lisió inter-P.
|
||||
const std::vector<Player*>* all_players_{nullptr};
|
||||
@@ -223,6 +251,24 @@ class Player : public AnimatedSprite {
|
||||
EAST,
|
||||
WEST };
|
||||
|
||||
// Configuració d'inèrcia llegida del bloc `inertia:` del YAML. Amb
|
||||
// `brake_time_ms == 0` (o bloc absent) la inèrcia està desactivada i
|
||||
// el comportament és instantani: soltar input para el jugador en sec.
|
||||
struct InertiaConfig {
|
||||
int brake_time_ms{0}; // Temps en ms perquè la velocitat caiga de ±SPEED a 0.
|
||||
int threshold_ms{0}; // Temps mínim en moviment continu per activar la inèrcia.
|
||||
};
|
||||
static InertiaConfig inertia_config;
|
||||
|
||||
// Integra un eix. Si hi ha input en aquest eix, la velocitat física
|
||||
// salta a aquest valor (acceleració instantània). Si no, i hi ha
|
||||
// input en l'altre eix (`any_input == true`), la velocitat d'aquest
|
||||
// eix es posa a 0 en sec: el jugador està fent un gir de 90°, no
|
||||
// soltant l'input — no volem que arrossegue en diagonal. Només quan
|
||||
// l'usuari deixa anar tot l'input (`any_input == false`) s'activa la
|
||||
// inèrcia de frenada (si `motion_time_ms` ha passat el llindar).
|
||||
static void integrateAxis(float& phys, float input, float delta_time, float motion_time_ms, bool any_input);
|
||||
|
||||
// Configuració del gir de 180°, llegida del bloc `turn:` del YAML del
|
||||
// player. Si `duration_ms` és 0 (o el bloc no existeix) la mecànica
|
||||
// queda desactivada i els canvis de direcció són instantanis.
|
||||
|
||||
Reference in new issue
Block a user