feat(border): refactor a Graphics::Border amb bumps i flash verd clar per impactes contra les parets
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
// border.cpp - Implementació del border del playfield
|
||||
// © 2026 JailDesigner
|
||||
|
||||
#include "core/graphics/border.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
#include "core/defaults.hpp"
|
||||
#include "core/rendering/line_renderer.hpp"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
Border::Border(Rendering::Renderer* renderer)
|
||||
: renderer_(renderer) {}
|
||||
|
||||
void Border::update(float delta_time) {
|
||||
for (auto& side : sides_) {
|
||||
// Desplaçament decau cap a 0 amb ritme constant (lineal).
|
||||
const float DEC = Defaults::Border::DISPLACEMENT_RECOVERY_PER_S * delta_time;
|
||||
side.displacement_px = std::max(0.0F, side.displacement_px - DEC);
|
||||
}
|
||||
}
|
||||
|
||||
void Border::bumpAt(Vec2 contact_point, float strength) {
|
||||
const SDL_FRect& zona = Defaults::Zones::PLAYAREA;
|
||||
const std::array<float, SIDE_COUNT> DISTANCES = {
|
||||
/* TOP */ std::abs(contact_point.y - zona.y),
|
||||
/* RIGHT */ std::abs((zona.x + zona.w) - contact_point.x),
|
||||
/* BOTTOM */ std::abs((zona.y + zona.h) - contact_point.y),
|
||||
/* LEFT */ std::abs(contact_point.x - zona.x)};
|
||||
|
||||
int closest_idx = 0;
|
||||
float closest_dist = DISTANCES[0];
|
||||
for (int i = 1; i < SIDE_COUNT; i++) {
|
||||
if (DISTANCES[i] < closest_dist) {
|
||||
closest_dist = DISTANCES[i];
|
||||
closest_idx = i;
|
||||
}
|
||||
}
|
||||
applyBump(closest_idx, strength);
|
||||
}
|
||||
|
||||
void Border::applyBump(int side_idx, float strength) {
|
||||
const float S = std::clamp(strength, 0.0F, 1.0F);
|
||||
SideState& side = sides_[static_cast<std::size_t>(side_idx)];
|
||||
side.displacement_px = std::min(
|
||||
Defaults::Border::MAX_DISPLACEMENT_PX,
|
||||
side.displacement_px + (S * Defaults::Border::MAX_DISPLACEMENT_PX));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Lerp de l'oscil·lador (color base actual) cap a un color "flash" en
|
||||
// funció de f ∈ [0, 1]. Retorna sempre amb alpha>0 perquè el line_renderer
|
||||
// l'use directament (sense barrejar amb el global).
|
||||
auto lerpColor(SDL_Color flash, float f) -> SDL_Color {
|
||||
const float CLAMPED = std::clamp(f, 0.0F, 1.0F);
|
||||
const SDL_Color BASE = Rendering::getLineColor();
|
||||
const auto LERP_U8 = [&](unsigned char a, unsigned char b) {
|
||||
const float OUT = (static_cast<float>(a) * (1.0F - CLAMPED)) + (static_cast<float>(b) * CLAMPED);
|
||||
return static_cast<unsigned char>(OUT);
|
||||
};
|
||||
return SDL_Color{
|
||||
.r = LERP_U8(BASE.r, flash.r),
|
||||
.g = LERP_U8(BASE.g, flash.g),
|
||||
.b = LERP_U8(BASE.b, flash.b),
|
||||
.a = 255};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void Border::draw() const {
|
||||
const SDL_FRect& zona = Defaults::Zones::PLAYAREA;
|
||||
const int X1 = static_cast<int>(zona.x);
|
||||
const int Y1 = static_cast<int>(zona.y);
|
||||
const int X2 = static_cast<int>(zona.x + zona.w);
|
||||
const int Y2 = static_cast<int>(zona.y + zona.h);
|
||||
|
||||
const int OFF_TOP = static_cast<int>(sides_[SIDE_TOP].displacement_px);
|
||||
const int OFF_RIGHT = static_cast<int>(sides_[SIDE_RIGHT].displacement_px);
|
||||
const int OFF_BOTTOM = static_cast<int>(sides_[SIDE_BOTTOM].displacement_px);
|
||||
const int OFF_LEFT = static_cast<int>(sides_[SIDE_LEFT].displacement_px);
|
||||
|
||||
// Color per costat: lerp(oscil·lador → flash) en funció del desplaçament.
|
||||
const SDL_Color FLASH = {
|
||||
.r = Defaults::Border::FLASH_COLOR_R,
|
||||
.g = Defaults::Border::FLASH_COLOR_G,
|
||||
.b = Defaults::Border::FLASH_COLOR_B,
|
||||
.a = 255};
|
||||
const float MAX_D = Defaults::Border::MAX_DISPLACEMENT_PX;
|
||||
const bool DO_FLASH = Defaults::Border::FLASH_ENABLED;
|
||||
|
||||
const SDL_Color C_TOP = DO_FLASH ? lerpColor(FLASH, sides_[SIDE_TOP].displacement_px / MAX_D) : SDL_Color{};
|
||||
const SDL_Color C_RIGHT = DO_FLASH ? lerpColor(FLASH, sides_[SIDE_RIGHT].displacement_px / MAX_D) : SDL_Color{};
|
||||
const SDL_Color C_BOTTOM = DO_FLASH ? lerpColor(FLASH, sides_[SIDE_BOTTOM].displacement_px / MAX_D) : SDL_Color{};
|
||||
const SDL_Color C_LEFT = DO_FLASH ? lerpColor(FLASH, sides_[SIDE_LEFT].displacement_px / MAX_D) : SDL_Color{};
|
||||
|
||||
// Una sola línia per costat (brillo 1.0). Si DO_FLASH = false → alpha = 0 → usa
|
||||
// el color global de l'oscil·lador.
|
||||
Rendering::linea(renderer_, X1, Y1 - OFF_TOP, X2, Y1 - OFF_TOP, 1.0F, 0.0F, C_TOP);
|
||||
Rendering::linea(renderer_, X2 + OFF_RIGHT, Y1, X2 + OFF_RIGHT, Y2, 1.0F, 0.0F, C_RIGHT);
|
||||
Rendering::linea(renderer_, X1, Y2 + OFF_BOTTOM, X2, Y2 + OFF_BOTTOM, 1.0F, 0.0F, C_BOTTOM);
|
||||
Rendering::linea(renderer_, X1 - OFF_LEFT, Y1, X1 - OFF_LEFT, Y2, 1.0F, 0.0F, C_LEFT);
|
||||
}
|
||||
|
||||
} // namespace Graphics
|
||||
Reference in New Issue
Block a user