aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/api.org75
-rw-r--r--docs/entities.org5
-rw-r--r--docs/guide.org4
-rw-r--r--docs/physics.org57
-rw-r--r--docs/tweens.org90
5 files changed, 208 insertions, 23 deletions
diff --git a/docs/api.org b/docs/api.org
index f18b80a..f6cfe50 100644
--- a/docs/api.org
+++ b/docs/api.org
@@ -287,7 +287,7 @@ Returns the tile ID at grid position ~(col, row)~ across all layers. Returns ~0~
(import downstroke-entity)
#+end_src
-The entity module provides property list (plist) accessors for game objects. Entities are immutable plists, never modified in place.
+The entity module provides property list (plist) accessors for game objects. Entities are immutable plists, never modified in place. It also defines ~entity-skips-pipeline?~ and the ~define-pipeline~ macro for frame pipeline steps that respect ~#:skip-pipelines~ (see ~docs/physics.org~ for the built-in physics step names).
** ~entity-ref~
@@ -344,6 +344,22 @@ Example:
; Equivalent to (entity-set player #:x (+ 10 (entity-ref player #:x 0)))
#+end_src
+** ~entity-skips-pipeline?~
+
+#+begin_src scheme
+(entity-skips-pipeline? entity step-symbol)
+#+end_src
+
+Returns true if ~step-symbol~ appears in the entity’s ~#:skip-pipelines~ list (and that list is non-empty). The built-in physics step names are documented in ~docs/physics.org~; other engine modules may reserve additional symbols for their own frame phases (rendering, animation, etc.) using the same plist key.
+
+** ~define-pipeline~
+
+#+begin_src scheme
+(define-pipeline (procedure-name skip-symbol) (entity-formal extra-formal ...) body ...)
+#+end_src
+
+Syntax for authors of per-entity pipeline steps: expands to a ~define~ that returns the **first** formal (the entity) unchanged when ~skip-symbol~ is listed in ~#:skip-pipelines~; otherwise runs ~body ...~ inside ~(let () ...)~. Used throughout ~downstroke-physics~; other modules can use it for consistent skip behavior. The procedure name and skip symbol differ when needed (e.g. ~detect-ground~ vs ~ground-detection~).
+
** Shared Entity Keys
All entities can have these keys. Not all are required:
@@ -363,6 +379,7 @@ All entities can have these keys. Not all are required:
| ~#:on-ground?~ | boolean | Is entity touching a solid tile below? |
| ~#:facing~ | integer | 1 (right) or -1 (left) |
| ~#:solid?~ | boolean | Participate in AABB entity collisions? |
+| ~#:skip-pipelines~ | list | Symbols naming pipeline steps to skip; physics defines the built-in set (~docs/physics.org~) |
| ~#:anim-name~ | symbol | Current animation name |
| ~#:anim-frame~ | integer | Current frame index |
| ~#:anim-tick~ | integer | Ticks in current frame |
@@ -377,15 +394,19 @@ The physics module provides functions for movement, collision detection, and gro
** Physics Pipeline Order
-The built-in physics runs in this order each frame:
+The built-in physics functions are normally run in this order each frame (after reading input, before rendering):
-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
+1. ~apply-jump~ — if jump pressed and on ground, set ~#:ay~
+2. ~apply-acceleration~ — consume ~#:ay~ into ~#:vy~
+3. ~apply-gravity~ — add gravity to ~#:vy~
+4. ~apply-velocity-x~ — move by ~#:vx~
+5. ~resolve-tile-collisions-x~ — snap against horizontal tile collisions
+6. ~apply-velocity-y~ — move by ~#:vy~
+7. ~resolve-tile-collisions-y~ — snap against vertical tile collisions
+8. ~detect-ground~ — set ~#:on-ground?~ if standing on a tile
+9. ~resolve-entity-collisions~ — push apart solid entities (whole list)
+
+Entities may list ~#:skip-pipelines~ to omit specific steps; see ~entity-skips-pipeline?~ under ~downstroke-entity~ and ~docs/physics.org~.
(This separation ensures smooth sliding along walls.)
@@ -963,6 +984,42 @@ Changes the music volume while it is playing. ~volume~ is 0.0 to 1.0.
Releases all audio resources. Call at shutdown or in a cleanup hook.
+* Tweens (~downstroke-tween~)
+
+#+begin_src scheme
+(import downstroke-tween)
+#+end_src
+
+Time-based interpolation of numeric entity properties. Library-only — call from ~update:~; see ~docs/tweens.org~ for patterns with ~#:skip-pipelines~.
+
+** ~make-tween~
+
+#+begin_src scheme
+(make-tween entity #!key props duration (delay 0) ease (on-complete #f))
+#+end_src
+
+| Keyword | Description |
+|---------+-------------|
+| ~props~ | Alist ~((#:key . target-number) ...)~ |
+| ~duration~ | Milliseconds of interpolation after ~delay~ |
+| ~delay~ | Initial wait in ms (default 0) |
+| ~ease~ | Symbol (e.g. ~quad-in-out~) or ~(lambda (t) ...)~ with ~t~ in [0,1] |
+| ~on-complete~ | Optional ~(lambda (entity) ...)~ once at completion |
+
+** ~tween-step~
+
+#+begin_src scheme
+(tween-step tween entity dt)
+#+end_src
+
+Returns two values: updated tween struct and updated entity. ~dt~ is elapsed milliseconds for this frame.
+
+** ~tween-finished?~ / ~tween-active?~
+
+** Easing exports
+
+~ease-linear~, ~ease-quad-in~, ~ease-quad-out~, ~ease-quad-in-out~, ~ease-cubic-in~, ~ease-cubic-out~, ~ease-cubic-in-out~, ~ease-sine-in-out~, ~ease-expo-in~, ~ease-expo-out~, ~ease-expo-in-out~, ~ease-back-out~, ~ease-named~, ~ease-resolve~.
+
* Animation (~downstroke-animation~)
#+begin_src scheme
diff --git a/docs/entities.org b/docs/entities.org
index db5663d..f6e870c 100644
--- a/docs/entities.org
+++ b/docs/entities.org
@@ -18,6 +18,10 @@ Entities in Downstroke are plain Scheme **plists** (property lists) — alternat
This minimal approach keeps the engine lean: your game defines whatever keys it needs. The shared keys listed below are *conventions* for physics, rendering, and animation — use them to integrate with the engine's built-in systems. Custom keys are always allowed.
+* Pipeline skips (~#:skip-pipelines~)
+
+The optional key ~#:skip-pipelines~ holds a list of **symbols** naming frame pipeline steps that should be skipped for that entity. The physics module defines the built-in step names (see ~docs/physics.org~). The predicate ~entity-skips-pipeline?~ and the syntax ~define-pipeline~ live in ~downstroke-entity~ so any subsystem (physics now; rendering or animation later if you extend the engine) can use the same mechanism without a separate “core pipeline” module.
+
* Creating Entities
There is no ~make-entity~ constructor. Create an entity as a plain list:
@@ -109,6 +113,7 @@ The engine recognizes these standard keys. Use them to integrate with the physic
| ~#:gravity?~ | boolean | Whether gravity applies to this entity. Set to ~#t~ for platformers (gravity pulls down), ~#f~ for top-down or flying entities. Used by ~apply-gravity~. |
| ~#:on-ground?~ | boolean | Whether the entity is touching a solid tile below (set by ~detect-ground~). Use this to gate jump input: only allow jumping if ~#:on-ground?~ is true. |
| ~#:solid?~ | boolean | Whether this entity participates in entity-entity collision. If ~#t~, ~resolve-entity-collisions~ will check it against other solid entities. |
+| ~#:skip-pipelines~ | list of symbols | Optional. Each symbol names a physics step to skip for this entity (e.g. ~gravity~, ~velocity-x~). See ~docs/physics.org~. |
| ~#:tile-id~ | integer | Sprite index in the tileset (1-indexed). Required for rendering with ~draw-sprite~. Updated automatically by animation (~animate-entity~). |
| ~#:facing~ | number | Horizontal flip direction: ~1~ = right (default), ~-1~ = left. Used by renderer to flip sprite horizontally. Update when changing direction. |
| ~#:tags~ | list of symbols | List of tag symbols, e.g., ~'(player solid)~. Used by ~scene-find-tagged~ and ~scene-find-all-tagged~ for fast lookups. |
diff --git a/docs/guide.org b/docs/guide.org
index ca9cfbf..de07c82 100644
--- a/docs/guide.org
+++ b/docs/guide.org
@@ -240,7 +240,7 @@ This is invaluable for tuning collision geometry and understanding why entities
* Demo Overview
-Downstroke includes seven complete demo games that showcase different features:
+Downstroke includes several demo games that showcase different features:
| Demo | File | What it shows |
|------|------|--------------|
@@ -251,6 +251,7 @@ Downstroke includes seven complete demo games that showcase different features:
| Audio | =demo/audio.scm= | Sound effects, music toggle, text rendering |
| Sprite Font | =demo/spritefont.scm= | Bitmap text rendering using non-contiguous tileset ranges |
| Menu | =demo/menu.scm= | State machine menus, keyboard navigation, TTF text rendering |
+| Tweens | =demo/tweens.scm= | Easing curves, =tween-step=, =#:skip-pipelines= with tile collision |
Each demo is self-contained and serves as a working reference for a particular game mechanic.
@@ -283,5 +284,6 @@ For more details:
- **Full API reference**: See =docs/api.org= for all functions and keyword arguments.
- **Entity model**: See =docs/entities.org= to learn about plist keys, tags, prefabs, and mixins.
- **Physics pipeline**: See =docs/physics.org= for the full physics specification and collision model.
+- **Tweens**: See =docs/tweens.org= for time-based property interpolation and combining tweens with physics.
Happy coding!
diff --git a/docs/physics.org b/docs/physics.org
index a267d6d..2a82210 100644
--- a/docs/physics.org
+++ b/docs/physics.org
@@ -22,38 +22,69 @@ The =tilemap= argument is required by collision functions, since collision data
* Physics Pipeline
-The canonical 9-step physics pipeline is:
+The canonical **per-entity** physics pipeline (what you typically call from =update:=) is:
#+begin_src
-input
+apply-jump (set #:ay if jump pressed and on-ground)
-apply-jump (set #:ay if jump pressed and on-ground)
+apply-acceleration (consume #:ay into #:vy)
-apply-acceleration (consume #:ay into #:vy)
+apply-gravity (add gravity constant to #:vy)
-apply-gravity (add gravity constant to #:vy)
+apply-velocity-x (add #:vx to #:x)
-apply-velocity-x (add #:vx to #:x)
+resolve-tile-collisions-x (snap off horizontal tiles, zero #:vx)
-resolve-tile-collisions-x (snap off horizontal tiles, zero #:vx)
- ↓
-apply-velocity-y (add #:vy to #:y)
+apply-velocity-y (add #:vy to #:y)
resolve-tile-collisions-y (snap off vertical tiles, zero #:vy)
-detect-ground (probe 1px below feet, set #:on-ground?)
- ↓
-resolve-entity-collisions (push apart overlapping solid entities)
+detect-ground (probe 1px below feet, set #:on-ground?)
-render
+resolve-entity-collisions (push apart overlapping solid entities; whole list)
#+end_src
+Input and rendering live **outside** this list — you read input first, then run the steps you need, then render.
+
**Not all steps are needed for all game types.** See the examples section for three different patterns:
- **Platformer**: uses all 9 steps
- **Top-down**: skips gravity, acceleration, jump, ground detection
- **Physics Sandbox**: uses all steps, applies them to multiple entities
+* Skipping steps (~#:skip-pipelines~)
+
+An entity may include ~#:skip-pipelines=, a list of **symbols** naming steps to **omit** for that entity only. Absent or empty means no steps are skipped.
+
+| Symbol | Skipped call |
+|--------+----------------|
+| ~jump~ | ~apply-jump~ |
+| ~acceleration~ | ~apply-acceleration~ |
+| ~gravity~ | ~apply-gravity~ |
+| ~velocity-x~ | ~apply-velocity-x~ |
+| ~velocity-y~ | ~apply-velocity-y~ |
+| ~tile-collisions-x~ | ~resolve-tile-collisions-x~ |
+| ~tile-collisions-y~ | ~resolve-tile-collisions-y~ |
+| ~ground-detection~ | ~detect-ground~ |
+| ~entity-collisions~ | participation in ~resolve-entity-collisions~ / ~resolve-pair~ |
+
+**Entity–entity collisions:** if *either* entity in a pair lists ~entity-collisions~ in ~#:skip-pipelines=, that pair is not resolved (no push-apart). Use this for “ghost” actors or scripted motion that should not participate in mutual solid resolution.
+
+**Legacy ~apply-velocity~:** skips each axis independently if ~velocity-x~ or ~velocity-y~ is listed.
+
+Helper: ~(entity-skips-pipeline? entity step-symbol)~ (from ~downstroke-entity~) returns ~#t~ if ~step-symbol~ is in the entity’s skip list.
+
+** ~define-pipeline~ (~downstroke-entity~)
+
+Physics steps are defined with ~(define-pipeline (procedure-name skip-symbol) (formals ...) body ...)~ from the entity module. The first formal must be the entity. The procedure name and skip symbol are separate so names like ~detect-ground~ can use the skip key ~ground-detection~. ~apply-velocity~ is still written by hand because it consults ~velocity-x~ and ~velocity-y~ independently.
+
+The renderer and other subsystems do **not** use ~#:skip-pipelines~ today; they run after your ~update:~ hook. If you add render-phase or animation-phase skips later, reuse the same plist key and helpers from ~downstroke-entity~ and document the new symbols alongside physics.
+
+Use cases:
+
+- **Tweens / knockback:** skip ~jump~, ~acceleration~, ~gravity~, ~velocity-x~, ~velocity-y~ while a tween drives ~#:x~ / ~#:y~, but keep tile resolution so the body does not rest inside walls.
+- **Top-down:** omit gravity, jump, acceleration, ground detection from your *call order*; you usually do not need ~#:skip-pipelines= unless some entities differ from others.
+
* Pipeline Steps
** apply-jump
diff --git a/docs/tweens.org b/docs/tweens.org
new file mode 100644
index 0000000..9ac87cd
--- /dev/null
+++ b/docs/tweens.org
@@ -0,0 +1,90 @@
+#+title: Tweens
+#+author: Downstroke Contributors
+
+* Overview
+
+The =downstroke-tween= module interpolates **numeric** entity properties over wall-clock time. It is **decoupled** from the engine: you create tween values, call =tween-step= each frame from your =update:= hook, and store the returned entity back into the scene.
+
+Durations and delays are in **milliseconds**, matching the =dt= argument to =update:=.
+
+* Import
+
+#+begin_src scheme
+(import downstroke-tween)
+#+end_src
+
+* Core API
+
+** ~make-tween~
+
+#+begin_src scheme
+(make-tween entity #!key props duration (delay 0) ease (on-complete #f))
+#+end_src
+
+| Keyword | Meaning |
+|---------+---------|
+| ~props~ | Alist =((#:x . 200) (#:y . 40))= — keyword keys, numeric targets |
+| ~duration~ | Positive integer, milliseconds of interpolation (after ~delay~) |
+| ~delay~ | Non-negative integer ms before interpolation starts |
+| ~ease~ | Easing symbol (see table below) or ~(lambda (t) ...)= with ~t~ in $[0,1]$ |
+| ~on-complete~ | Optional ~(lambda (entity) ...)=, called **once** when the tween reaches its targets |
+
+Start values are captured from ~entity~ at construction time. While the tween runs, intermediate values may be **inexact** (flonums) even if starts and ends are integers.
+
+** ~tween-step~
+
+#+begin_src scheme
+(tween-step tween entity dt)
+#+end_src
+
+Returns ~(values new-tween new-entity)~. Advance time by ~dt~ (ms). Before ~delay~ elapses, ~entity~ is unchanged. After completion, further steps return the same values (idempotent). When the tween completes, ~on-complete~ runs with the **final** entity (targets applied), then the callback slot is cleared.
+
+** ~tween-finished?~ / ~tween-active?~
+
+Predicates on the tween struct.
+
+* Easing
+
+Each ease maps normalized time ~t ∈ [0,1]~ to an interpolation factor (usually in ~[0,1]~; ~back-out~ may exceed ~1~ briefly).
+
+| Symbol | Procedure |
+|--------|-----------|
+| ~linear~ | ~ease-linear~ |
+| ~quad-in~, ~quad-out~, ~quad-in-out~ | quadratic |
+| ~cubic-in~, ~cubic-out~, ~cubic-in-out~ | cubic |
+| ~sine-in-out~ | smooth sine |
+| ~expo-in~, ~expo-out~, ~expo-in-out~ | exponential |
+| ~back-out~ | overshoot then settle (Robert Penner–style) |
+
+** ~ease-named~ / ~ease-resolve~
+
+~ease-named~ turns a symbol into a procedure. ~ease-resolve~ accepts a symbol or procedure (identity for procedures) for use in custom tooling.
+
+All easing procedures are exported if you want to compose curves manually.
+
+* Order of operations with physics
+
+Tweens usually **fight** velocity and gravity if both update ~#:x~ / ~#:y~. Typical pattern:
+
+1. Set the entity’s ~#:skip-pipelines~ to skip integration steps you do not want (see [[physics.org][Physics]]).
+2. Run ~tween-step~ for that entity.
+3. Run your normal physics pipeline (collisions can still run).
+
+Clear ~#:skip-pipelines~ in ~on-complete~ when the tween ends.
+
+Example skip list for “kinematic shove” while keeping tile collisions:
+
+#+begin_src scheme
+(entity-set player #:skip-pipelines
+ '(jump acceleration gravity velocity-x velocity-y))
+#+end_src
+
+* Demo
+
+=bin/demo-tweens= (source =demo/tweens.scm=) shows one row per easing and a crate that tweens horizontally while integration is skipped and tile resolution still runs.
+
+* Limitations (current version)
+
+- Single segment per tween (no built-in chains or yoyo).
+- Numeric properties only.
+- No engine integration — you wire ~tween-step~ yourself.