Files
fn_registry/dev/issues/0072b-gamedev-runtime-core.md

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
gamedev
multi-app alta
0072a
2026-05-10 2026-05-17
gamedev
cpp

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 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

  • Funciones en registry con .md + tests.
  • App runtime_test corre --self-test exit 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).