- Defaults::Palette::WOUNDED ({255,215,0}) dorat per a parpadeig
- Defaults::Enemies::Wounded::{DURATION, BLINK_HZ}
- Enemy: wounded_timer_, wound_expired_this_frame_
- API: herir(), isWounded(), getWoundedTimer(),
woundExpiredThisFrame(), consumeWoundExpired(), applyImpulse()
- update() decrementa timer i marca expiració al creuar 0
- destruir() reseteja l'estat wounded
Sense efectes visuals ni canvis de comportament: cap callsite invoca
encara herir() ni applyImpulse(). Build verda i smoke test xvfb OK.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reemplaça core/defaults.hpp pels subheaders concrets a director.cpp i
config_yaml.cpp (silencia unused-includes de clangd). Marca el umbrella
amb IWYU pragma: begin_exports/end_exports per evitar falsos positius
als consumidors transitius.
Separa el tamany lògic (1280×720) del render target offscreen. Llista
tancada de 5 presets 16:9 (720p/900p/1080p/1440p/2160p) llegida de
rendering.render_{width,height} amb fallback a 1280×720 si invàlida.
Inclou API resizeRenderTarget() preparada per al menú de servei futur.
Toasts centrats al centre-superior amb fons semitransparent, slide-in/out
amb easings cubic, integrats als toggles F1-F5 i a la doble pulsació
d'ESC per confirmar la sortida.
- COLOR_INFO passa de blanc neutre (230,230,230) a cian (80,230,255)
per a diferenciar més els toasts informatius dels d'avís/error.
- TEXT_SCALE de 0.4 → 0.55 perquè el text sigui més llegible amb
l'aspect-fit del viewport.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
La primera ESC ja no tanca el joc directament: dispara un toast
"PREMEU ESC UN ALTRE COP PER EIXIR" en vermell. Mentre el toast està
entrant o aguantant (Notifier::isActiveWindow()), una segona ESC
confirma i tanca. Si l'usuari espera a que el toast comenci a sortir
o desaparegui, ESC torna a obrir la finestra de confirmació sense
tancar — només una doble pulsació consecutiva tanca.
Si el Notifier no existeix (no hauria de passar dins runFrameLoop),
ESC manté el comportament antic de tancar directament.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Substitueixen els std::cout dels handlers per crides a notifyInfo() del
Notifier:
- F1/F2: ZOOM: X.YX (amb el valor actual)
- F3: PANTALLA COMPLETA / MODE FINESTRA
- F4: VSYNC ACTIU / VSYNC INACTIU
- F5: AA ACTIU / AA INACTIU
Tots els missatges en majúscules perquè la font vectorial actual només
té glyphs A-Z. Es manté la lògica de toggle i de persistència de cfg;
únicament canvia el canal de feedback (consola → toast HUD).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Notifier singleton (System::init/get/destroy) que dibuixa un cuadre
centrat al centre-superior amb fons semitransparent (derivat oscur del
color del text) i bordes en línies.
- Màquina d'estats HIDDEN → ENTERING → HOLDING → EXITING amb easing
outCubic (entrada) i inCubic (sortida), slide de 300 ms.
- pushRect() afegit a GpuFrameRenderer (2 triangles, edge_dist=0) per
poder pintar el fons opac/semitransparent reutilitzant el pipeline de
línies — sense afegir cap pipeline nou.
- VectorText::render/renderCentered admeten color RGBA explícit
(default {0,0,0,0} preserva el comportament previ amb oscil·lador
global de color).
- Easing header-only a core/utils/easing.hpp (outCubic, inCubic).
- Director crea Notifier just després del DebugOverlay i el draweja com
a última capa per damunt de l'escena i el debug.
Encara cap consumer el crida; els F1-F5 i la doble pulsació d'ESC
arriben en commits posteriors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tres fronts arreglats a la rama:
- Fullscreen: el viewport ja no depèn de zoom_factor_ (capat per max_zoom_),
sinó que és aspect-fit de la mida física actual. Afegit
SetWindowFullscreenMode(nullptr) i preservació del zoom_factor_ de windowed
durant transicions.
- VSync: setVSync ara consulta SDL_WindowSupportsGPUPresentMode i fa fallback
IMMEDIATE → MAILBOX → VSYNC quan el driver/compositor força VSync. Loggeja
el mode efectiu.
- Antialias geomètric a les línies: edge attribute + smoothstep al fragment.
Toggle runtime amb F5, indicador 'AA: ON/OFF' al debug overlay (F11).
Permet alternar l'AA geomètric en runtime:
- Action::TOGGLE_ANTIALIAS bound a F5.
- GlobalEvents::handle reacciona al scancode F5 cridant sdl.toggleAntialias().
- SDLManager::toggleAntialias muta cfg_->rendering.antialias i propaga a
gpu_renderer_.setAntialias().
- GpuFrameRenderer manté l'estat antialias_enabled_ (true per defecte) i
pushLine adapta extrusió i edge_dist en funció del flag — geometria nua
quan està OFF, fade als bords quan està ON.
- RenderingConfig guanya el camp `antialias{1}` per coherència amb vsync;
l'estat NO es persisteix al YAML de moment (decisió volgudament conservadora,
podem afegir-ho en un commit a part si cal).
- DebugOverlay (F11) mostra una tercera línia "AA: ON/OFF" sota VSYNC per
poder comparar a temps real.
Afegim antialias geomètric (sense MSAA) al pipeline de línies aprofitant
que la línia ja es construeix com a quad extruït a CPU:
- LineVertex: nou camp edge_dist (±1 als laterals del quad, 0 al centre).
- pushLine: extrudeix 0.5px extra per banda (AA_PADDING) per allotjar el
fade sense menjar gruix nominal.
- line.vert: passa l'edge_dist al fragment com a varying.
- line.frag: alpha *= 1 - smoothstep(0.7, 1.0, |edge_dist|) — fade Hermite
C¹ als bords, sense banding.
AA actiu per defecte. El toggle a runtime (F5) ve en el commit següent.
setVSync demanava SDL_GPU_PRESENTMODE_IMMEDIATE sense comprovar suport.
A SDL_GPU només VSYNC està garantit; IMMEDIATE i MAILBOX són opcionals.
Si no estaven suportats (típicament Wayland/X11 amb compositor), SDL
retornava error i la swapchain es quedava en VSYNC sense que ho sabéssim.
Ara:
- Consultem SDL_WindowSupportsGPUPresentMode abans de fer la crida.
- En VSync OFF: provem IMMEDIATE → fallback a MAILBOX → si cap, ens
quedem en VSYNC i avisem (driver/compositor força VSync).
- Loggejem sempre el mode efectiu (no només els errors), perquè ara mateix
no hi havia forma de saber des de fora si el toggle havia tingut efecte.
Quan arribava un SDL_EVENT_WINDOW_RESIZED en fullscreen, recalculàvem
zoom_factor_ a partir de la mida física i el clampàvem a max_zoom_. Això
"consumia" el zoom_factor_ que tenia l'usuari en windowed, així que en
tornar a windowed (F3) la mida quedava la del clamp, no la prèvia.
Ara, en fullscreen, zoom_factor_ i windowed_*_ es deixen intactes (no
participen del càlcul del viewport, que ja és aspect-fit sobre la mida
física). En windowed, comportament inalterat.
A SDL3, SDL_SetWindowFullscreen(true) sol hereta el SDL_DisplayMode que tingués
la finestra. Sense una crida prèvia a SDL_SetWindowFullscreenMode(win, nullptr),
el comportament és no determinista entre invocacions (i pot acabar en mode
exclusiu si abans hi havia hagut un mode setejat).
Afegim la crida amb mode=nullptr just abans d'activar el fullscreen perquè
sempre entrem en "borderless desktop" (cobrint el monitor on viu la finestra).
El viewport del pase final es calculava com `Game::WIDTH * zoom_factor_`. Però
`zoom_factor_` està capat a `max_zoom_`, que es deriva de `display - 100px`
(marge per a decoracions). En fullscreen això deixa marc negre als 4 costats:
amb display 1920×1080 max_zoom_≈1.25 → viewport 1600×900 dins de 1920×1080.
Ara l'escala es calcula directament de la finestra física actual com a
aspect-fit (`min(curW/1280, curH/720)`), de manera que el viewport sempre
omple un eix i lletraboxeja l'altre, independentment del zoom_factor_. El
zoom_factor_ continua dimensionant la finestra en mode windowed (F1/F2).
Atac sistemàtic al CODE_REVIEW.md generat tras tancar el cicle de lint.
10 hallazgos del audit + 3 side-roads del hook, en 18 commits atòmics.
Hallazgos del audit cerrats:
- #1 Scene::init() lifecycle (fusionat al ctor de GameScene)
- #11 Ship::isAlive/isHit/isActive consolidats en isActive()
- #16 Rotation3D mort (eliminat struct + paràmetre + apply3dRotation)
- #18 ShapeLoader::resolvePath + BASE_PATH morts
- #21 Options::physics/audio/gameplay morts (cap reader en runtime)
- #22+#30 defaults.hpp partit en 15 subfitxers + umbrella
- #24 aliases morts de game/constants.hpp (MARGIN_*, VELOCITAT*)
- #25 Defaults::Physics::*_SPEED legacy del Pascal
- #28 inversió de dependència core→game per a Options:
Config::EngineConfig (POD) viu a core/config/, els sistemes
(Director, SDLManager, DebugOverlay, Input) reben referència
injectada. La capa YAML viu a game/config_yaml.{hpp,cpp}
(renomenat des d'Options).
- #34 doble inicialització d'enemies_ a GameScene
- #37 Director::run() ja no estàtica (lateral de #28)
Out of scope (per un hallazgo separat):
- core/system/director.cpp encara inclou game/scenes/*.hpp;
cal factory pattern per a escenes.
Side-roads del hook:
- relative path a cppcheck del pre-commit
- alineació amb --suppress=useStlAlgorithm de make cppcheck
- std::ranges::fill surfat per cppcheck a GameScene ctor
Verificat: compila clean, clang-tidy + cppcheck zero hits nous
(32 NOLINTs preexistents igual que abans).
Pas 7 final del hallazgo #28. La capa de game/options havia esdevingut
exclusivament una capa de persistència YAML que llegia i escrivia
Config::EngineConfig. El nom "Options" no reflectia bé aquest rol.
Canvis:
- Renomenats fitxers: game/options.{hpp,cpp} → game/config_yaml.{hpp,cpp}
(preservant la història de git via mv).
- Renomenat namespace: Options → ConfigYaml.
- Esborrades del .hpp les referències-alias inline (window, rendering,
player1, player2, keyboard_controls, gamepad_controls, console) que
ja no tenien call-sites externs (només existien per a la transició).
El .hpp ara només exposa engine_config + version + path + funcions.
- A config_yaml.cpp s'introdueixen aliases internes (anonymous namespace)
per mantenir llegible el codi de la implementació, sense exposar-les.
- Actualitzat main.cpp per a usar ConfigYaml::*.
- Actualitzats els comentaris stale a sdl_manager.hpp, director.hpp,
engine_config.hpp i audio.hpp.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pas 5/N del hallazgo #28.
Director deixa d'incloure game/options.hpp i les seves crides a
Options::*. El seu ctor accepta ara:
- Config::EngineConfig& cfg → la struct runtime (window, console, ...).
- Config::ConfigPersistence → 4 lambdes (init/set_path/load/save)
que delegen la persistència a la capa concreta (game/Options::*).
Cap més referència a Options:: ni a "game/..." dins del Director:
- cfg_->* substitueix tot Options::* (window, console, player1/2,
rendering, engine_config).
- persistence_.{init,save,load,set_path} substitueix les funcions
d'I/O de YAML.
run() i checkProgramArguments deixen de ser estàtics (necessiten
accés a cfg_ i persistence_). Això també desfà el smell del
hallazgo #37 (Director::run estàtic que llegia estat d'instància).
main.cpp queda com a orquestrador: construeix la struct
ConfigPersistence amb lambdes que enllacen amb Options::* i la
injecta al Director.
Afegit: Config::ConfigPersistence a engine_config.hpp.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pas 4/N del hallazgo #28.
SDLManager deixa d'incloure game/options.hpp. El ctor accepta ara una
Config::EngineConfig& (per llegir/mutar window i rendering) i un
opcional std::function<void()> on_persist callback.
Canvis funcionals:
- Es mantenen les mutacions de window.{width,height,zoom_factor,fullscreen}
però ara sobre cfg_->window en lloc d'Options::window. Comportament
idèntic perquè Options::window és un alias a engine_config.window.
- toggleVSync deixa de cridar Options::saveToFile() directament i
invoca on_persist_ si està connectat. El Director li passa una lambda
que fa la persistència (mantenint sdl_manager agnòstic).
- initWindowAndGpu (free function) rep el vsync inicial per paràmetre.
- Eliminat el ctor per defecte (SDLManager()) que no era cridat des de
cap call-site del projecte.
Cleanup preexistent surfat per clang-tidy en treure el ctor default:
- finestra_, max_width_, max_height_, max_zoom_ passen a tindre
default member initializers; eliminat el seu ctor mem-init redundant.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pas 3/N del hallazgo #28.
Input deixa d'incloure game/options.hpp. Els antics applyPlayerXFromOptions
es renombren a applyPlayerXBindings(const Config::PlayerBindings&) i
reben els bindings per paràmetre en lloc de llegir-los del global
Options::*. El Director hi passa Options::player1/2 als call-sites.
Esborrats applyKeyboardBindingsFromOptions i applyGamepadBindingsFromOptions
que no eren cridats per ningú (dead code aprofitat).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Afegit --suppress=useStlAlgorithm al hook, que ja estava al
target cppcheck de CMakeLists.txt:297. La regla és sorollosa
(suggereix std::find_if/std::any_of/std::transform a qualsevol
raw loop que es podria fer més curt) i el projecte ja va decidir
desactivar-la a nivell de pasada completa.
Segon desencontre entre el hook i el target CMake (el primer va
ser el -I absolut vs relatiu). Mantenim el hook i make cppcheck
coherents per no fer veure problemes que no n'hi ha.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pas 2/N del hallazgo #28.
DebugOverlay deixa d'incloure game/options.hpp i passa a rebre un
const Config::RenderingConfig& en el seu constructor. El Director li
passa Options::rendering (que ja és un alias d'engine_config.rendering).
Eliminat: include "game/options.hpp" des de core/system/debug_overlay.cpp.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pas 1/N del hallazgo #28. Sense canvi de comportament:
Nou: source/core/config/engine_config.hpp
- Defineix Config::EngineConfig (POD) amb les sub-structs WindowConfig,
RenderingConfig, KeyboardBindings, GamepadBindings, PlayerBindings i
el flag console.
- Sense singletons ni virtuals; la inversió real es fa en commits
posteriors injectant Config::EngineConfig& per constructor.
Modificat: source/game/options.hpp
- Elimina les struct definitions locals (Window, Rendering, ...).
- Afegeix Options::engine_config (única font de veritat).
- Conserva Options::window, Options::rendering, player1, player2,
keyboard_controls, gamepad_controls i console com a referències
inline a camps d'engine_config. Cost runtime zero, callsites
existents no requereixen cap canvi.
Hallazgo #28 de CODE_REVIEW.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
defaults.hpp tenia 527 línies amb 17 namespaces de dominis distints
(Window, Game, Zones, Entities, Palette, Ship, Physics, Math,
Brightness, Rendering, Audio, Music, Sound, Controls, Enemies, Title,
FloatingScore). 22 .cpp/.hpp l'incloïen, així que tocar una constant
forçava recompilar pràcticament tot.
Es divideix en 15 subfitxers (un per namespace, fusionant Music/Sound
a audio.hpp i unificant els dos blocs Game duplicats en un sol):
defaults/window.hpp defaults/audio.hpp
defaults/game.hpp defaults/controls.hpp
defaults/zones.hpp defaults/enemies.hpp
defaults/entities.hpp defaults/title.hpp
defaults/palette.hpp defaults/floating_score.hpp
defaults/ship.hpp defaults/math.hpp
defaults/physics.hpp defaults/brightness.hpp
defaults/rendering.hpp
Cross-deps explícites (#include en lloc d'order-of-declaration):
zones.hpp -> game.hpp (per Game::WIDTH/HEIGHT)
enemies.hpp -> entities.hpp (per SHIP_RADIUS)
title.hpp -> game.hpp, math.hpp + <cmath>
defaults.hpp queda com a umbrella que inclou els 15 subfitxers. Els
22 includers existents no requereixen cap canvi. Codi nou pot
incloure el subfitxer concret per millorar la compilació incremental.
Hallazgos #22 i #30 de CODE_REVIEW.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Constants legacy heretades del Pascal, en unitats/frame, que la
migració a SDL3 va deixar sense ús real:
- ENEMY_SPEED i BULLET_SPEED només es llegien des d'Options::physics
(esborrat al #21) i des de Constants::VELOCITAT/VELOCITAT_MAX
(esborrat al #24). Ara amb zero callers.
- VELOCITY_SCALE no tenia callers (les velocitats efectives es
calculen a Bullet::BULLET_SPEED = 140 px/s i a
Defaults::Enemies::{Pentagon,Cuadrado,Molinillo}::VELOCITAT).
S'ajusta el comentari del namespace per reflectir que ara conté
només la física del control de la nau.
Hallazgo #25 de CODE_REVIEW.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Esborrats:
- Constants::MARGIN_LEFT/RIGHT/TOP/BOTTOM (zero callers; tots els
call-sites llegeixen Defaults::Zones::PLAYAREA directament).
- Constants::VELOCITAT i VELOCITAT_MAX (zero callers; eren els últims
lectors de Defaults::Physics::ENEMY_SPEED/BULLET_SPEED).
Es mantenen MAX_ORNIS, MAX_BALES (sí usats a game_scene.hpp) i PI,
més els helpers de zona.
Habilita el hallazgo #25 (eliminar Defaults::Physics::ENEMY_SPEED /
BULLET_SPEED / VELOCITY_SCALE) — ja sense lectors.
Hallazgo #24 de CODE_REVIEW.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Aquestes tres seccions s'estaven carregant del YAML, parsejant,
validant i escrivint, però cap d'elles tenia consumidor en runtime:
- Options::physics: l'únic call-site era un std::cout informatiu a
director.cpp:109. Ship/Enemy/Bullet llegeixen Defaults::Physics
directament.
- Options::audio: explícitament desacoblat (audio.hpp:22-25) — la
font de configuració era Defaults::Audio via Audio::Config.
- Options::gameplay: zero readers. Els arrays són compile-time.
Esborrats:
- Structs Physics/Gameplay/Music/Sound/Audio i les globals.
- Defaults a init(), helpers loadXxxConfigFromYaml, secció escrita
a saveToFile, crides al loadFromFile.
- La línia "Física: rotation=..." del console output del Director.
Es manté Options::window i Options::rendering (sí utilitzats).
Hallazgo #21 de CODE_REVIEW.md (opció a: borrar).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Amb -I "\$REPO_ROOT/source" (path absolut), cppcheck no resolia bé el
<cstdint> i emetia un syntaxError fals sobre les capçaleres del tipus
"enum class X : std::uint8_t {" (afecta scene_context.hpp i d'altres
que tenen enums tipats).
El bug estava latent des del commit c45e524 ("clang-tidy --fix
mecánico (... enum size)"), que va afegir els underlying-types als
enums. Cap commit posterior va tocar fitxers que els inclogueren,
així que ningú l'havia activat fins ara.
Resolt amb path relatiu (els git hooks corren sempre des del repo
root, així que "source" és suficient).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Els tres mètodes retornaven el mateix bool a partir d'is_hit_:
isActive() = !is_hit_ (override de Entity)
isAlive() = !is_hit_
isHit() = is_hit_
Eren tres formes diferents de preguntar el mateix, repartides sense
criteri pels call-sites (collision_system, game_scene). Conservem
isActive() perquè és l'override polimòrfic d'Entity i esborrem els
altres dos. Actualitzats els 5 call-sites externs.
Hallazgo #11 de CODE_REVIEW.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
L'interfície Scene només declara handleEvent/update/draw/isFinished.
GameScene::init() era un mètode públic addicional que ningú (ni el
Director) cridava externament: només el propi ctor el cridava al
final. El comentari del header ("llamado por Director tras crear la
escena") era fals: el Director mai l'invoca.
TitleScene i LogoScene ja inicialitzen tot al ctor sense exposar
init(). Aquesta diferència trencava l'expectativa del lifecycle.
Movem tot el cos de init() al ctor i esborrem la declaració i la
definició. Aprofitem per:
- Eliminar el guard "if (!stage_config_)" que pressuposava re-init,
cas que mai s'arribava a donar.
- Treure el comentari DEPRECATED sobre spawn_position_ (residu).
Hallazgo #1 de CODE_REVIEW.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
El ctor de GameScene ja construïa cada Enemy amb el renderer, però
init() (cridat des del propi ctor) tornava a assignar
enemies_[i] = Enemy(sdl_.getRenderer()) sobre la mateixa instància.
Treball perdut, a més d'incoherent amb ships_ i bullets_, que no es
reassignen a init() sinó que es limiten a init()/addBody.
Eliminem la reassignació i deixem només setShipPosition i addBody,
alineat amb la resta d'entitats.
Hallazgo #34 de CODE_REVIEW.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cppcheck (style: useStlAlgorithm) marcava els raw loops d'assignació
sobre std::array com a candidats clars per std::fill/std::generate.
Amb fill només es construeix la temporal una vegada i es copia a cada
element, en lloc de construir N temporals.
Preexistent, no introduït per cap commit recent, però el hook ho
demanava en tocar el fitxer. Es resolt el root cause en lloc de
suprimir.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
L'struct Rotation3D, la funció apply3dRotation i el paràmetre opcional
rotation_3d de renderShape mai s'activaven en cap caller:
- Ship, Enemy i Bullet passaven explícitament nullptr.
- Title scene, logo scene, starfield, vector_text i ship_animator
usaven el default nullptr (set els 7 callers).
CLAUDE.md descriu un sistema 3D del title screen que ja no està viu —
el comentari en ship_animator.cpp aclareix que la perspectiva s'ha
bakeat dins de la shape, així que la rotació dinàmica era residu
històric.
Esborrats: struct Rotation3D + ctors + hasRotation(), apply3dRotation(),
la branca rotation_3d a transformPoint() i el seu paràmetre, el
paràmetre rotation_3d de renderShape, i els arguments nullptr als
3 callers d'entitats.
Hallazgo #16 de CODE_REVIEW.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cap caller invocava resolvePath fora de la seua pròpia definició.
A més, BASE_PATH apuntava a "data/shapes/" mentre que load() ja
construeix el path amb el prefix "shapes/" directament — el helper
mai s'hauria activat encara que es cridara.
Hallazgo #18 de CODE_REVIEW.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reporte completo de la pasada de revisión arquitectónica realizada por
el subagente Plan tras cerrar el ciclo de lint. Organiza los 40
hallazgos en 8 áreas (escenas, sistemas, entidades, renderizado,
configuración, naming, headers, bugs latentes), cada uno con prioridad,
tipo (estructural/opinable), file:line, problema, propuesta y esfuerzo
estimado.
Incluye:
- Top picks de bugs latentes y limpieza con impacto
- Lista de hallazgos que requieren verificación profunda
- Lista de hallazgos opinables (potencialmente rechazables)
- Resumen de lo ya resuelto en chore/lint
- Plan de ataque sugerido para iterar
Permite continuar el code review en otro equipo sin perder el contexto.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Identifier-naming: rename de métodos públicos y cross-file al inglés
(camelBack), traducción de campos y locales en el proceso (TitleShip,
StageManager, SpawnController, ShipAnimator, helpers de PlayArea, etc.).
Refactor por cognitive-complexity (>25): GameScene::draw (59→3) con 9
helpers de estado, PhysicsWorld::resolveBodyCollisions (35→5) extrayendo
resolveBodyPair, Options::load{Window,Physics,Audio}ConfigFromYaml
(32/49/57→5/2/3) con templates readField, TitleScene::update (68→4) con
5 sub-pasos por estado + handleSkipInput/handleStartInput +
triggerExitForJoinedPlayers, DebrisManager::explode (39→3) con
extractSegments/spawnDebris/applyAngularVelocity/applyVisualRotation.
use-anyofallof: bucles → std::ranges::any_of/all_of en Input,
ShipAnimator y SpawnController.
readability-static-accessed-through-instance: Director::run y
VectorText::getTextWidth/Height invocados por clase.
readability-convert-member-functions-to-static: ResourcePack::decryptData.
unused-includes: eliminación de <utility>, <cstdint>, <vector>,
<iostream>, defaults.hpp y otros no usados directamente en headers y
unidades de traducción. Restablecido core/defaults.hpp en title_scene.cpp
(falsa "unused" del header).
Bug fix: eliminado isActive() duplicado en Bullet (redeclaración tras
rename de esta_activa→isActive que chocaba con el override de Entity).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Métodos privados que no consultan estado de la instancia pasan a 'static'
en la declaración del header. Las definiciones en el .cpp pierden el 'const'
trailing (incompatible con static). Cero callsites afectados: las
llamadas via 'this->method()' o sin qualifier siguen siendo válidas para
métodos estáticos.
Aplicado en:
- Shape: trim, startsWith, extractValue, parsePoints.
- VectorText: getShapeFilename, get_text_width, get_text_height.
- Pack: readFile, calculateChecksum, encryptData.
- DebrisManager: computeExplosionDirection.
- Enemy: attemptSafeSpawn.
- LogoScene / TitleScene: checkSkipButtonPressed (consulta Input singleton).
- SpawnController: get_enemics_vius.
- StageManager: processPlaying.
- ShipAnimator: updateEntering, updateFloating, updateExiting,
configureShipP1, configureShipP2, computeOffscreenPosition.
- Director: run (los miembros executable_path_ / system_folder_ se fijan
en el ctor y no se vuelven a leer en el loop principal).
Verificado previamente con grep que ningún '&Class::method' los usa como
function pointer (cambiar a estático cambiaría su tipo).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>