neteja NOLINT obsolets (audio 14 + player + ajusta justificacions)
This commit is contained in:
1 parent
822bed0748
commit
7a859c1e44
7 files changed
+175
-160
No files matched your search
@@ -90,7 +90,6 @@ void Audio::playMusicInternal(Ja::Music* music, const int loop, const int crossf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pausa la música (l'estat el transiciona Engine::pauseMusic)
|
// Pausa la música (l'estat el transiciona Engine::pauseMusic)
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const) — muta estat via engine_; unique_ptr::operator-> no propaga const
|
|
||||||
void Audio::pauseMusic() {
|
void Audio::pauseMusic() {
|
||||||
if (music_enabled_ && getMusicState() == MusicState::PLAYING) {
|
if (music_enabled_ && getMusicState() == MusicState::PLAYING) {
|
||||||
engine_->pauseMusic();
|
engine_->pauseMusic();
|
||||||
@@ -98,7 +97,6 @@ void Audio::pauseMusic() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Continua la música pausada (l'estat el transiciona Engine::resumeMusic)
|
// Continua la música pausada (l'estat el transiciona Engine::resumeMusic)
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const) — muta estat via engine_; unique_ptr::operator-> no propaga const
|
|
||||||
void Audio::resumeMusic() {
|
void Audio::resumeMusic() {
|
||||||
if (music_enabled_ && getMusicState() == MusicState::PAUSED) {
|
if (music_enabled_ && getMusicState() == MusicState::PAUSED) {
|
||||||
engine_->resumeMusic();
|
engine_->resumeMusic();
|
||||||
@@ -106,14 +104,12 @@ void Audio::resumeMusic() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Atura la música (l'estat el transiciona Engine::stopMusic)
|
// Atura la música (l'estat el transiciona Engine::stopMusic)
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const) — muta estat via engine_; unique_ptr::operator-> no propaga const
|
|
||||||
void Audio::stopMusic() {
|
void Audio::stopMusic() {
|
||||||
if (music_enabled_) {
|
if (music_enabled_) {
|
||||||
engine_->stopMusic();
|
engine_->stopMusic();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
|
||||||
void Audio::setMusicSpeed(float ratio) {
|
void Audio::setMusicSpeed(float ratio) {
|
||||||
if (music_enabled_) {
|
if (music_enabled_) {
|
||||||
engine_->setMusicSpeed(ratio);
|
engine_->setMusicSpeed(ratio);
|
||||||
@@ -121,7 +117,6 @@ void Audio::setMusicSpeed(float ratio) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reprodueix un so per nom
|
// Reprodueix un so per nom
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const) — muta estat via engine_; unique_ptr::operator-> no propaga const
|
|
||||||
void Audio::playSound(const std::string& name, Group group) {
|
void Audio::playSound(const std::string& name, Group group) {
|
||||||
if (sound_enabled_) {
|
if (sound_enabled_) {
|
||||||
engine_->playSound(AudioResource::getSound(name), 0, static_cast<int>(group));
|
engine_->playSound(AudioResource::getSound(name), 0, static_cast<int>(group));
|
||||||
@@ -129,7 +124,6 @@ void Audio::playSound(const std::string& name, Group group) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reprodueix un so per punter directe
|
// Reprodueix un so per punter directe
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const) — muta estat via engine_; unique_ptr::operator-> no propaga const
|
|
||||||
void Audio::playSound(Ja::Sound* sound, Group group) {
|
void Audio::playSound(Ja::Sound* sound, Group group) {
|
||||||
if (sound_enabled_ && sound != nullptr) {
|
if (sound_enabled_ && sound != nullptr) {
|
||||||
engine_->playSound(sound, 0, static_cast<int>(group));
|
engine_->playSound(sound, 0, static_cast<int>(group));
|
||||||
@@ -141,7 +135,6 @@ void Audio::playSound(Ja::Sound* sound, Group group) {
|
|||||||
// processa tot el sample amb el ratio des del primer pull del callback.
|
// processa tot el sample amb el ratio des del primer pull del callback.
|
||||||
// Si l'engine torna -1 (sense canal lliure) o el so no existeix, no fem
|
// Si l'engine torna -1 (sense canal lliure) o el so no existeix, no fem
|
||||||
// la crida al ratio — sense efectes col·laterals.
|
// la crida al ratio — sense efectes col·laterals.
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const)
|
|
||||||
void Audio::playSound(const std::string& name, Group group, float speed) {
|
void Audio::playSound(const std::string& name, Group group, float speed) {
|
||||||
if (!sound_enabled_) { return; }
|
if (!sound_enabled_) { return; }
|
||||||
auto* sound = AudioResource::getSound(name);
|
auto* sound = AudioResource::getSound(name);
|
||||||
@@ -155,7 +148,6 @@ void Audio::playSound(const std::string& name, Group group, float speed) {
|
|||||||
// Reprodueix un so processat per un eco definit a sounds.yaml. Si el preset no
|
// Reprodueix un so processat per un eco definit a sounds.yaml. Si el preset no
|
||||||
// existeix o l'engine retorna -1 (cap de canals d'efecte plé), cau a playSound
|
// existeix o l'engine retorna -1 (cap de canals d'efecte plé), cau a playSound
|
||||||
// sec — l'usuari sent el so encara que la cua no s'apliqui.
|
// sec — l'usuari sent el so encara que la cua no s'apliqui.
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const) — muta estat via engine_
|
|
||||||
void Audio::playSoundWithEcho(const std::string& name, const std::string& preset_name, Group group) {
|
void Audio::playSoundWithEcho(const std::string& name, const std::string& preset_name, Group group) {
|
||||||
if (!sound_enabled_) { return; }
|
if (!sound_enabled_) { return; }
|
||||||
auto* sound = AudioResource::getSound(name);
|
auto* sound = AudioResource::getSound(name);
|
||||||
@@ -175,7 +167,6 @@ void Audio::playSoundWithEcho(const std::string& name, const std::string& preset
|
|||||||
|
|
||||||
// Reprodueix un so processat per un reverb definit a sounds.yaml. Mateix
|
// Reprodueix un so processat per un reverb definit a sounds.yaml. Mateix
|
||||||
// fallback que playSoundWithEcho.
|
// fallback que playSoundWithEcho.
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const) — muta estat via engine_
|
|
||||||
void Audio::playSoundWithReverb(const std::string& name, const std::string& preset_name, Group group) {
|
void Audio::playSoundWithReverb(const std::string& name, const std::string& preset_name, Group group) {
|
||||||
if (!sound_enabled_) { return; }
|
if (!sound_enabled_) { return; }
|
||||||
auto* sound = AudioResource::getSound(name);
|
auto* sound = AudioResource::getSound(name);
|
||||||
@@ -194,7 +185,6 @@ void Audio::playSoundWithReverb(const std::string& name, const std::string& pres
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Atura tots els sons
|
// Atura tots els sons
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const) — muta estat via engine_; unique_ptr::operator-> no propaga const
|
|
||||||
void Audio::stopAllSounds() {
|
void Audio::stopAllSounds() {
|
||||||
if (sound_enabled_) {
|
if (sound_enabled_) {
|
||||||
engine_->stopChannel(-1);
|
engine_->stopChannel(-1);
|
||||||
@@ -202,7 +192,6 @@ void Audio::stopAllSounds() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fa una fosa de sortida de la música
|
// Fa una fosa de sortida de la música
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const) — muta estat via engine_; unique_ptr::operator-> no propaga const
|
|
||||||
void Audio::fadeOutMusic(int milliseconds) {
|
void Audio::fadeOutMusic(int milliseconds) {
|
||||||
if (music_enabled_ && getMusicState() == MusicState::PLAYING) {
|
if (music_enabled_ && getMusicState() == MusicState::PLAYING) {
|
||||||
engine_->fadeOutMusic(milliseconds);
|
engine_->fadeOutMusic(milliseconds);
|
||||||
@@ -212,7 +201,6 @@ void Audio::fadeOutMusic(int milliseconds) {
|
|||||||
// Registra un callback que el motor dispararà quan la pista actual acabi de
|
// Registra un callback que el motor dispararà quan la pista actual acabi de
|
||||||
// drenar (times == 0 + stream buit). S'executa al mateix thread que
|
// drenar (times == 0 + stream buit). S'executa al mateix thread que
|
||||||
// Audio::update (render loop); els consumidors no poden fer I/O blocant.
|
// Audio::update (render loop); els consumidors no poden fer I/O blocant.
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const) — muta estat via engine_
|
|
||||||
void Audio::setOnMusicEnded(std::function<void()> callback) {
|
void Audio::setOnMusicEnded(std::function<void()> callback) {
|
||||||
if (engine_) { engine_->setOnMusicEnded(std::move(callback)); }
|
if (engine_) { engine_->setOnMusicEnded(std::move(callback)); }
|
||||||
}
|
}
|
||||||
@@ -251,13 +239,11 @@ auto Audio::effectiveVolume(float volume, bool channel_enabled) const -> float {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Estableix el volum dels sons (float 0.0..1.0)
|
// Estableix el volum dels sons (float 0.0..1.0)
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const) — muta estat via engine_; unique_ptr::operator-> no propaga const
|
|
||||||
void Audio::setSoundVolume(float sound_volume, Group group) {
|
void Audio::setSoundVolume(float sound_volume, Group group) {
|
||||||
engine_->setSoundVolume(effectiveVolume(sound_volume, sound_enabled_), static_cast<int>(group));
|
engine_->setSoundVolume(effectiveVolume(sound_volume, sound_enabled_), static_cast<int>(group));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estableix el volum de la música (float 0.0..1.0)
|
// Estableix el volum de la música (float 0.0..1.0)
|
||||||
// NOLINTNEXTLINE(readability-make-member-function-const) — muta estat via engine_; unique_ptr::operator-> no propaga const
|
|
||||||
void Audio::setMusicVolume(float music_volume) {
|
void Audio::setMusicVolume(float music_volume) {
|
||||||
engine_->setMusicVolume(effectiveVolume(music_volume, music_enabled_));
|
engine_->setMusicVolume(effectiveVolume(music_volume, music_enabled_));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
// (TU aïllat perquè clang-analyzer no dispari fals positius al nostre codi).
|
// (TU aïllat perquè clang-analyzer no dispari fals positius al nostre codi).
|
||||||
#define STB_VORBIS_HEADER_ONLY
|
#define STB_VORBIS_HEADER_ONLY
|
||||||
// clang-format off
|
// clang-format off
|
||||||
// NOLINTNEXTLINE(bugprone-suspicious-include)
|
// NOLINTNEXTLINE(bugprone-suspicious-include) -- stb_vorbis és single-file: la macro de dalt limita aquest TU a només-declaracions; la implementació viu a external/stb_vorbis_impl.cpp.
|
||||||
#include "external/stb_vorbis.c"
|
#include "external/stb_vorbis.c"
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace Screenshot {
|
|||||||
// Estat de mòdul: ruta base on s'escriu la subcarpeta
|
// Estat de mòdul: ruta base on s'escriu la subcarpeta
|
||||||
// `screenshots/`. Buida per defecte ⇒ relativa al CWD (fallback
|
// `screenshots/`. Buida per defecte ⇒ relativa al CWD (fallback
|
||||||
// si el Director no ha pogut establir la ruta per plataforma).
|
// si el Director no ha pogut establir la ruta per plataforma).
|
||||||
std::string g_base_dir; // NOLINT(*-avoid-non-const-global-variables)
|
std::string g_base_dir; // NOLINT(*-avoid-non-const-global-variables) -- estat de mòdul (singleton-like): s'estableix una vegada al startup via setBaseDir() i es llegeix N vegades; encapsulat dins del namespace anònim, no és accessible des de fora.
|
||||||
|
|
||||||
// Construeix la ruta del directori on van les captures:
|
// Construeix la ruta del directori on van les captures:
|
||||||
// `<base>/screenshots/`. Si la base és buida, retorna
|
// `<base>/screenshots/`. Si la base és buida, retorna
|
||||||
|
|||||||
@@ -345,9 +345,7 @@ namespace {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// cppcheck-suppress constParameterReference
|
// cppcheck-suppress constParameterReference -- Tilemap& mutable per simetria amb `toggle()` i per futures invalidacions de caches d'edició; cppcheck no pot anticipar que les futures mutacions estan previstes en el contracte.
|
||||||
// Tilemap& mutable per simetria amb `toggle()` i per futures
|
|
||||||
// invalidacions de caches d'edició, encara que `save()` sigui const.
|
|
||||||
void Editor::exit(Tilemap& tilemap, const EntityManager& entities) {
|
void Editor::exit(Tilemap& tilemap, const EntityManager& entities) {
|
||||||
if (!active_) { return; }
|
if (!active_) { return; }
|
||||||
// Constraint del nivell: cal exactament una porta i com a mínim un
|
// Constraint del nivell: cal exactament una porta i com a mínim un
|
||||||
|
|||||||
@@ -53,18 +53,19 @@ class EntityFactory {
|
|||||||
// IMPORTANT: perquè el registrador es cridi, el `.cpp` que el conté ha
|
// IMPORTANT: perquè el registrador es cridi, el `.cpp` que el conté ha
|
||||||
// d'estar enllaçat directament a l'executable (no dins una STATIC lib
|
// d'estar enllaçat directament a l'executable (no dins una STATIC lib
|
||||||
// sense `--whole-archive`). Tots els `concrete/*.cpp` entren a APP_SOURCES.
|
// sense `--whole-archive`). Tots els `concrete/*.cpp` entren a APP_SOURCES.
|
||||||
#define REGISTER_ENTITY_AS(NAME, CLASS, TAG) \
|
#define REGISTER_ENTITY_AS(NAME, CLASS, TAG) \
|
||||||
namespace { \
|
namespace { \
|
||||||
struct TAG##_Registrar { \
|
struct TAG##_Registrar { \
|
||||||
TAG##_Registrar() { \
|
TAG##_Registrar() { \
|
||||||
EntityFactory::instance().registerCreator( \
|
EntityFactory::instance().registerCreator( \
|
||||||
NAME, \
|
NAME, \
|
||||||
[](const fkyaml::node& yaml) -> std::unique_ptr<Entity> { \
|
[](const fkyaml::node& yaml) -> std::unique_ptr<Entity> { \
|
||||||
return std::make_unique<CLASS>(yaml); \
|
return std::make_unique<CLASS>(yaml); \
|
||||||
}); \
|
}); \
|
||||||
} \
|
} \
|
||||||
}; \
|
}; \
|
||||||
const TAG##_Registrar g_##TAG##_registrar; /* NOLINT(cert-err58-cpp) */ \
|
/* NOLINTNEXTLINE(cert-err58-cpp) -- inicialització estàtica intencionada: el constructor registra el creator a l'EntityFactory abans de main(); el patró és l'únic mecanisme C++ que permet auto-registre per tipus sense modificar la factory. */ \
|
||||||
|
const TAG##_Registrar g_##TAG##_registrar; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define REGISTER_ENTITY(NAME, CLASS) REGISTER_ENTITY_AS(NAME, CLASS, CLASS)
|
#define REGISTER_ENTITY(NAME, CLASS) REGISTER_ENTITY_AS(NAME, CLASS, CLASS)
|
||||||
+150
-129
@@ -513,143 +513,115 @@ void Player::integrateAxis(float& phys, float input, float delta_time, float mot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pipeline d'estats i input separats; extracció a helpers empitjoraria la
|
// DYING: animació `death_spinning` + pausa de respawn. Ignorem tot
|
||||||
// llegibilitat. La complexitat puja 1 per la guarda EXITED.
|
// l'input (ni moviment, ni salt, ni atac). El moviment queda
|
||||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
// congelat al lloc de la mort; `applyMovement` avança l'animació i
|
||||||
void Player::tick(float delta_time) {
|
// detecta la fi per disparar el respawn. Mantenim els flancs de
|
||||||
// EXITED/DISABLED: jugador fora del joc, no fa res. Cap input, cap
|
// botó actualitzats perquè una tecla sostinguda no es comporte com
|
||||||
// física, cap bus event. Continua sent al vector de jugadors per
|
// a flanc nou en sortir del cicle.
|
||||||
// simplicitat (no s'esborra) però queda completament inert fins
|
void Player::tickDying() {
|
||||||
// que GameScene el reactiva (respawn / spawnFromAir).
|
(void)consumeJumpEdge();
|
||||||
if (isOutOfPlay()) { return; }
|
(void)consumeAttackEdge();
|
||||||
|
input_vx_ = 0.0F;
|
||||||
|
input_vy_ = 0.0F;
|
||||||
|
intended_vx_ = 0.0F;
|
||||||
|
intended_vy_ = 0.0F;
|
||||||
|
motion_time_ms_ = 0.0F;
|
||||||
|
setVelX(0.0F);
|
||||||
|
setVelY(0.0F);
|
||||||
|
}
|
||||||
|
|
||||||
// Decrement del timer d'immunitat. Independent de l'estat: si el
|
// En LANDING_STUN, descomptem el timer i ignorem qualsevol input
|
||||||
// jugador mor durant la immunitat (només via forat, que no es gateja),
|
// (moviment i salt). Quan s'esgota, tornem a GROUNDED al pròxim
|
||||||
// el `respawn` rearma una nova finestra. Si la finestra acaba mentre
|
// frame. La velocitat queda a zero — després del stun hi tornarà
|
||||||
// és AIRBORNE/HURT, no passa res — el gate dels hazards passa a
|
// a haver intenció si el jugador prem alguna tecla.
|
||||||
// quedar obert al primer frame post-zero.
|
void Player::tickLandingStun(float delta_time) {
|
||||||
if (immunity_remaining_ms_ > 0.0F) {
|
landing_stun_remaining_ms_ -= delta_time * 1000.0F;
|
||||||
immunity_remaining_ms_ -= delta_time * 1000.0F;
|
if (landing_stun_remaining_ms_ <= 0.0F) {
|
||||||
immunity_remaining_ms_ = std::max(immunity_remaining_ms_, 0.0F);
|
landing_stun_remaining_ms_ = 0.0F;
|
||||||
|
state_ = State::GROUNDED;
|
||||||
}
|
}
|
||||||
|
input_vx_ = 0.0F;
|
||||||
|
input_vy_ = 0.0F;
|
||||||
|
intended_vx_ = 0.0F;
|
||||||
|
intended_vy_ = 0.0F;
|
||||||
|
motion_time_ms_ = 0.0F;
|
||||||
|
setVelX(0.0F);
|
||||||
|
setVelY(0.0F);
|
||||||
|
// Mantenim els flancs del botó de salt actualitzats fins i tot
|
||||||
|
// durant el stun: així si l'usuari l'ha estat prement abans, no
|
||||||
|
// se'l consumeix com a salt nou en sortir del stun.
|
||||||
|
(void)consumeJumpEdge();
|
||||||
|
(void)consumeAttackEdge();
|
||||||
|
}
|
||||||
|
|
||||||
// DYING: animació `death_spinning` + pausa de respawn. Ignorem tot
|
// En AIRBORNE el jugador no llig input direccional: la velocitat
|
||||||
// l'input (ni moviment, ni salt, ni atac). El moviment queda
|
// horitzontal queda fixada al moment del despegue. Tampoc canvia
|
||||||
// congelat al lloc de la mort; `applyMovement` avança l'animació i
|
// facing. Sí actualitzem els flancs del botó perquè la propera
|
||||||
// detecta la fi per disparar el respawn. Mantenim els flancs de
|
// pulsació quan torne a terra es detecte com a flanc nou.
|
||||||
// botó actualitzats perquè una tecla sostinguda no es comporte com
|
void Player::tickAirborne() {
|
||||||
// a flanc nou en sortir del cicle.
|
(void)consumeJumpEdge();
|
||||||
if (state_ == State::DYING) {
|
(void)consumeAttackEdge();
|
||||||
(void)consumeJumpEdge();
|
setVelX(intended_vx_);
|
||||||
(void)consumeAttackEdge();
|
setVelY(intended_vy_);
|
||||||
input_vx_ = 0.0F;
|
}
|
||||||
input_vy_ = 0.0F;
|
|
||||||
intended_vx_ = 0.0F;
|
// En ATTACKING el jugador queda bloquejat tot el `swing_ms +
|
||||||
intended_vy_ = 0.0F;
|
// cooldown_ms`: ni input direccional, ni salt, ni atac, ni canvi
|
||||||
motion_time_ms_ = 0.0F;
|
// de facing. El timer descompta amb `delta_time * 1000` per
|
||||||
setVelX(0.0F);
|
// mantenir la convenció de delta_ms de la resta d'estats temporals.
|
||||||
setVelY(0.0F);
|
// Mantenim els flancs dels botons actualitzats perquè una
|
||||||
return;
|
// tecla mantinguda no es comporte com a flanc nou en sortir.
|
||||||
|
void Player::tickAttacking(float delta_time) {
|
||||||
|
(void)consumeJumpEdge();
|
||||||
|
(void)consumeAttackEdge();
|
||||||
|
attacking_remaining_ms_ -= delta_time * 1000.0F;
|
||||||
|
if (attacking_remaining_ms_ <= 0.0F) {
|
||||||
|
attacking_remaining_ms_ = 0.0F;
|
||||||
|
state_ = State::GROUNDED;
|
||||||
}
|
}
|
||||||
|
input_vx_ = 0.0F;
|
||||||
|
input_vy_ = 0.0F;
|
||||||
|
intended_vx_ = 0.0F;
|
||||||
|
intended_vy_ = 0.0F;
|
||||||
|
motion_time_ms_ = 0.0F;
|
||||||
|
setVelX(0.0F);
|
||||||
|
setVelY(0.0F);
|
||||||
|
}
|
||||||
|
|
||||||
// Reset per frame: el resolver del GameScene el tornarà a posar a
|
// En HURT el jugador està projectat sense control: descomptem
|
||||||
// true si aquest frame hi ha push actiu. Així quan el push acaba
|
// velocitat per inèrcia (decaiment lineal fins a 0). Quan arriba a
|
||||||
// (un deixa d'empentar, l'altre comença a caminar), l'animació torna
|
// zero, tornem a GROUNDED i el frame següent ja torna a llegir input.
|
||||||
// a governar-se per la velocitat real sense estat romanent.
|
// El moviment real l'aplica `applyMovement` (igual que els altres
|
||||||
being_pushed_ = false;
|
// estats), que també gestiona el xoc contra murs.
|
||||||
|
void Player::tickHurt(float delta_time) {
|
||||||
// En LANDING_STUN, descomptem el timer i ignorem qualsevol input
|
(void)consumeJumpEdge();
|
||||||
// (moviment i salt). Quan s'esgota, tornem a GROUNDED al pròxim
|
(void)consumeAttackEdge();
|
||||||
// frame. La velocitat queda a zero — després del stun hi tornarà
|
const float DECEL = (cfg_.hurt.brake_time_ms > 0)
|
||||||
// a haver intenció si el jugador prem alguna tecla.
|
? cfg_.hurt.initial_speed_px_per_s / (static_cast<float>(cfg_.hurt.brake_time_ms) / 1000.0F)
|
||||||
if (state_ == State::LANDING_STUN) {
|
: 0.0F;
|
||||||
landing_stun_remaining_ms_ -= delta_time * 1000.0F;
|
const float STEP = DECEL * delta_time;
|
||||||
if (landing_stun_remaining_ms_ <= 0.0F) {
|
auto decay = [STEP](float& v) {
|
||||||
landing_stun_remaining_ms_ = 0.0F;
|
if (std::fabs(v) <= STEP) {
|
||||||
state_ = State::GROUNDED;
|
v = 0.0F;
|
||||||
|
} else {
|
||||||
|
v -= std::copysign(STEP, v);
|
||||||
}
|
}
|
||||||
input_vx_ = 0.0F;
|
};
|
||||||
input_vy_ = 0.0F;
|
decay(intended_vx_);
|
||||||
intended_vx_ = 0.0F;
|
decay(intended_vy_);
|
||||||
intended_vy_ = 0.0F;
|
if (intended_vx_ == 0.0F && intended_vy_ == 0.0F) {
|
||||||
motion_time_ms_ = 0.0F;
|
state_ = State::GROUNDED;
|
||||||
setVelX(0.0F);
|
|
||||||
setVelY(0.0F);
|
|
||||||
// Mantenim els flancs del botó de salt actualitzats fins i tot
|
|
||||||
// durant el stun: així si l'usuari l'ha estat prement abans, no
|
|
||||||
// se'l consumeix com a salt nou en sortir del stun.
|
|
||||||
(void)consumeJumpEdge();
|
|
||||||
(void)consumeAttackEdge();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// En AIRBORNE el jugador no llig input direccional: la velocitat
|
|
||||||
// horitzontal queda fixada al moment del despegue. Tampoc canvia
|
|
||||||
// facing. Sí actualitzem els flancs del botó perquè la propera
|
|
||||||
// pulsació quan torne a terra es detecte com a flanc nou.
|
|
||||||
if (state_ == State::AIRBORNE) {
|
|
||||||
(void)consumeJumpEdge();
|
|
||||||
(void)consumeAttackEdge();
|
|
||||||
setVelX(intended_vx_);
|
|
||||||
setVelY(intended_vy_);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// En ATTACKING el jugador queda bloquejat tot el `swing_ms +
|
|
||||||
// cooldown_ms`: ni input direccional, ni salt, ni atac, ni canvi
|
|
||||||
// de facing. El timer descompta amb `delta_time * 1000` per
|
|
||||||
// mantenir la convenció de delta_ms de la resta d'estats temporals.
|
|
||||||
// Mantenim els flancs dels botons actualitzats perquè una
|
|
||||||
// tecla mantinguda no es comporte com a flanc nou en sortir.
|
|
||||||
if (state_ == State::ATTACKING) {
|
|
||||||
(void)consumeJumpEdge();
|
|
||||||
(void)consumeAttackEdge();
|
|
||||||
attacking_remaining_ms_ -= delta_time * 1000.0F;
|
|
||||||
if (attacking_remaining_ms_ <= 0.0F) {
|
|
||||||
attacking_remaining_ms_ = 0.0F;
|
|
||||||
state_ = State::GROUNDED;
|
|
||||||
}
|
|
||||||
input_vx_ = 0.0F;
|
|
||||||
input_vy_ = 0.0F;
|
|
||||||
intended_vx_ = 0.0F;
|
|
||||||
intended_vy_ = 0.0F;
|
|
||||||
motion_time_ms_ = 0.0F;
|
|
||||||
setVelX(0.0F);
|
|
||||||
setVelY(0.0F);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// En HURT el jugador està projectat sense control: descomptem
|
|
||||||
// velocitat per inèrcia (decaiment lineal fins a 0). Quan arriba a
|
|
||||||
// zero, tornem a GROUNDED i el frame següent ja torna a llegir input.
|
|
||||||
// El moviment real l'aplica `applyMovement` (igual que els altres
|
|
||||||
// estats), que també gestiona el xoc contra murs.
|
|
||||||
if (state_ == State::HURT) {
|
|
||||||
(void)consumeJumpEdge();
|
|
||||||
(void)consumeAttackEdge();
|
|
||||||
const float DECEL = (cfg_.hurt.brake_time_ms > 0)
|
|
||||||
? cfg_.hurt.initial_speed_px_per_s / (static_cast<float>(cfg_.hurt.brake_time_ms) / 1000.0F)
|
|
||||||
: 0.0F;
|
|
||||||
const float STEP = DECEL * delta_time;
|
|
||||||
auto decay = [STEP](float& v) {
|
|
||||||
if (std::fabs(v) <= STEP) {
|
|
||||||
v = 0.0F;
|
|
||||||
} else {
|
|
||||||
v -= std::copysign(STEP, v);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
decay(intended_vx_);
|
|
||||||
decay(intended_vy_);
|
|
||||||
if (intended_vx_ == 0.0F && intended_vy_ == 0.0F) {
|
|
||||||
state_ = State::GROUNDED;
|
|
||||||
}
|
|
||||||
input_vx_ = 0.0F;
|
|
||||||
input_vy_ = 0.0F;
|
|
||||||
setVelX(intended_vx_);
|
|
||||||
setVelY(intended_vy_);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
input_vx_ = 0.0F;
|
||||||
|
input_vy_ = 0.0F;
|
||||||
|
setVelX(intended_vx_);
|
||||||
|
setVelY(intended_vy_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Estat normal de joc (GROUNDED): llegeix input, integra física, actualitza
|
||||||
|
// facing i processa els flancs d'atac i salt.
|
||||||
|
void Player::tickGroundedInput(float delta_time) {
|
||||||
// Refresca les vinculacions des d'Options en calent: així un remap fet
|
// Refresca les vinculacions des d'Options en calent: així un remap fet
|
||||||
// al menú de servei té efecte immediatament, sense esperar al pròxim
|
// al menú de servei té efecte immediatament, sense esperar al pròxim
|
||||||
// GameScene::onEnter. Replica el comportament d'AEE
|
// GameScene::onEnter. Replica el comportament d'AEE
|
||||||
@@ -725,6 +697,55 @@ void Player::tick(float delta_time) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dispatcher per estat. La complexitat real viu als handlers individuals.
|
||||||
|
void Player::tick(float delta_time) {
|
||||||
|
// 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; }
|
||||||
|
|
||||||
|
// Decrement del timer d'immunitat. Independent de l'estat: si el
|
||||||
|
// jugador mor durant la immunitat (només via forat, que no es gateja),
|
||||||
|
// el `respawn` rearma una nova finestra. Si la finestra acaba mentre
|
||||||
|
// és AIRBORNE/HURT, no passa res — el gate dels hazards passa a
|
||||||
|
// quedar obert al primer frame post-zero.
|
||||||
|
if (immunity_remaining_ms_ > 0.0F) {
|
||||||
|
immunity_remaining_ms_ -= delta_time * 1000.0F;
|
||||||
|
immunity_remaining_ms_ = std::max(immunity_remaining_ms_, 0.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state_ == State::DYING) {
|
||||||
|
tickDying();
|
||||||
|
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
|
||||||
|
// a governar-se per la velocitat real sense estat romanent.
|
||||||
|
being_pushed_ = false;
|
||||||
|
|
||||||
|
if (state_ == State::LANDING_STUN) {
|
||||||
|
tickLandingStun(delta_time);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (state_ == State::AIRBORNE) {
|
||||||
|
tickAirborne();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (state_ == State::ATTACKING) {
|
||||||
|
tickAttacking(delta_time);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (state_ == State::HURT) {
|
||||||
|
tickHurt(delta_time);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tickGroundedInput(delta_time);
|
||||||
|
}
|
||||||
|
|
||||||
void Player::refreshControlsFromOptions() {
|
void Player::refreshControlsFromOptions() {
|
||||||
if (id_ != 0 && id_ != 1) { return; }
|
if (id_ != 0 && id_ != 1) { return; }
|
||||||
const auto& kb = (id_ == 0) ? Options::controls().keyboard_p1
|
const auto& kb = (id_ == 0) ? Options::controls().keyboard_p1
|
||||||
|
|||||||
@@ -604,6 +604,15 @@ class Player : public AnimatedSprite {
|
|||||||
void renderShadow() const;
|
void renderShadow() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Sub-handlers de tick(), un per estat amb sortida prematura. Mantenir-los
|
||||||
|
// a part redueix la complexitat cognitiva del dispatcher principal.
|
||||||
|
void tickDying();
|
||||||
|
void tickLandingStun(float delta_time);
|
||||||
|
void tickAirborne();
|
||||||
|
void tickAttacking(float delta_time);
|
||||||
|
void tickHurt(float delta_time);
|
||||||
|
void tickGroundedInput(float delta_time);
|
||||||
|
|
||||||
// Alias privat històric. Mantingut perquè viu dins de l'implementació
|
// Alias privat històric. Mantingut perquè viu dins de l'implementació
|
||||||
// (snapToLane, clamp). Els consumidors externs usen `getBaseBox()`.
|
// (snapToLane, clamp). Els consumidors externs usen `getBaseBox()`.
|
||||||
[[nodiscard]] auto baseBox() const -> SDL_FRect { return getBaseBox(); }
|
[[nodiscard]] auto baseBox() const -> SDL_FRect { return getBaseBox(); }
|
||||||
|
|||||||
Reference in new issue
Block a user