Crea los componentes base del nuevo motor de fisica sin alterar
todavia el comportamiento del juego. La migracion de Ship/Enemy/
Bullet al nuevo sistema queda para Fase 6.
Nuevos archivos:
- core/physics/rigid_body.hpp - struct POD con:
* Vec2 position, velocity (cartesianas, NO polares)
* float angle, angular_velocity
* mass, inverse_mass (cacheado; 0 = estatico)
* restitution (elasticidad 0..1)
* linear_damping, angular_damping (s-1, exponencial)
* radius (circulo de colision)
* applyForce / applyImpulse / clearAccumulators
* setStatic() para paredes/obstaculos
- core/physics/physics_world.hpp/.cpp - mundo fisico:
* Almacena RigidBody* (no-owning, ownership en entidades)
* setBounds(SDL_FRect) para paredes implicitas (PLAYAREA)
* update(dt) = integrate + resolveBoundsCollisions + resolveBodyCollisions
* Integrador semi-implicito de Euler + damping exponencial
* Resolucion circulo-circulo con correccion posicional e impulsos elasticos
* Formula del impulso: j = -(1+e)*(v_rel . n) / (1/m_a + 1/m_b)
* Broadphase trivial O(n^2): suficiente para ~25 cuerpos del juego
Decisiones de diseno:
- Velocidad en cartesianas (Vec2) en lugar de la representacion polar
actual (escalar velocidad + cos/sin del angulo cada frame). Adios al
acoplamiento entre orientacion y direccion de movimiento.
- Composicion sobre herencia: RigidBody es un struct independiente que
las entidades incrustaran como member en Fase 6, no una clase base.
- El integrador semi-implicito es la version estandar para juegos
arcade (mas estable que Euler explicito sin coste extra).
- Damping exponencial (exp(-damping*dt)) en lugar de lineal: mantiene
el feeling consistente independientemente del framerate.
- Sin gravedad: el juego es top-down, no necesita campo de fuerzas
global. Las entidades aplican sus propias fuerzas (thrust).
Pendiente Fase 6:
- Anadir RigidBody body_ a Entity (member, no pointer)
- Migrar Ship: thrust como applyForce, en lugar de velocity_ escalar
- Migrar Enemy: cambios de direccion via applyImpulse, rebotes los
hace PhysicsWorld
- Migrar Bullet: lineal sin damping, restitution=0 (no rebotan)
- Anadir PhysicsWorld a GameScene, registrar bodies, llamar update()
Compila y enlaza. Smoke test xvfb OK: el juego arranca igual que antes
(la nueva infraestructura aun no se invoca).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Primera sub-fase del naming sweep. Punt era un struct sense
operacions, conservat per compatibilitat amb el Pascal original.
Substituit per Vec2, un aggregate amb operadors aritmetics, dot,
length, normalized i length_squared (camelBack: lengthSquared)
seguint les regles del .clang-tidy del projecte.
Canvis:
- core/types.hpp reescrit: nou struct Vec2 amb +=,-=,*=,/=,
unary -, ==, dot, length, lengthSquared, normalized
- Operadors fora de la classe: +, -, *, / (amb float per ambdues
bandes), - unari, ==
- Vec2 segueix sent aggregate (sense constructors definits):
els 'designated initializers' del codi existent funcionen igual:
Vec2{.x = ..., .y = ...}
- Sed global sobre 35 fitxers: tots els 'Punt' -> 'Vec2'
Net: 35 fitxers tocats, +180 / -114. Compila i enllaça.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>