Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5.0 KiB
id, title, status, type, domain, scope, priority, depends, blocks, related, created, updated, tags
| id | title | status | type | domain | scope | priority | depends | blocks | related | created | updated | tags | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0072b | gamedev — runtime nucleo (sprite batcher, audio, input, game loop) | pendiente | feature |
|
multi-app | alta |
|
2026-05-10 | 2026-05-17 |
|
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:
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:
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):
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 encore, crearlo
Tests
Cada funcion lleva su test minimo. Uso de --self-test mode en una app de prueba (cpp/apps/runtime_test/) que:
- Inicializa todo
- Carga un sprite
- Carga un sonido
- Simula input
- Corre 100 frames
- 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
- Funciones en registry con
.md+ tests. - App
runtime_testcorre--self-testexit 0 en PC + WASM. - Sprite batcher dibuja 10000 sprites @ 60fps en navegador moderno.
- Audio one-shot sin glitches en PC + WASM.
- 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).