aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/api.org39
-rw-r--r--docs/entities.org31
-rw-r--r--docs/guide.org10
-rw-r--r--docs/physics.org12
4 files changed, 45 insertions, 47 deletions
diff --git a/docs/api.org b/docs/api.org
index d4dc074..15c6e54 100644
--- a/docs/api.org
+++ b/docs/api.org
@@ -208,7 +208,7 @@ Creates a scene record representing the current level state.
| ~tileset~ | tileset/false | #f | Tileset metadata (from ~load-tileset~) when there is no tilemap; required with ~tileset-texture~ to draw ~#:tile-id~ sprites without a TMX map |
| ~camera~ | camera/false | #f | Viewport position |
| ~tileset-texture~ | SDL2 texture/false | #f | Rendered tileset image |
-| ~camera-target~ | symbol/false | #f | Tag symbol of the entity to follow (see ~scene-camera-target-set!~) |
+| ~camera-target~ | symbol/false | #f | Tag symbol of the entity to follow (set via ~update-scene~) |
| ~background~ | list/false | #f | Framebuffer clear color: ~(r g b)~ or ~(r g b a)~ (0–255). ~#f~ means opaque black. Set each frame in ~game-run!~ before ~SDL_RenderClear~. |
** ~make-camera~
@@ -239,13 +239,13 @@ Accessors for camera position.
Mutate camera position (in-place).
-** ~camera-follow!~
+** ~camera-follow~
#+begin_src scheme
-(camera-follow! camera entity viewport-w viewport-h)
+(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.
+Returns a new camera centered on an entity, clamping to stay within world bounds (never negative). ~viewport-w~ and ~viewport-h~ are the game window dimensions. The original camera is not modified.
** ~scene-add-entity~
@@ -253,7 +253,7 @@ Centers the camera on an entity, clamping to stay within world bounds (never neg
(scene-add-entity scene entity)
#+end_src
-Appends an entity to the scene's entity list. Returns the modified scene.
+Appends an entity to the scene's entity list. Returns a new scene; the original is not modified.
** ~scene-update-entities~
@@ -261,7 +261,7 @@ Appends an entity to the scene's entity list. Returns the modified scene.
(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.
+Applies each procedure in sequence to all entities in the scene. Each procedure takes a single entity and returns a modified entity. Returns a new scene with the updated entity list; the original is not modified.
Example:
@@ -276,13 +276,13 @@ Example:
; Each entity is passed through increment-x, then through apply-gravity
#+end_src
-** ~scene-sync-groups!~
+** ~scene-sync-groups~
#+begin_src scheme
-(scene-sync-groups! scene)
+(scene-sync-groups scene)
#+end_src
-For every entity with ~#:group-id~ that is not an origin (~#:group-origin?~ is false), sets ~#:x~ and ~#:y~ to the corresponding origin’s position plus that entity’s ~#:group-local-x~ and ~#:group-local-y~. Origins are read from ~scene-entities~, so after a tween or other motion that returns a *new* origin plist, replace that origin in the scene’s list (match on ~#:group-id~ / ~#:group-origin?~) before calling ~scene-sync-groups!~. Call after updating origin positions and before per-entity physics so platforms and collisions see a consistent pose. Returns the scene.
+For every entity with ~#:group-id~ that is not an origin (~#:group-origin?~ is false), sets ~#:x~ and ~#:y~ to the corresponding origin’s position plus that entity’s ~#:group-local-x~ and ~#:group-local-y~. Origins are read from ~scene-entities~, so after a tween or other motion that returns a *new* origin plist, replace that origin in the scene’s list (match on ~#:group-id~ / ~#:group-origin?~) before calling ~scene-sync-groups~. Call after updating origin positions and before per-entity physics so platforms and collisions see a consistent pose. Returns a new scene; the original is not modified.
** ~scene-filter-entities~
@@ -290,7 +290,7 @@ For every entity with ~#:group-id~ that is not an origin (~#:group-origin?~ is f
(scene-filter-entities scene predicate)
#+end_src
-Removes all entities that do not satisfy the predicate. Returns the modified scene.
+Keeps only entities that satisfy the predicate. Returns a new scene; the original is not modified.
Example:
@@ -318,11 +318,16 @@ Returns a list of all entities whose ~#:tags~ list contains the given tag. Retur
** 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!~
-- ~scene-camera-target~, ~scene-camera-target-set!~
+Read accessors:
+- ~scene-entities~, ~scene-tilemap~, ~scene-camera~, ~scene-tileset-texture~, ~scene-camera-target~, ~scene-background~
+
+Functional updater (returns a new scene with the specified fields changed):
+
+#+begin_src scheme
+(update-scene scene entities: new-entities camera-target: 'player)
+#+end_src
+
+Mutating setters (~scene-entities-set!~, etc.) are also generated but should be avoided in favour of ~update-scene~ and the pure pipeline functions above. Use ~game-scene-set!~ at the boundary to store the final scene back on the game struct.
** ~tilemap-tile-at~
@@ -1328,7 +1333,7 @@ Looks up a prefab by type symbol in the registry and returns a fresh entity plis
(instantiate-group-prefab registry type origin-x origin-y)
#+end_src
-Looks up a *group prefab* by type symbol and returns a list ~(origin member ...)~: one origin entity plus one entity per part. Optional group-level flags ~#:pose-only-origin?~ and ~#:static-parts?~ select origin/part profiles (see ~docs/entities.org~); defaults are ~#f~ (physics-driving origin, non-static parts). Each instance receives a fresh gensym ~#:group-id~ shared by the origin and all members. Returns ~#f~ if the type is not in ~group-prefabs~. After moving origins (tween and/or physics), ensure updated origins are stored in the scene’s entity list, then call ~scene-sync-groups!~ so member ~#:x~ / ~#:y~ match ~origin + #:group-local-x/y~.
+Looks up a *group prefab* by type symbol and returns a list ~(origin member ...)~: one origin entity plus one entity per part. Optional group-level flags ~#:pose-only-origin?~ and ~#:static-parts?~ select origin/part profiles (see ~docs/entities.org~); defaults are ~#f~ (physics-driving origin, non-static parts). Each instance receives a fresh gensym ~#:group-id~ shared by the origin and all members. Returns ~#f~ if the type is not in ~group-prefabs~. After moving origins (tween and/or physics), ensure updated origins are stored in the scene’s entity list, then call ~scene-sync-groups~ so member ~#:x~ / ~#:y~ match ~origin + #:group-local-x/y~.
** ~tilemap-objects->entities~
@@ -1343,5 +1348,5 @@ Example:
#+begin_src scheme
(let* ((registry (load-prefabs "assets/prefabs.scm" '() '()))
(entities (tilemap-objects->entities tilemap registry)))
- (scene-entities-set! scene entities))
+ (update-scene scene entities: entities))
#+end_src
diff --git a/docs/entities.org b/docs/entities.org
index 048cd8e..3766522 100644
--- a/docs/entities.org
+++ b/docs/entities.org
@@ -126,19 +126,19 @@ The engine recognizes these standard keys. Use them to integrate with the physic
| ~#:anim-tick~ | integer | Tick counter for frame timing (0 to ~#:duration - 1~). Incremented by ~animate-entity~; resets when frame advances. |
| ~#:group-id~ | symbol | Shared id for one rigid assembly (from ~instantiate-group-prefab~). All parts and the origin share the same symbol. |
| ~#:group-origin?~ | boolean | When ~#t~, this entity is the assembly’s pose origin; world ~#:x~ / ~#:y~ drive the group. Members should not set this. |
-| ~#:group-local-x~, ~#:group-local-y~ | number | Offset from the origin’s top-left corner; members’ world position is origin + local (updated by ~scene-sync-groups!~). |
+| ~#:group-local-x~, ~#:group-local-y~ | number | Offset from the origin’s top-left corner; members’ world position is origin + local (updated by ~scene-sync-groups~). |
| ~#:skip-render~ | boolean | When ~#t~, ~render-scene!~ skips drawing this entity (used for invisible origins). |
* Entity groups (prefab assemblies)
A **group prefab** describes one *origin* entity plus several *parts* with local offsets. Data lives in the optional ~group-prefabs~ section of the prefab file (alongside ~mixins~ and ~prefabs~). Each group entry has the shape ~(name #:type-members SYMBOL #:parts (part ...) ...)~ with two optional flags:
-- ~#:pose-only-origin?~ — when ~#t~ (typical for tweened platforms), the origin is invisible, does not run physics pipelines, and is driven by tweens or scripts. When ~#f~ (default), the origin uses a small *physics-driving* profile (~#:gravity? #t~, no ~#:skip-pipelines~): integrate the origin like a mover, then call ~scene-sync-groups!~ so parts stay glued as a rigid body. For that case, set ~#:origin-width~ and ~#:origin-height~ to the full assembly size (same box as the combined parts); otherwise the origin stays 0×0 and tile collision only sees a point at the reference corner, which can leave the raft overlapping solid floor tiles.
+- ~#:pose-only-origin?~ — when ~#t~ (typical for tweened platforms), the origin is invisible, does not run physics pipelines, and is driven by tweens or scripts. When ~#f~ (default), the origin uses a small *physics-driving* profile (~#:gravity? #t~, no ~#:skip-pipelines~): integrate the origin like a mover, then call ~scene-sync-groups~ so parts stay glued as a rigid body. For that case, set ~#:origin-width~ and ~#:origin-height~ to the full assembly size (same box as the combined parts); otherwise the origin stays 0×0 and tile collision only sees a point at the reference corner, which can leave the raft overlapping solid floor tiles.
- ~#:static-parts?~ — when ~#t~, each part gets static rigid-body defaults (no gravity on parts; pose comes from the origin). When ~#f~ (default), parts only have what you put in each part plist.
Each ~part~ is a plist using ~#:local-x~ / ~#:local-y~ (or ~#:group-local-x~ / ~#:group-local-y~) and the usual ~#:width~, ~#:height~, ~#:tile-id~, physics keys, etc.
-Use ~(instantiate-group-prefab registry 'name origin-x origin-y)~ from ~downstroke-prefabs~ to obtain ~(origin member ...)~. Append all of them to the scene. After moving origins (tweens and/or physics), ensure updated origins are in ~scene-entities~, then call ~(scene-sync-groups! scene)~ so every part’s ~#:x~ / ~#:y~ matches the origin plus local offsets (see ~docs/api.org~ for ordering).
+Use ~(instantiate-group-prefab registry 'name origin-x origin-y)~ from ~downstroke-prefabs~ to obtain ~(origin member ...)~. Append all of them to the scene. After moving origins (tweens and/or physics), ensure updated origins are in ~scene-entities~, then call ~(scene-sync-groups scene)~ so every part’s ~#:x~ / ~#:y~ matches the origin plus local offsets (see ~docs/api.org~ for ordering).
* Entities in Scenes
@@ -152,17 +152,17 @@ Returns the list of all entities in the scene.
(define all-entities (scene-entities scene))
#+end_src
-** ~scene-entities-set! scene entities~
+** ~update-scene~
-Mutates the scene to replace the entity list. Use after ~scene-update-entities~ or batch operations.
+Returns a new scene with the specified fields changed. Preferred over the mutating ~scene-entities-set!~.
#+begin_src scheme
-(scene-entities-set! scene (list updated-player updated-enemy))
+(update-scene scene entities: (list updated-player updated-enemy))
#+end_src
** ~scene-add-entity scene entity~
-Adds an entity to the scene and returns the scene. Appends to the entity list.
+Returns a new scene with the entity appended to the entity list.
#+begin_src scheme
(scene-add-entity scene new-enemy)
@@ -183,17 +183,15 @@ Maps each procedure over the scene's entities, applying them in sequence. Each p
The result is equivalent to:
#+begin_src scheme
-(let* ((es (scene-entities scene))
- (es (map apply-gravity es))
- (es (map apply-velocity-x es))
- (es (map apply-velocity-y es)))
- (scene-entities-set! scene es)
- scene)
+(chain scene
+ (scene-update-entities _ apply-gravity)
+ (scene-update-entities _ apply-velocity-x)
+ (scene-update-entities _ apply-velocity-y))
#+end_src
** ~scene-filter-entities scene pred~
-Removes all entities that do not satisfy the predicate. Use to despawn dead enemies, collected items, etc.
+Keeps only entities satisfying the predicate; returns a new scene. Use to despawn dead enemies, collected items, etc.
#+begin_src scheme
;; Remove all entities with #:health <= 0:
@@ -392,7 +390,8 @@ Here is a full example showing entity creation, initialization in the scene, and
(let ((player (if (< (entity-ref player #:vx 0) 0)
(entity-set player #:facing -1)
(entity-set player #:facing 1))))
- (scene-entities-set! scene (list player))))))
+ (game-scene-set! game
+ (update-scene scene entities: (list player)))))))
#+end_src
-Note the let*-chaining pattern: each update builds on the previous result, keeping the data flow clear and each step testable.
+Note the let*-chaining pattern: each update builds on the previous result, keeping the data flow clear and each step testable. The single ~game-scene-set!~ at the boundary stores the final scene back on the game struct.
diff --git a/docs/guide.org b/docs/guide.org
index 1c5a8f3..96663ea 100644
--- a/docs/guide.org
+++ b/docs/guide.org
@@ -101,7 +101,8 @@ Now let's add an entity you can move with the keyboard. Create =square.scm=:
(entity-ref box #:vx 0))))
(box (entity-set box #:y (+ (entity-ref box #:y 0)
(entity-ref box #:vy 0)))))
- (scene-entities-set! scene (list box))))
+ (game-scene-set! game
+ (update-scene scene entities: (list box)))))
render: (lambda (game)
(let* ((scene (game-scene game))
@@ -194,11 +195,8 @@ For a real game, you probably want tilemaps, gravity, and collision detection. D
(player (apply-velocity-y player))
(player (resolve-tile-collisions-y player tm))
(player (detect-on-solid player tm)))
- ;; Update camera to follow player
- (let ((cam-x (max 0 (- (entity-ref player #:x 0) 300))))
- (camera-x-set! (scene-camera scene) cam-x))
- ;; Replace entities in scene
- (scene-entities-set! scene (list player))))))
+ (game-scene-set! game
+ (update-scene scene entities: (list player)))))))
(game-run! *game*)
#+end_src
diff --git a/docs/physics.org b/docs/physics.org
index 9c44718..8401a38 100644
--- a/docs/physics.org
+++ b/docs/physics.org
@@ -331,11 +331,8 @@ update: (lambda (game dt)
(player (resolve-tile-collisions-y player tm))
;; Check if standing on ground
(player (detect-on-solid player tm)))
- ;; Update camera to follow player
- (let ((cam-x (max 0 (- (entity-ref player #:x 0) 300))))
- (camera-x-set! (scene-camera scene) cam-x))
- ;; Store updated player back in scene
- (scene-entities-set! scene (list player))))
+ (game-scene-set! game
+ (update-scene scene entities: (list player)))))
#+end_src
** Step-by-Step
@@ -378,9 +375,8 @@ update: (lambda (game dt)
(player (resolve-tile-collisions-y player tm)))
;; Update camera to follow player
(camera-x-set! (scene-camera scene) (max 0 (- (entity-ref player #:x 0) 300)))
- (camera-y-set! (scene-camera scene) (max 0 (- (entity-ref player #:y 0) 200)))
- ;; Store updated player back in scene
- (scene-entities-set! scene (list player))))
+ (game-scene-set! game
+ (update-scene scene entities: (list player)))))
#+end_src
** Step-by-Step