efbf2457a1
Primera tanda mecánica sobre el lint pendiente. Arregla la causa raíz, no
silencia diagnósticos. Detalle por categoría:
- Uninit members (cppcheck warnings) → inicializadores en declaración:
Bullet (esta_, owner_id_, grace_timer_), Enemy (drotacio_, rotacio_,
esta_, type_, tracking_timer_, ship_position_, tracking_strength_,
direction_change_timer_, timer_invulnerabilitat_), Ship (is_hit_,
invulnerable_timer_), Shape (escala_defecte_) y TitleShip (todos los
miembros del struct, que viven dentro de un std::array<,2>).
- returnByReference (cppcheck performance) → return const T&:
Shape::getName, ResourceLoader::getBasePath. De paso, Shape::get_nom
se renombra a getName y get_num_primitives a getNumPrimitives para
cumplir la convención camelBack del proyecto (lint del .clang-tidy).
- useInitializationList (cppcheck performance) →
Starfield::shape_estrella_ pasa a la lista de inicialización (reordenada
según la declaración para no disparar -Wreorder-ctor).
- noExplicitConstructor (cppcheck style) → explicit en ctores de 1 arg:
Bullet(Renderer*), Enemy(Renderer*), Ship(Renderer*,...) y VectorText(Renderer*).
- variableScope (cppcheck style) → en vector_text.cpp se elimina la
variable 'c' intermedia y se usa el literal '\\xA9' directamente en el
único punto donde se necesita.
- constParameterReference (cppcheck style) → drawScoreboardAnimated pasa
el VectorText por const ref (la API render/renderCentered es const).
- Warnings preexistentes del compilador (resueltos de paso):
- stage_config.hpp: stage_id <= 255 sobre uint8_t era siempre true; se
elimina la comparación redundante y se explica con comentario.
- director.cpp: 'struct stat st = {.st_dev = 0};' disparaba
-Wmissing-field-initializers; pasa a 'struct stat st{};' (zero-init
completo, robusto a las variantes específicas del SO).
- game_scene.cpp: stepDeathSequence devolvía un bool [[nodiscard]] que
el caller ignoraba; el valor era puramente interno. Cambiada la
firma a void.
- cppcheck: añadido --suppress=useStlAlgorithm. Las 26 sugerencias
'Consider using std::any_of/find_if/count_if' son cosméticas y no
aportan claridad sobre las raw loops actuales.
- .clang-tidy de source/core/audio/ eliminado: deshabilitaba todos los
checks en ese subdirectorio por dependencia de jail_audio.hpp, pero
impedía ejecutar 'make tidy' (clang-tidy aborta con "no checks
enabled" al primer archivo del directorio). El proyecto pasa a usar
el mismo patrón de CCAE: solo source/external/ y source/legacy/
quedan fuera del lint.
- lint-reports/ añadido a .gitignore. Carpeta donde 'make tidy' y
'make cppcheck' vuelcan su salida completa para inspección posterior.
Build limpio, cero warnings activos.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
170 lines
6.0 KiB
C++
170 lines
6.0 KiB
C++
// starfield.cpp - Implementació del sistema de estrelles de fons
|
|
// © 2026 JailDesigner
|
|
|
|
#include "core/graphics/starfield.hpp"
|
|
|
|
#include <cmath>
|
|
#include <cstdlib>
|
|
#include <iostream>
|
|
|
|
#include "core/defaults.hpp"
|
|
#include "core/graphics/shape_loader.hpp"
|
|
#include "core/rendering/shape_renderer.hpp"
|
|
|
|
namespace Graphics {
|
|
|
|
// Constructor
|
|
Starfield::Starfield(Rendering::Renderer* renderer,
|
|
const Vec2& punt_fuga,
|
|
const SDL_FRect& area,
|
|
int densitat)
|
|
: shape_estrella_(ShapeLoader::load("star.shp")),
|
|
renderer_(renderer),
|
|
punt_fuga_(punt_fuga),
|
|
area_(area),
|
|
densitat_(densitat) {
|
|
if (!shape_estrella_ || !shape_estrella_->isValid()) {
|
|
std::cerr << "ERROR: No s'ha pogut load star.shp" << '\n';
|
|
return;
|
|
}
|
|
|
|
// Configurar 3 capes con diferents velocitats i escales
|
|
// Capa 0: Fons llunyà (lenta, pequeña)
|
|
capes_.push_back({20.0F, 0.3F, 0.8F, densitat / 3});
|
|
|
|
// Capa 1: Profunditat mitjana
|
|
capes_.push_back({40.0F, 0.5F, 1.2F, densitat / 3});
|
|
|
|
// Capa 2: Primer pla (ràpida, grande)
|
|
capes_.push_back({80.0F, 0.8F, 2.0F, densitat / 3});
|
|
|
|
// Calcular radi màxim (distancia del centro al racó més llunyà)
|
|
float dx = std::max(punt_fuga_.x, area_.w - punt_fuga_.x);
|
|
float dy = std::max(punt_fuga_.y, area_.h - punt_fuga_.y);
|
|
radi_max_ = std::sqrt((dx * dx) + (dy * dy));
|
|
|
|
// Inicialitzar estrelles con posicions distribuïdes (pre-omplir pantalla)
|
|
for (int capa_idx = 0; capa_idx < 3; capa_idx++) {
|
|
int num = capes_[capa_idx].num_estrelles;
|
|
for (int i = 0; i < num; i++) {
|
|
Estrella estrella;
|
|
estrella.capa = capa_idx;
|
|
|
|
// Angle aleatori
|
|
estrella.angle = (static_cast<float>(rand()) / RAND_MAX) * 2.0F * Defaults::Math::PI;
|
|
|
|
// Distancia aleatòria (0.0 a 1.0) per omplir toda la pantalla
|
|
estrella.distancia_centre = static_cast<float>(rand()) / RAND_MAX;
|
|
|
|
// Calcular posición desde la distancia
|
|
float radi = estrella.distancia_centre * radi_max_;
|
|
estrella.position.x = punt_fuga_.x + (radi * std::cos(estrella.angle));
|
|
estrella.position.y = punt_fuga_.y + (radi * std::sin(estrella.angle));
|
|
|
|
estrelles_.push_back(estrella);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Inicialitzar una estrella (nueva o regenerada)
|
|
void Starfield::inicialitzar_estrella(Estrella& estrella) const {
|
|
// Angle aleatori des del point de fuga hacia fuera
|
|
estrella.angle = (static_cast<float>(rand()) / RAND_MAX) * 2.0F * Defaults::Math::PI;
|
|
|
|
// Distancia inicial pequeña (5% del radi màxim) - neix prop del centro
|
|
estrella.distancia_centre = 0.05F;
|
|
|
|
// Posición inicial: mucho prop del point de fuga
|
|
float radi = estrella.distancia_centre * radi_max_;
|
|
estrella.position.x = punt_fuga_.x + (radi * std::cos(estrella.angle));
|
|
estrella.position.y = punt_fuga_.y + (radi * std::sin(estrella.angle));
|
|
}
|
|
|
|
// Verificar si una estrella está fuera de l'àrea
|
|
bool Starfield::fora_area(const Estrella& estrella) const {
|
|
return (estrella.position.x < area_.x ||
|
|
estrella.position.x > area_.x + area_.w ||
|
|
estrella.position.y < area_.y ||
|
|
estrella.position.y > area_.y + area_.h);
|
|
}
|
|
|
|
// Calcular scale dinàmica segons distancia del centro
|
|
float Starfield::calcular_escala(const Estrella& estrella) const {
|
|
const CapaConfig& capa = capes_[estrella.capa];
|
|
|
|
// Interpolació lineal basada en distancia del centro
|
|
// distancia_centre: 0.0 (centro) → 1.0 (vora)
|
|
return capa.escala_min +
|
|
((capa.escala_max - capa.escala_min) * estrella.distancia_centre);
|
|
}
|
|
|
|
// Calcular brightness dinàmica segons distancia del centro
|
|
float Starfield::calcular_brightness(const Estrella& estrella) const {
|
|
// Interpolació lineal: estrelles properes (vora) més brillants
|
|
// distancia_centre: 0.0 (centro, llunyanes) → 1.0 (vora, properes)
|
|
float brightness_base = Defaults::Brightness::STARFIELD_MIN +
|
|
((Defaults::Brightness::STARFIELD_MAX - Defaults::Brightness::STARFIELD_MIN) *
|
|
estrella.distancia_centre);
|
|
|
|
// Aplicar multiplicador i limitar a 1.0
|
|
return std::min(1.0F, brightness_base * multiplicador_brightness_);
|
|
}
|
|
|
|
// Actualitzar posicions de las estrelles
|
|
void Starfield::update(float delta_time) {
|
|
for (auto& estrella : estrelles_) {
|
|
// Obtenir configuración de la capa
|
|
const CapaConfig& capa = capes_[estrella.capa];
|
|
|
|
// Moure hacia fuera des del centro
|
|
float velocity = capa.velocitat_base;
|
|
float dx = velocity * std::cos(estrella.angle) * delta_time;
|
|
float dy = velocity * std::sin(estrella.angle) * delta_time;
|
|
|
|
estrella.position.x += dx;
|
|
estrella.position.y += dy;
|
|
|
|
// Actualitzar distancia del centro
|
|
float dx_centre = estrella.position.x - punt_fuga_.x;
|
|
float dy_centre = estrella.position.y - punt_fuga_.y;
|
|
float dist_px = std::sqrt((dx_centre * dx_centre) + (dy_centre * dy_centre));
|
|
estrella.distancia_centre = dist_px / radi_max_;
|
|
|
|
// Si ha sortit de l'àrea, regenerar-la
|
|
if (fora_area(estrella)) {
|
|
inicialitzar_estrella(estrella);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Establir multiplicador de brightness
|
|
void Starfield::set_brightness(float multiplier) {
|
|
multiplicador_brightness_ = std::max(0.0F, multiplier); // Evitar valors negatius
|
|
}
|
|
|
|
// Dibuixar todas las estrelles
|
|
void Starfield::draw() {
|
|
if (!shape_estrella_->isValid()) {
|
|
return;
|
|
}
|
|
|
|
for (const auto& estrella : estrelles_) {
|
|
// Calcular scale i brightness dinàmicament
|
|
float scale = calcular_escala(estrella);
|
|
float brightness = calcular_brightness(estrella);
|
|
|
|
// Renderizar estrella sin rotación
|
|
Rendering::render_shape(
|
|
renderer_,
|
|
shape_estrella_,
|
|
estrella.position,
|
|
0.0F, // angle (las estrelles no giren)
|
|
scale, // scale dinàmica
|
|
1.0F, // progress (siempre visible)
|
|
brightness // brightness dinàmica
|
|
);
|
|
}
|
|
}
|
|
|
|
} // namespace Graphics
|