docs(capabilities): unifica tag gamedev en gamedev-2d + separa gamedev-engine
El doctor reportaba el dominio gamedev en doble FAIL: el tag plano `gamedev` (44 funciones) como `ungrouped_candidate` y la pagina `gamedev-2d.md` como `doc_orphan`. Causa raiz: el INDEX declaraba `[gamedev](gamedev-2d.md)` y el auditor solo registra el slug cuando label==target, asi que ni casaba la pagina ni declaraba el tag. Al revisar las 44 funciones habia dos clusters reales bajo el mismo tag, asi que se separan en dos grupos honestos: - gamedev-2d (tag canonico): 31 builders de workflow ComfyUI + 5 de apoyo (post-proceso + puente a Godot) = 36. Se elimina el tag plano `gamedev` de los builders (ya tenian `gamedev-2d`) y se reemplaza por `gamedev-2d` en las de apoyo. - gamedev-engine (grupo nuevo, pagina madre nueva): runtime de juego C++ multiplataforma (SDL3 + sokol_gfx + miniaudio, Issue 0072b) = 8. Game loop, camara 2D, input unificado, sprite batch, setup render/audio, build wasm. El tag plano `gamedev` queda eliminado (count 0). INDEX corregido: fila gamedev-2d con label==target y conteo 36 + fila nueva gamedev-engine (8). Verificacion: `fn index` + `fn doctor capabilities` -> ambos grupos OK (declared_in_index=yes, doc_exists=yes, sin issues); `gamedev` plano = 0. Solo se modifico el campo `tags` de los .md, ningun archivo de codigo. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
# Capability group: `gamedev-engine` — runtime de juego C++ multiplataforma (PC + WebAssembly)
|
||||
|
||||
Cluster de primitivas C++ que forman el núcleo de un runtime de juego 2D portable a
|
||||
escritorio (Windows/Linux/macOS) y navegador (WebAssembly via emscripten). Stack:
|
||||
**SDL3** (ventana + input + GL context) + **sokol_gfx** (render) + **miniaudio**
|
||||
(audio). Nacido del Issue 0072b.
|
||||
|
||||
A diferencia del grupo hermano `gamedev-2d` (generación de *assets* 2D con ComfyUI y
|
||||
puente a Godot), este grupo es el **motor que ejecuta el juego**: el bucle de
|
||||
simulación, la cámara, el input, el render por lotes y el audio. No genera arte; lo
|
||||
consume en tiempo de ejecución.
|
||||
|
||||
Tag: `gamedev-engine`. Filtro: `mcp__registry__fn_search query="" tag="gamedev-engine"`.
|
||||
|
||||
## Funciones del grupo
|
||||
|
||||
| ID | Firma corta | Qué hace | Pureza |
|
||||
|---|---|---|---|
|
||||
| `game_loop_cpp_gamedev` | `loop_run(SDL_Window*, const LoopCfg&) -> void` | Game loop fixed-timestep estilo Glenn Fiedler ("Fix Your Timestep"): desacopla `on_fixed_update` (dt fijo) de `on_render` (factor de interpolación), acumulador con cap anti spiral-of-death. Branch automático desktop (while loop) vs `__EMSCRIPTEN__` (`emscripten_set_main_loop`). | impure |
|
||||
| `input_unified_cpp_gamedev` | `input_begin_frame(InputState&); input_process_event(InputState&, const SDL_Event*)` | Snapshot unificado de input por frame para SDL3: mapea teclado (WASD+flechas), ratón, gamepad y touch a botones lógicos (left/right/up/down/action_a..y/start/back) y ejes analógicos, con flags `*_pressed` de rising edge limpio. | impure |
|
||||
| `camera_2d_cpp_gamedev` | `world_to_screen / screen_to_world(Camera2D, Vec2) -> Vec2; visible_world_rect(Camera2D) -> Rect; view_proj_matrix(Camera2D, float[16])` | Cámara ortográfica 2D pura (pos centro, zoom, rotación, viewport): conversiones world↔screen, AABB visible y matriz view-projection 4×4 column-major lista para cualquier renderer. Fast-path sin trig si `rotation==0`. | pure |
|
||||
| `sokol_setup_cpp_gfx` | `make_environment() -> sg_environment; make_swapchain(int w, int h) -> sg_swapchain` | Builders puros para inicializar sokol_gfx sobre un GL context creado por SDL3 (no por sokol_app): `sg_environment` con defaults RGBA8 + depth/stencil y `sg_swapchain` del default framebuffer del contexto activo. | pure |
|
||||
| `sprite_batch_cpp_gfx` | `sprite_batch_create(int cap=4096) -> SpriteBatch; sprite_batch_begin/draw/end` | Batched textured quad renderer sobre sokol_gfx: begin/draw/end con auto-flush por cambio de atlas o capacidad llena. Vertex layout pos+uv+color, alpha blending estándar, GLSL 330 / GLES 300. Base de plataformeros, top-down y UI sprites. | impure |
|
||||
| `audio_engine_cpp_gamedev` | `engine_init() -> Engine; engine_shutdown(Engine&); engine_set_volume(Engine&, float)` | Lifecycle del engine de audio basado en miniaudio (single-header, public domain): inicializa device default, master volume, libera recursos. Cross-platform (WASAPI/ALSA/CoreAudio y WebAudio bajo emscripten). Única TU que define `MINIAUDIO_IMPLEMENTATION`. | impure |
|
||||
| `audio_play_cpp_gamedev` | `sound_load(Engine&, const char*) -> Sound; sound_play/stop/set_volume/destroy(Sound&); play_sound_oneshot(Engine&, const char*, float)` | Reproducción de audio sobre `fn::audio::Engine`: carga con streaming desde disco (wav/mp3/flac/ogg), play/stop/volumen por sonido, y helper fire-and-forget para one-shots sin handle. | impure |
|
||||
| `build_wasm_cpp_app_bash_infra` | `build_wasm_cpp_app(app_name, [--no-budget-check]) -> void` | Compila una app C++ del registry (`cpp/apps/<name>`) a WebAssembly via emscripten. Produce `build/wasm/<name>/<name>.{html,js,wasm,wasm.gz}`. Falla si el gzip supera 2 MB (budget). | impure |
|
||||
|
||||
## Ejemplo canónico (esqueleto de un juego 2D)
|
||||
|
||||
Las primitivas se componen así dentro del `main()` de una app C++ del registry. Cada
|
||||
identificador (`fn::game_loop`, `fn::input`, `fn::camera2d`, `fn::gfx`, `fn::audio`)
|
||||
proviene de la función homónima del registry; la app solo aporta la lógica de juego.
|
||||
|
||||
```cpp
|
||||
// 1. Ventana + GL context con SDL3, sokol_gfx encima (sokol_setup)
|
||||
sg_setup(...); // usa make_environment() del registry
|
||||
auto swap = fn::gfx::make_swapchain(W, H);
|
||||
auto batch = fn::gfx::sprite_batch_create(4096);
|
||||
auto audio = fn::audio::engine_init();
|
||||
fn::audio::play_sound_oneshot(audio, "assets/music.ogg", 0.6f);
|
||||
|
||||
// 2. Estado de cámara e input
|
||||
fn::game::Camera2D cam{ .pos = {0,0}, .zoom = 1.0f, .viewport = {W, H} };
|
||||
fn::input::InputState in{};
|
||||
|
||||
// 3. Game loop fixed-timestep: simulación e interpolación desacopladas
|
||||
fn::game::LoopCfg cfg{
|
||||
.on_event = [&](const SDL_Event* e){ fn::input::input_process_event(in, e); },
|
||||
.on_fixed_update = [&](float dt){ /* mover entidades usando in.left_pressed... */ },
|
||||
.on_render = [&](float alpha){
|
||||
fn::gfx::sprite_batch_begin(batch);
|
||||
// draw sprites con cam.view_proj_matrix(...) como transform
|
||||
fn::gfx::sprite_batch_end(batch);
|
||||
},
|
||||
};
|
||||
fn::game::loop_run(window, cfg);
|
||||
|
||||
// 4. Distribuir a navegador: build_wasm_cpp_app "<app>" -> build/wasm/<app>/
|
||||
```
|
||||
|
||||
## Fronteras (qué NO cubre)
|
||||
|
||||
- **Generación de assets** (sprites, tiles, VFX): es el grupo hermano `gamedev-2d`
|
||||
(ComfyUI → post-proceso → Godot). Este grupo solo los *renderiza* en runtime.
|
||||
- **Física / colisiones / ECS**: no incluidos. El `on_fixed_update` recibe el dt fijo;
|
||||
la simulación la pone la app.
|
||||
- **TileSet / mapas / escenas**: no hay sistema de niveles; `sprite_batch` dibuja quads
|
||||
sueltos.
|
||||
- **App end-to-end consumidora**: a fecha de hoy estas primitivas son el núcleo del
|
||||
runtime (Issue 0072b) pero **no hay todavía una app C++ que las componga end-to-end**
|
||||
(varias están marcadas `pendiente-usar`). El ejemplo de arriba es el esqueleto
|
||||
previsto, no un binario validado. Cuando exista la primera app, su `app.md`
|
||||
declarará estas IDs en `uses_functions` y servirá de validación e2e.
|
||||
|
||||
## Prerequisitos / notas
|
||||
|
||||
- **SDL3** para ventana + input + GL context; **sokol_gfx** (vendored en `cpp/vendor/`)
|
||||
para render; **miniaudio** (single-header) para audio.
|
||||
- Target nativo: GLSL 330. Target WebAssembly (emscripten): GLES 300 — `sprite_batch`
|
||||
emite ambos shaders.
|
||||
- `build_wasm_cpp_app` exige el SDK de emscripten en el entorno y respeta un budget de
|
||||
2 MB gzip por defecto (`--no-budget-check` para saltarlo).
|
||||
Reference in New Issue
Block a user