feat(player): sombra translúcida sota el jugador mentre està en l'aire

This commit is contained in:
JailDesigner committed 2026-04-25 11:59:13 +02:00
1 parent c4caa9021e
commit 64390f8ad7
3 files changed
+46

No files matched your search

+34
View File
@@ -9,6 +9,7 @@
#include "core/input/gamepad_manager.hpp"
#include "core/input/input_state.hpp"
#include "core/rendering/screen.hpp"
#include "core/resources/resource_cache.hpp"
#include "core/resources/resource_helper.hpp"
#include "external/fkyaml_node.hpp"
@@ -689,6 +690,39 @@ void Player::render() {
pos_.y = SAVED_Y;
}
void Player::renderShadow() const {
// Sense salt actiu, no hi ha sombra: això simplifica els callsites,
// que poden cridar `renderShadow` per a tots els jugadors sense
// discriminar.
if (!isAirborne()) { return; }
// Sombra centrada al sprite, recolzada a la línia dels peus reals
// (ignorant `jump_z_`). L'amplada es redueix proporcional a l'altura
// del salt — al pic queda més estreta, donant la sensació de
// "elevació" sense necessitat de coordenades 3D reals. Si el
// jump_config té un divisor zero (cas degenerat), només dibuixem
// la sombra a mida plena per evitar nan.
const auto PEAK = (jump_config.gravity_px_per_s2 > 0.0F)
? (jump_config.impulse_px_per_s * jump_config.impulse_px_per_s) / (2.0F * jump_config.gravity_px_per_s2)
: 0.0F;
const float NORM_Z = (PEAK > 0.0F) ? std::clamp(jump_z_ / PEAK, 0.0F, 1.0F) : 0.0F;
constexpr float MAX_SHRINK = 0.4F; // Fins a un 40% més estreta al pic.
const float SHRINK = 1.0F - (NORM_Z * MAX_SHRINK);
constexpr int SHADOW_H = 3;
const auto SHADOW_W = static_cast<int>(static_cast<float>(base_size) * SHRINK);
const float CX = getPosX() + (static_cast<float>(sprite_w) * 0.5F);
const float GROUND_Y = getGroundFeetY();
const auto SX = static_cast<int>(CX - (static_cast<float>(SHADOW_W) * 0.5F));
const auto SY = static_cast<int>(GROUND_Y) - SHADOW_H;
// ARGB negre amb alpha ~40%. `blendRect` mescla sobre el canvas; així
// la sombra fosqueja el sòl (pintat o no) sense tapar-lo del tot.
constexpr std::uint32_t SHADOW_ARGB = 0x00000000U;
constexpr std::uint8_t SHADOW_ALPHA = 100;
Screen::get().blendRect(SX, SY, SHADOW_W, SHADOW_H, SHADOW_ARGB, SHADOW_ALPHA);
}
auto Player::animationName(bool moving) const -> const char* {
// En l'aire forcem la variant `jump_*` (per direcció), independent de
// si hi ha velocitat horitzontal: per al jugador, l'estat visual del
+6
View File
@@ -212,6 +212,12 @@ class Player : public AnimatedSprite {
// la posició al món no s'alteren.
void render() override;
// Pinta una sombra translúcida sota el jugador a nivell de sòl
// (sense aplicar `jump_z_`). El GameScene la crida en una passada
// pre-actors, així queda per sota dels actors i del propi jugador.
// No-op si el jugador no està en l'aire.
void renderShadow() const;
private:
// Alias privat històric. Mantingut perquè viu dins de l'implementació
// (snapToLane, clamp). Els consumidors externs usen `getBaseBox()`.