diff options
| author | Gene Pasquet <dev@etenil.net> | 2026-04-05 23:12:54 +0100 |
|---|---|---|
| committer | Gene Pasquet <dev@etenil.net> | 2026-04-05 23:12:54 +0100 |
| commit | b99ada53b715def5492c7d04c0d327fa7048e5d3 (patch) | |
| tree | 9e94dbc8ff863ef09ef18f4be31fb45e085572a4 /docs/api.org | |
| parent | 027053b11a3a5d861ed2fa2db245388bd95ac246 (diff) | |
Complete implementation
Diffstat (limited to 'docs/api.org')
| -rw-r--r-- | docs/api.org | 846 |
1 files changed, 846 insertions, 0 deletions
diff --git a/docs/api.org b/docs/api.org new file mode 100644 index 0000000..0a443d6 --- /dev/null +++ b/docs/api.org @@ -0,0 +1,846 @@ +#+TITLE: Downstroke API Reference + +This document describes the public API for the Downstroke game engine. All exported functions are organized by module. + +* Engine (~downstroke/engine~) + +#+begin_src scheme +(import downstroke/engine) +#+end_src + +The engine module provides the top-level game lifecycle and state management. + +** ~make-game~ + +#+begin_src scheme +(make-game #!key + (title "Downstroke Game") + (width 640) + (height 480) + (frame-delay 16) + (input-config *default-input-config*) + (preload #f) + (create #f) + (update #f) + (render #f)) +#+end_src + +Creates and initializes a game object. All parameters are optional keywords. + +| Parameter | Type | Default | Description | +|-----------+------+---------+-------------| +| ~title~ | string | "Downstroke Game" | Window title | +| ~width~ | integer | 640 | Game window width in pixels | +| ~height~ | integer | 480 | Game window height in pixels | +| ~frame-delay~ | integer | 16 | Delay between frames in milliseconds (30 FPS ≈ 33) | +| ~input-config~ | input-config | *default-input-config* | Keyboard/controller mappings | +| ~preload~ | procedure/false | #f | Hook: ~(lambda (game) ...)~ called once before create | +| ~create~ | procedure/false | #f | Hook: ~(lambda (game) ...)~ called once at startup | +| ~update~ | procedure/false | #f | Hook: ~(lambda (game dt) ...)~ called each frame | +| ~render~ | procedure/false | #f | Hook: ~(lambda (game) ...)~ called after render-scene! | + +The game object is the central hub. Use it to store/retrieve assets, manage scenes, and access the current input state. + +** ~game-run!~ + +#+begin_src scheme +(game-run! game) +#+end_src + +Starts the main event loop. Initializes SDL2, opens the window, and runs the frame loop indefinitely until the user quits or the ~quit~ action is pressed. Never returns. + +Lifecycle order within each frame: +1. Collect SDL2 events +2. Update input state +3. Call ~update:~ hook (or active state's ~update~) +4. Clear renderer +5. Call ~render-scene!~ (if scene is set) +6. Call ~render:~ hook (or active state's ~render~) +7. Present renderer +8. Apply frame delay + +** ~game-camera~ + +#+begin_src scheme +(game-camera game) +#+end_src + +Returns the current scene's camera struct. Only valid after ~create:~ runs. Returns a camera record with ~x~ and ~y~ fields for the top-left viewport corner in world coordinates. + +** ~game-asset~ + +#+begin_src scheme +(game-asset game key) +#+end_src + +Retrieves an asset from the game's registry by key. Returns ~#f~ if the key is not found. + +** ~game-asset-set!~ + +#+begin_src scheme +(game-asset-set! game key value) +#+end_src + +Stores an asset in the game's registry. Overwrites any existing value at the key. + +** ~make-game-state~ + +#+begin_src scheme +(make-game-state #!key (create #f) (update #f) (render #f)) +#+end_src + +Creates a state record (plist) with optional lifecycle hooks. Used with ~game-add-state!~ and ~game-start-state!~ to build a state machine within the game. + +| Parameter | Type | Default | Description | +|-----------+------+---------+-------------| +| ~create~ | procedure/false | #f | Called when entering this state | +| ~update~ | procedure/false | #f | Called each frame while active | +| ~render~ | procedure/false | #f | Called each frame after rendering (overlay) | + +** ~game-add-state!~ + +#+begin_src scheme +(game-add-state! game name state) +#+end_src + +Registers a named state (created with ~make-game-state~) in the game's state table. ~name~ must be a symbol. + +** ~game-start-state!~ + +#+begin_src scheme +(game-start-state! game name) +#+end_src + +Transitions to a named state, activating its lifecycle hooks. Calls the state's ~create:~ hook (if present) immediately. + +** Example: Game with State Machine + +#+begin_src scheme +(define my-game (make-game title: "My Game")) + +(game-add-state! my-game 'playing + (make-game-state + create: (lambda (game) (print "Game started")) + update: (lambda (game dt) (print "Updating...")) + render: (lambda (game) (print "Rendering overlay")))) + +(game-add-state! my-game 'paused + (make-game-state + create: (lambda (game) (print "Paused")))) + +; Start the game in 'playing state +(game-start-state! my-game 'playing) + +; Later, transition to paused +(game-start-state! my-game 'paused) +#+end_src + +* World (~downstroke/world~) + +#+begin_src scheme +(import downstroke/world) +#+end_src + +The world module provides the scene (level) abstraction and camera management. + +** ~make-scene~ + +Auto-generated by defstruct. Use keyword arguments: + +#+begin_src scheme +(make-scene #!key + (entities '()) + (tilemap #f) + (camera #f) + (tileset-texture #f)) +#+end_src + +Creates a scene record representing the current level state. + +| Parameter | Type | Default | Description | +|-----------+------+---------+-------------| +| ~entities~ | list | ~'()~ | List of entity plists | +| ~tilemap~ | tilemap/false | #f | Tile grid and collisions | +| ~camera~ | camera/false | #f | Viewport position | +| ~tileset-texture~ | SDL2 texture/false | #f | Rendered tileset image | + +** ~make-camera~ + +Auto-generated by defstruct. Use keyword arguments: + +#+begin_src scheme +(make-camera #!key (x 0) (y 0)) +#+end_src + +Creates a camera record. ~x~ and ~y~ are the pixel coordinates of the viewport's top-left corner in world space. + +** ~camera-x~, ~camera-y~ + +#+begin_src scheme +(camera-x camera) +(camera-y camera) +#+end_src + +Accessors for camera position. + +** ~camera-x-set!~, ~camera-y-set!~ + +#+begin_src scheme +(camera-x-set! camera x) +(camera-y-set! camera y) +#+end_src + +Mutate camera position (in-place). + +** ~camera-follow!~ + +#+begin_src scheme +(camera-follow! camera entity viewport-w viewport-h) +#+end_src + +Centers the camera on an entity, clamping to stay within world bounds (never negative). ~viewport-w~ and ~viewport-h~ are the game window dimensions. + +** ~scene-add-entity~ + +#+begin_src scheme +(scene-add-entity scene entity) +#+end_src + +Appends an entity to the scene's entity list. Returns the modified scene. + +** ~scene-update-entities~ + +#+begin_src scheme +(scene-update-entities scene proc1 proc2 ...) +#+end_src + +Applies each procedure in sequence to all entities in the scene. Each procedure takes a single entity and returns a modified entity. The scene's entity list is updated once with the final result. Returns the modified scene. + +Example: + +#+begin_src scheme +(define (increment-x entity) + (entity-set entity #:x (+ 1 (entity-ref entity #:x 0)))) + +(define (apply-gravity entity) + (entity-set entity #:vy (+ 1 (entity-ref entity #:vy 0)))) + +(scene-update-entities scene increment-x apply-gravity) +; Each entity is passed through increment-x, then through apply-gravity +#+end_src + +** ~scene-filter-entities~ + +#+begin_src scheme +(scene-filter-entities scene predicate) +#+end_src + +Removes all entities that do not satisfy the predicate. Returns the modified scene. + +Example: + +#+begin_src scheme +; Remove all entities with type 'enemy +(scene-filter-entities scene + (lambda (e) (not (eq? (entity-type e) 'enemy)))) +#+end_src + +** ~scene-find-tagged~ + +#+begin_src scheme +(scene-find-tagged scene tag) +#+end_src + +Returns the first entity whose ~#:tags~ list (a list of symbols) contains the given tag, or ~#f~ if not found. + +** ~scene-find-all-tagged~ + +#+begin_src scheme +(scene-find-all-tagged scene tag) +#+end_src + +Returns a list of all entities whose ~#:tags~ list contains the given tag. Returns ~'()~ if none found. + +** Accessor functions (auto-generated by defstruct) + +- ~scene-entities~, ~scene-entities-set!~ +- ~scene-tilemap~, ~scene-tilemap-set!~ +- ~scene-camera~, ~scene-camera-set!~ +- ~scene-tileset-texture~, ~scene-tileset-texture-set!~ + +* Entity (~downstroke/entity~) + +#+begin_src scheme +(import downstroke/entity) +#+end_src + +The entity module provides property list (plist) accessors for game objects. Entities are immutable plists, never modified in place. + +** ~entity-ref~ + +#+begin_src scheme +(entity-ref entity key #!optional default) +#+end_src + +Retrieves the value of a key from an entity plist. Returns ~default~ (or ~#f~) if the key is not found. If ~default~ is a procedure, it is called with no arguments to produce the default. + +Example: + +#+begin_src scheme +(entity-ref player #:x 0) ; Get x, defaulting to 0 +(entity-ref player #:tags '()) ; Get tags, defaulting to empty list +#+end_src + +** ~entity-type~ + +#+begin_src scheme +(entity-type entity) +#+end_src + +Shorthand for ~(entity-ref entity #:type #f)~. Returns the entity's ~#:type~ field or ~#f~. + +** ~entity-set~ + +#+begin_src scheme +(entity-set entity key value) +#+end_src + +Returns a new plist with the key/value updated. **Does not modify the original entity.** This is a functional (immutable) operation. + +Example: + +#+begin_src scheme +(define player (list #:x 100 #:y 200 #:type 'player)) +(define moved (entity-set player #:x 150)) +; player is still (list #:x 100 #:y 200 #:type 'player) +; moved is (list #:x 150 #:y 200 #:type 'player) +#+end_src + +** ~entity-update~ + +#+begin_src scheme +(entity-update entity key proc #!optional default) +#+end_src + +Functional update: applies ~proc~ to the current value of ~key~ and updates the entity with the result. Returns a new plist. + +Example: + +#+begin_src scheme +(entity-update player #:x (lambda (x) (+ x 10))) +; Equivalent to (entity-set player #:x (+ 10 (entity-ref player #:x 0))) +#+end_src + +** Shared Entity Keys + +All entities can have these keys. Not all are required: + +| Key | Type | Description | +|-----|------|-------------| +| ~#:type~ | symbol | Entity type (e.g., 'player, 'enemy) | +| ~#:x~ | number | X position in pixels | +| ~#:y~ | number | Y position in pixels | +| ~#:width~ | number | Bounding box width in pixels | +| ~#:height~ | number | Bounding box height in pixels | +| ~#:vx~ | number | X velocity in pixels/frame | +| ~#:vy~ | number | Y velocity in pixels/frame | +| ~#:tile-id~ | integer | Sprite index in tileset (1-indexed) | +| ~#:tags~ | list | List of symbols for lookup (e.g., '(player)) | +| ~#:gravity?~ | boolean | Apply gravity to this entity? | +| ~#:on-ground?~ | boolean | Is entity touching a solid tile below? | +| ~#:facing~ | integer | 1 (right) or -1 (left) | +| ~#:solid?~ | boolean | Participate in AABB entity collisions? | +| ~#:anim-name~ | symbol | Current animation name | +| ~#:anim-frame~ | integer | Current frame index | +| ~#:anim-tick~ | integer | Ticks in current frame | + +* Physics (~downstroke/physics~) + +#+begin_src scheme +(import downstroke/physics) +#+end_src + +The physics module implements the main collision and movement pipeline. The physics pipeline runs automatically before the user's ~update:~ hook. + +** Physics Pipeline Order + +The built-in physics runs in this order each frame: + +1. ~apply-acceleration~ — consume ~#:ay~ into ~#:vy~ +2. ~apply-gravity~ — add gravity to ~#:vy~ +3. ~apply-velocity-x~ — move by ~#:vx~ +4. ~resolve-tile-collisions-x~ — snap against horizontal tile collisions +5. ~apply-velocity-y~ — move by ~#:vy~ +6. ~resolve-tile-collisions-y~ — snap against vertical tile collisions +7. ~detect-ground~ — set ~#:on-ground?~ if standing on a tile + +(This separation ensures smooth sliding along walls.) + +** ~apply-acceleration~ + +#+begin_src scheme +(apply-acceleration entity) +#+end_src + +Consumes ~#:ay~ (one-shot acceleration) into ~#:vy~ and clears ~#:ay~ to 0. Only applies if ~#:gravity?~ is true. + +** ~apply-gravity~ + +#+begin_src scheme +(apply-gravity entity) +#+end_src + +Adds the gravity constant (1 pixel/frame²) to ~#:vy~. Only applies if ~#:gravity?~ is true. + +** ~apply-velocity-x~ + +#+begin_src scheme +(apply-velocity-x entity) +#+end_src + +Updates ~#:x~ by adding ~#:vx~. Returns a new entity. + +** ~apply-velocity-y~ + +#+begin_src scheme +(apply-velocity-y entity) +#+end_src + +Updates ~#:y~ by adding ~#:vy~. Returns a new entity. + +** ~apply-velocity~ + +#+begin_src scheme +(apply-velocity entity) +#+end_src + +Legacy function: updates both ~#:x~ and ~#:y~ by their respective velocities. + +** ~resolve-tile-collisions-x~ + +#+begin_src scheme +(resolve-tile-collisions-x entity tilemap) +#+end_src + +Detects and resolves collisions between the entity's bounding box and solid tiles along the X axis. Snaps the entity's ~#:x~ to the near/far tile edge and sets ~#:vx~ to 0. Returns a new entity. + +** ~resolve-tile-collisions-y~ + +#+begin_src scheme +(resolve-tile-collisions-y entity tilemap) +#+end_src + +Detects and resolves collisions between the entity's bounding box and solid tiles along the Y axis. Snaps the entity's ~#:y~ to the near/far tile edge and sets ~#:vy~ to 0. Returns a new entity. + +** ~detect-ground~ + +#+begin_src scheme +(detect-ground entity tilemap) +#+end_src + +Probes one pixel below the entity's feet to detect if it is standing on a solid tile. Sets ~#:on-ground?~ to true or false. Only applies if ~#:gravity?~ is true. Returns a new entity. + +** ~apply-jump~ + +#+begin_src scheme +(apply-jump entity jump-pressed?) +#+end_src + +If the jump button is pressed and the entity is on ground, sets ~#:ay~ to ~(- #:jump-force)~ (default 15 pixels/frame). On the next frame, ~apply-acceleration~ consumes this into ~#:vy~. Returns a new entity. + +** ~resolve-entity-collisions~ + +#+begin_src scheme +(resolve-entity-collisions entities) +#+end_src + +Detects and resolves AABB collisions between all pairs of entities with ~#:solid?~ true. Pushes overlapping entities apart along the axis of minimum penetration and sets their velocities in the push direction. Returns a new entity list. + +** ~scene-resolve-collisions~ + +#+begin_src scheme +(scene-resolve-collisions scene) +#+end_src + +Applies ~resolve-entity-collisions~ to the scene's entity list. Returns the modified scene. + +** Physics Constants + +- ~*gravity*~ = 1 (pixels per frame per frame) +- ~*jump-force*~ = 15 (vertical acceleration on jump) + +* Input (~downstroke/input~) + +#+begin_src scheme +(import downstroke/input) +#+end_src + +The input module handles keyboard, joystick, and game controller events. It maintains the current and previous input state to support pressed/released detection. + +** ~*default-input-config*~ + +The default input configuration record. Use as the ~input-config:~ parameter to ~make-game~, or create a custom one with ~make-input-config~. + +| Action | Keyboard | Joystick | Controller | +|--------|----------|----------|------------| +| ~up~ | W or Up | Y-axis negative | DPad Up, Left-Y negative | +| ~down~ | S or Down | Y-axis positive | DPad Down, Left-Y positive | +| ~left~ | A or Left | X-axis negative | DPad Left, Left-X negative | +| ~right~ | D or Right | X-axis positive | DPad Right, Left-X positive | +| ~a~ | J or Z | Button 0 | A button | +| ~b~ | K or X | Button 1 | B button | +| ~start~ | Return | Button 7 | Start button | +| ~select~ | (unmapped) | Button 6 | Back button | +| ~quit~ | Escape | (unmapped) | (unmapped) | + +** ~input-held?~ + +#+begin_src scheme +(input-held? state action) +#+end_src + +Returns true if the action is currently held down. ~action~ is a symbol like ~'left~ or ~'a~. + +** ~input-pressed?~ + +#+begin_src scheme +(input-pressed? state action) +#+end_src + +Returns true if the action was pressed in this frame (held now but not in the previous frame). + +** ~input-released?~ + +#+begin_src scheme +(input-released? state action) +#+end_src + +Returns true if the action was released in this frame (held previously but not now). + +** ~create-input-state~ + +#+begin_src scheme +(create-input-state config) +#+end_src + +Initializes an input state record from a configuration. All actions start as unpressed. + +** Example: Player Movement + +#+begin_src scheme +(define (update-player game dt) + (let ((input (game-input game)) + (player (car (scene-entities (game-scene game))))) + (if (input-pressed? input 'a) + (apply-jump player #t) + player))) +#+end_src + +* Renderer (~downstroke/renderer~) + +#+begin_src scheme +(import downstroke/renderer) +#+end_src + +The renderer module provides SDL2 drawing abstractions. + +** ~render-scene!~ + +#+begin_src scheme +(render-scene! renderer scene) +#+end_src + +Draws the entire scene: first the tilemap layers, then all entities. Called automatically by ~game-run!~ before the user's ~render:~ hook. Does nothing if the scene is ~#f~. + +** ~entity-screen-coords~ + +#+begin_src scheme +(entity-screen-coords entity camera) +#+end_src + +Returns a list ~(x y width height)~ of the entity's bounding box in screen (viewport) coordinates. Pure function, testable without SDL2. + +Example: + +#+begin_src scheme +(entity-screen-coords player (make-camera x: 100 y: 50)) +; If player is at world (200, 100) with size (16, 16): +; Returns (100 50 16 16) -- offset by camera position +#+end_src + +** ~entity-flip~ + +#+begin_src scheme +(entity-flip entity) +#+end_src + +Returns an SDL2 flip list based on the entity's ~#:facing~ field. Returns ~'(horizontal)~ if facing is -1, ~'()~ otherwise. + +** ~draw-ui-text~ + +#+begin_src scheme +(draw-ui-text renderer font text color x y) +#+end_src + +Renders a single line of text to the screen at the given pixel coordinates. ~color~ is an SDL2 color struct. Positions are in screen (viewport) space, not world space. Does not cache; call once per frame for each text element. + +* Assets (~downstroke/assets~) + +#+begin_src scheme +(import downstroke/assets) +#+end_src + +The assets module provides a simple registry for game resources. + +** ~make-asset-registry~ + +#+begin_src scheme +(make-asset-registry) +#+end_src + +Creates an empty asset registry (hash-table). Returned by ~make-game~ automatically. + +** ~asset-set!~ + +#+begin_src scheme +(asset-set! registry key value) +#+end_src + +Stores a value in the registry by key (any hashable value). Overwrites any existing value. + +** ~asset-ref~ + +#+begin_src scheme +(asset-ref registry key) +#+end_src + +Retrieves a value from the registry by key. Returns ~#f~ if not found. + +** Example: Storing Fonts + +#+begin_src scheme +(define (preload game) + (let ((font (ttf:open-font "assets/font.ttf" 16))) + (game-asset-set! game 'main-font font))) + +(define (render-overlay game) + (let ((font (game-asset game 'main-font))) + (draw-ui-text (game-renderer game) font "Score: 100" + (sdl2:make-color 255 255 255) 10 10))) +#+end_src + +* Sound (~downstroke/sound~) + +#+begin_src scheme +(import downstroke/sound) +#+end_src + +The sound module provides music and sound effect playback via SDL_mixer. + +** ~init-audio!~ + +#+begin_src scheme +(init-audio!) +#+end_src + +Initializes SDL_mixer with default settings (44100 Hz, stereo, 512 buffer). Call once in the ~preload:~ hook. + +** ~load-sounds!~ + +#+begin_src scheme +(load-sounds! sound-alist) +#+end_src + +Loads sound effects from an alist of ~(name . path)~ pairs, where ~name~ is a symbol and ~path~ is a file path. Stores them globally for playback. + +Example: + +#+begin_src scheme +(load-sounds! '((jump . "assets/jump.wav") + (hit . "assets/hit.wav"))) +#+end_src + +** ~play-sound~ + +#+begin_src scheme +(play-sound name) +#+end_src + +Plays a loaded sound effect by name (symbol). Plays on the first available channel. No-op if the sound is not found. + +** ~load-music!~ + +#+begin_src scheme +(load-music! path) +#+end_src + +Loads background music from a file. Replaces any previously loaded music. + +** ~play-music!~ + +#+begin_src scheme +(play-music! volume) +#+end_src + +Plays the loaded music on an infinite loop. ~volume~ is a number from 0.0 to 1.0. + +** ~stop-music!~ + +#+begin_src scheme +(stop-music!) +#+end_src + +Stops the currently playing music immediately. + +** ~set-music-volume!~ + +#+begin_src scheme +(set-music-volume! volume) +#+end_src + +Changes the music volume while it is playing. ~volume~ is 0.0 to 1.0. + +** ~cleanup-audio!~ + +#+begin_src scheme +(cleanup-audio!) +#+end_src + +Releases all audio resources. Call at shutdown or in a cleanup hook. + +* Animation (~downstroke/animation~) + +#+begin_src scheme +(import downstroke/animation) +#+end_src + +The animation module provides simple frame-based sprite animation. + +** ~set-animation~ + +#+begin_src scheme +(set-animation entity name) +#+end_src + +Switches the entity to a named animation, resetting frame and tick counters to 0. No-op if the animation is already active (prevents restarting mid-loop). Returns a new entity. + +** ~animate-entity~ + +#+begin_src scheme +(animate-entity entity animations) +#+end_src + +Advances the entity's animation frame based on elapsed ticks. ~animations~ is an alist of ~(name . animation-plist)~ pairs. Each animation plist has ~#:frames~ (list of tile IDs, 0-indexed) and ~#:duration~ (ticks per frame). Returns a new entity with updated ~#:anim-tick~, ~#:anim-frame~, and ~#:tile-id~. + +Example: + +#+begin_src scheme +(define player-animations + '((idle #:frames (28) #:duration 10) + (walk #:frames (27 28) #:duration 10) + (jump #:frames (29) #:duration 1))) + +(define player (list #:anim-name 'walk #:anim-frame 0 #:anim-tick 0)) +(animate-entity player player-animations) +; After 10 ticks, frame advances to 1 (wraps to 0 after reaching length) +#+end_src + +** ~frame->tile-id~ + +#+begin_src scheme +(frame->tile-id frames frame-idx) +#+end_src + +Converts a frame index to a tile ID (1-indexed). Used internally by ~animate-entity~. + +* Scene Loader (~downstroke/scene-loader~) + +#+begin_src scheme +(import downstroke/scene-loader) +#+end_src + +The scene-loader module provides utilities for loading Tiled maps and instantiating entities from prefabs. + +** ~game-load-scene!~ + +#+begin_src scheme +(game-load-scene! game filename) +#+end_src + +Loads a TMX (Tiled) map from a file and creates a scene. Steps: + +1. Loads the tilemap from the file +2. Creates an SDL2 texture from the tileset image +3. Creates an empty scene with the tilemap and camera +4. Stores the tilemap in game assets under key ~'tilemap~ +5. Sets the scene on the game +6. Returns the scene + +Example: + +#+begin_src scheme +(define (create-game game) + (game-load-scene! game "assets/level1.tmx") + ; Now add entities to the scene... + ) +#+end_src + +** ~create-tileset-texture~ + +#+begin_src scheme +(create-tileset-texture renderer tilemap) +#+end_src + +Creates an SDL2 texture from the tileset image embedded in a tilemap struct. Useful when you need the texture independently of ~game-load-scene!~. + +** ~make-prefab-registry~ + +#+begin_src scheme +(make-prefab-registry name1 constructor1 name2 constructor2 ...) +#+end_src + +Creates a hash-table mapping symbol names to entity constructor functions. Constructors have the signature ~(lambda (x y w h) entity)~. + +Example: + +#+begin_src scheme +(define (make-player x y w h) + (list #:type 'player #:x x #:y y #:width w #:height h + #:vx 0 #:vy 0 #:gravity? #t #:tile-id 29)) + +(define (make-enemy x y w h) + (list #:type 'enemy #:x x #:y y #:width w #:height h + #:vx -2 #:vy 0 #:gravity? #t #:tile-id 5)) + +(define prefabs + (make-prefab-registry + 'player make-player + 'enemy make-enemy)) +#+end_src + +** ~instantiate-prefab~ + +#+begin_src scheme +(instantiate-prefab registry type x y w h) +#+end_src + +Looks up a constructor by type in the registry and calls it with the given position and size. Returns the entity plist, or ~#f~ if the type is not registered. + +** ~tilemap-objects->entities~ + +#+begin_src scheme +(tilemap-objects->entities tilemap instantiate-fn) +#+end_src + +Converts the TMX object list (from Tiled) into entity plists. Each object's type (string from XML) is converted to a symbol and passed to ~instantiate-fn~. Filters out ~#f~ results (unregistered types). + +~instantiate-fn~ should have the signature ~(lambda (type x y w h) entity-or-#f)~, typically the curried version of ~instantiate-prefab~: + +Example: + +#+begin_src scheme +(let* ((prefabs (make-prefab-registry 'player make-player 'enemy make-enemy)) + (inst (lambda (t x y w h) (instantiate-prefab prefabs t x y w h))) + (entities (tilemap-objects->entities tilemap inst))) + (scene-entities-set! scene entities)) +#+end_src |
