feat(kotlin-compose): design system + 33 components + gallery_kt + e2e android emulator + scaffolder fixes

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-11 16:28:50 +02:00
parent 0bdb8454e1
commit cb6d9e61d1
152 changed files with 148262 additions and 25 deletions
+168
View File
@@ -0,0 +1,168 @@
---
id: 0072b
title: gamedev — runtime nucleo (sprite batcher, audio, input, game loop)
status: pending
priority: high
created: 2026-05-10
tags: [gamedev, cpp]
parent_issue: 0072
depends_on: [0072a]
---
## Objetivo
Implementar el runtime minimo necesario para hacer un juego 2D jugable: dibujar muchos sprites por frame, reproducir audio, leer input unificado (kb/gamepad/touch), y un game loop con fixed timestep.
Todo en `cpp/functions/gfx/` y `cpp/functions/gamedev/` (dominio nuevo) como funciones del registry, NO empotrado en una app concreta. Apps consumidoras importan via `uses_functions`.
## Funciones a crear
### Graphics (sokol_gfx wrappers)
| Funcion | Lang | Domain | Purity | Proposito |
|---|---|---|---|---|
| `sg_init` | cpp | gfx | impure | Inicializa sokol_gfx con SDL3 GL context |
| `sg_shader_load` | cpp | gfx | impure | Compila vertex+fragment, devuelve `sg_shader` |
| `sg_pipeline_create` | cpp | gfx | impure | Crea `sg_pipeline` con layout estandar (pos, uv, color) |
| `sg_image_load` | cpp | gfx | impure | stb_image → `sg_image` con mipmaps opcionales |
| `sg_buffer_create` | cpp | gfx | impure | Vertex/index buffers static o stream |
### Sprite batcher
`sprite_batch_cpp_gfx` (impure). API:
```cpp
struct SpriteBatch {
sg_pipeline pipeline;
sg_buffer vbo; // dynamic, ~64K vertices
sg_buffer ibo;
std::vector<Vertex> cpu_verts;
sg_image current_atlas;
};
void sprite_batch_begin(SpriteBatch& b, const Camera2D& cam);
void sprite_batch_draw(SpriteBatch& b, sg_image atlas, Rect src, Rect dst, Color tint, float rotation);
void sprite_batch_end(SpriteBatch& b); // flush draw call
```
Auto-flush cuando cambia atlas o se llena CPU buffer.
### Audio (miniaudio wrappers)
| Funcion | Domain | Proposito |
|---|---|---|
| `audio_init` | gamedev | Inicializa miniaudio engine |
| `audio_load_sound` | gamedev | wav/ogg/mp3 → sound handle |
| `audio_play_sound` | gamedev | Reproduce one-shot con volumen/pan/pitch |
| `audio_play_music` | gamedev | Streaming + loop |
| `audio_set_listener` | gamedev | Posicion 2D para audio espacial |
### Input unificado
`input_unified_cpp_gamedev` (impure). Abstrae kb/mouse/gamepad/touch en un mismo struct:
```cpp
struct InputState {
// Buttons logicos del juego
bool left, right, up, down;
bool action_a, action_b, action_x, action_y;
bool start, back;
// Analogicos (-1..1)
float lx, ly, rx, ry;
// Touch (mobile/web)
struct Touch { float x, y; bool pressed; } touches[8];
int touch_count;
// Mouse
float mx, my;
bool m_left, m_right;
};
void input_poll(InputState& s, const SDL_Event* events, int count);
```
Mapping: keyboard WASD/arrows + space/enter, gamepad SDL3 standard mapping, touch via virtual gamepad overlay (en sub-issue 0072g).
### Game loop
`game_loop_cpp_gamedev` (impure):
```cpp
struct GameLoopCfg {
float fixed_dt; // 1/60 default
int max_steps_per_frame; // 5 default (evita spiral of death)
void (*on_fixed_update)(void* user, float dt);
void (*on_render)(void* user, float interp);
void* user;
};
void game_loop_run(SDL_Window* w, const GameLoopCfg& cfg);
```
Fixed timestep con interpolacion para render (clasico Glenn Fiedler). En WASM usa `emscripten_set_main_loop`.
### Camara 2D
`camera_2d_cpp_gamedev` (pure). Struct + helpers para world↔screen, zoom, follow, shake.
## Estructura
```
cpp/functions/gfx/
sg_init.{cpp,h,md}
sg_shader_load.{cpp,h,md}
sg_pipeline_create.{cpp,h,md}
sg_image_load.{cpp,h,md}
sg_buffer_create.{cpp,h,md}
sprite_batch.{cpp,h,md}
cpp/functions/gamedev/ # Dominio nuevo
audio_init.{cpp,h,md}
audio_load_sound.{cpp,h,md}
audio_play_sound.{cpp,h,md}
audio_play_music.{cpp,h,md}
audio_set_listener.{cpp,h,md}
input_unified.{cpp,h,md}
game_loop.{cpp,h,md}
camera_2d.{cpp,h,md}
```
Registrar dominio `gamedev` en `cpp/CMakeLists.txt` y en docs del registry.
## Tipos del registry
`cpp/types/gamedev/`:
- `SpriteBatch` (product)
- `InputState` (product)
- `Camera2D` (product)
- `Color` (product, `{r,g,b,a}` floats)
- `Rect` (product, `{x,y,w,h}`)
- `Vec2` (product) — si no existe ya en `core`, crearlo
## Tests
Cada funcion lleva su test minimo. Uso de `--self-test` mode en una app de prueba (`cpp/apps/runtime_test/`) que:
1. Inicializa todo
2. Carga un sprite
3. Carga un sonido
4. Simula input
5. Corre 100 frames
6. Sale con codigo 0 si nada explota
## Tamaño
Budget: este sub-issue añade ≤ 600 KB al WASM gzip (miniaudio + sokol_gfx + box2d aun no + imgui ya contado en 0072a).
## Criterio de exito
- [x] Funciones en registry con `.md` + tests.
- [x] App `runtime_test` corre `--self-test` exit 0 en PC + WASM.
- [x] Sprite batcher dibuja 10000 sprites @ 60fps en navegador moderno.
- [x] Audio one-shot sin glitches en PC + WASM.
- [x] Input unificado funciona con kb + gamepad (touch en 0072g).
## No-objetivos
- Animacion de sprites (sub-issue futuro o parte de 0072k demo).
- Tilemap (en 0072c).
- Physics (en 0072j).
- Particles (sub-issue futuro).