Las balas pasan a ser cinematicas dentro del PhysicsWorld: - body_.setMass(0.5), radius=0 (no colisionan fisicamente) - disparar() setea body_.position + body_.velocity cartesiana (140 px/s) - update() detecta salida del PLAYAREA via body_.position y desactiva - postUpdate() sincroniza center_ desde body_.position - desactivar() detiene el body para evitar deriva mientras inactiva GameScene registra los bodies en init() y llama postUpdate(). El gameplay sigue gestionando colisiones bullet-enemy/bullet-ship con check_collision (el radio gameplay es BULLET_RADIUS=3, expuesto via getCollisionRadius). Renames a camelBack (clang-tidy): get_owner_id->getOwnerId, get_grace_timer->getGraceTimer. MIGRATION_PLAN.md actualizado: Fase 6e cerrada, Fase 7 (SDL3 GPU) siguiente. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.3 KiB
Plan de migración Orni Attack → SDL3 GPU + física vectorial
Documento maestro de la rama rewrite/physics-gpu. Resumen del progreso y
qué queda. Si pierdes el contexto de la sesión, léeme primero.
Visión
Modernizar la base técnica del juego antes de tunear jugabilidad:
- Limpiar legacy (polares, mezcla catalán/inglés, header guards).
- Adoptar formato 16:9 (1280×720).
- Importar subsistemas robustos de AEEA (audio, input deferido).
- Implementar física vectorial 2D con rigid bodies + colisiones elásticas.
- Migrar renderizado a SDL3 GPU sin fallback (memoria: project-no-sdl-fallback).
- Postprocesado y color.
El tuning de feeling se hace al final, post-GPU.
Estado actual
Rama de trabajo: rewrite/physics-gpu (pusheada a Gitea).
Tag de seguridad: beta-3.0 (snapshot de main antes de empezar).
| Fase | Estado | Commits |
|---|---|---|
| 0 — Limpieza de código muerto (primitives, polígonos, Bresenham, polares) | ✅ | 6cf990b |
1a — Punt → Vec2 con operadores modernos |
✅ | cd38101 |
| 1b — Renames de entidades + métodos virtuales a camelBack | ✅ | ae5cc1c |
| 1c — Renames de escenas | ✅ | 5871d29 |
| 1d — Renames effects/stage_system/locales | ✅ | 7ee359b |
| 1e — Pragma once + locales restantes + comentarios castellano | ✅ | bf83f16 |
(fix) — clave YAML quadrat → cuadrado post-sweep |
✅ | 56533ca |
| 2 — Cambio a 1280×720 (16:9) | ✅ | a4f6a55 |
| 3 — Import del subsistema de Audio desde AEEA | ✅ | ed98ef6 |
| 4 — Input parcial AEEA | ⏭️ saltado (decisión usuario) | — |
5 — Infraestructura física (RigidBody, PhysicsWorld) |
✅ | 0fd9360 |
6a+b — body_ en Entity + world_ en GameScene |
✅ | 0574077 |
| 6c — Migrar Ship | ✅ | 2fe22ff |
| 6d — Migrar Enemy | ✅ | 27242f5 |
| 6e — Migrar Bullet | ✅ | (este commit) |
| 7 — Migración a SDL3 GPU (sin fallback) | 🔲 siguiente | — |
| 8 — Postprocesado, color, paleta por tipo | 🔲 | — |
| 9 — Refactor de GameScene (2.877 LOC → módulos) | 🔲 | — |
| 10 — Tuning final de masa/restitución/damping | 🔲 | — |
Lo que queda inmediato (Fase 7)
Migración del renderizado a SDL3 GPU sin fallback.
Fase 6e completada: las balas son cinemáticas dentro del PhysicsWorld (radius=0
en el world → no colisionan físicamente, solo gameplay-level via check_collision).
Body con mass=0.5, restitution=0, damping=0. disparar() setea
body_.position + body_.velocity cartesiana; update() detecta salida de
PLAYAREA y desactiva; postUpdate() sincroniza center_ desde body. Smoke
test xvfb pasa sin errores.
Decisión técnica del proyecto: no fallback a SDL_Renderer
(memoria).
La fase 7 reemplaza completamente el pipeline actual de SDL_Renderer
(SDL_RenderLine, SDL_RenderGeometry) por SDL3 GPU.
Tareas previstas Fase 7:
- Sustituir
SDL_Renderer*porSDL_GPUDevice*en SDLManager. - Setup de swapchain + shaders básicos (vertex + fragment) para líneas vectoriales.
- Migrar
Rendering::render_shapea un pipeline GPU que reciba vertex buffers. - Postprocesado mínimo (Fase 8): bloom/glow, paleta por tipo de entidad.
Fase 10 (tuning) queda pendiente para después de SDL3 GPU + postpro. El usuario prefiere terminar la migración técnica antes de tunear feel.
Memoria del proyecto
Las preferencias y decisiones persistentes están en:
~/.claude/projects/-home-sergio-gitea-orni-attack/memory/MEMORY.md y los
archivos enlazados desde ahí. Léelos al empezar sesión nueva.
Resumen:
- No fallback a SDL_Renderer en Fase 7 — solo GPU o falla.
- Naming:
.clang-tidyexigeCamelCasetipos,camelBackmétodos,lower_case_miembros privados,UPPER_CASEconstantes. - Costuras del título tras 16:9 son tuning artístico, no bug, post-Fase 10.
- Push automático tras cada commit en
rewrite/physics-gpu. - Smoke test xvfb (
timeout 5 xvfb-run -a ./build/orni 2>&1 | head -40) tras builds importantes para validar arranque.
Convenciones técnicas
- Lenguaje código: inglés. Lenguaje comentarios: castellano. Strings de UI: valenciano (preservados).
- Coordenadas: cartesianas (
Vec2). Polares prohibidas (legacy). - Resolución lógica: 1280×720. Constantes en
core/defaults.hpp. - Audio: import de AEEA. API:
Audio::get()->playSound/playMusiccon crossfade y efectos. - Física:
Physics::RigidBodyencore/physics/rigid_body.hpp,Physics::PhysicsWorldencore/physics/physics_world.hpp/.cpp. Entity tienebody_como member. Flujo tri-fase por frame enGameScene::update:physics_world_.update(dt)— integrar y resolverentity.postUpdate(dt)— sincronizar mirror (center_, angle_)- Lógica del juego (input, AI, etc.) — aplica fuerzas/cambia velocity
Cómo reanudar tras compactación
- Lee este archivo.
- Lee
MEMORY.md(memorias persistentes). git log --oneline -20para ver últimos commits.git statuspara ver si hay trabajo en curso sin commitear.- Si la fase actual estaba a medias: continúa donde se quedó (este archivo indica en qué fase estamos).
- Tras cada commit, push automático:
git push origin rewrite/physics-gpu.
Configuración física actual (Fase 6e)
| Entidad | mass | radius (world) | restitution | linear_damping | angular_damping |
|---|---|---|---|---|---|
| Ship | 10.0 | 12 | 0.6 | 1.5 | 0.0 |
| Enemy Pentagon | 5.0 | 20 | 1.0 | 0.0 | 0.0 |
| Enemy Quadrat | 8.0 | 20 | 1.0 | 0.0 | 0.0 |
| Enemy Molinillo | 4.0 | 20 | 1.0 | 0.0 | 0.0 |
| Bullet | 0.5 | 0 (cinemática) | 0 | 0 | 0 |
| Wall (PLAYAREA bounds) | ∞ (estático) | — | — | — | — |
Nota: Bullet usa radius=0 en el body físico para que no participe en las
colisiones del world (ni body-body ni bounds). El radio de gameplay
(Defaults::Entities::BULLET_RADIUS = 3) lo expone vía getCollisionRadius()
y lo consumen check_collision y la detección de salida del PLAYAREA en
Bullet::update.
Las paredes son implícitas: physics_world_.setBounds(PLAYAREA) en
GameScene::init. No son RigidBody separados, sino un AABB que rebota.