aboutsummaryrefslogtreecommitdiff
path: root/docs/physics.org
diff options
context:
space:
mode:
authorGene Pasquet <dev@etenil.net>2026-04-07 23:36:12 +0100
committerGene Pasquet <dev@etenil.net>2026-04-07 23:36:12 +0100
commit19a5db8606a82830a5ccd0ed46d8e0cf3c95db0a (patch)
tree241e7376014068ab9fc7a1bc8fa7a29cc1b62490 /docs/physics.org
parent618ed5fd6f5ae9c9f275c1e3cfb74762d7d51a01 (diff)
Work on demos
Diffstat (limited to 'docs/physics.org')
-rw-r--r--docs/physics.org40
1 files changed, 18 insertions, 22 deletions
diff --git a/docs/physics.org b/docs/physics.org
index 2a82210..0eb9265 100644
--- a/docs/physics.org
+++ b/docs/physics.org
@@ -16,7 +16,7 @@ The =tilemap= argument is required by collision functions, since collision data
- =apply-gravity= — add gravity to falling entities
- =apply-velocity-x=, =apply-velocity-y= — move entity by velocity
- =resolve-tile-collisions-x=, =resolve-tile-collisions-y= — snap entity off tiles on collision
-- =detect-ground= — probe 1px below feet to set #:on-ground?
+- =detect-on-solid= — set =#:on-ground?= from tiles below feet and/or solid entities underfoot
- =resolve-entity-collisions= — all-pairs AABB push-apart for solid entities
- =aabb-overlap?= — pure boolean collision test (for queries, not resolution)
@@ -39,7 +39,7 @@ 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?)
+detect-on-solid (tiles and/or other solids underfoot, set #:on-ground?)
resolve-entity-collisions (push apart overlapping solid entities; whole list)
#+end_src
@@ -65,7 +65,7 @@ An entity may include ~#:skip-pipelines=, a list of **symbols** naming steps to
| ~velocity-y~ | ~apply-velocity-y~ |
| ~tile-collisions-x~ | ~resolve-tile-collisions-x~ |
| ~tile-collisions-y~ | ~resolve-tile-collisions-y~ |
-| ~ground-detection~ | ~detect-ground~ |
+| ~on-solid~ | ~detect-on-solid~ |
| ~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.
@@ -76,7 +76,7 @@ Helper: ~(entity-skips-pipeline? entity step-symbol)~ (from ~downstroke-entity~)
** ~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.
+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 (e.g. ~detect-on-solid~ vs ~on-solid~). ~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.
@@ -193,19 +193,19 @@ Velocity is zeroed to stop the entity from sliding. Call this immediately after
Velocity is zeroed. Call this immediately after =apply-velocity-y=.
-** detect-ground
+** detect-on-solid
#+begin_src scheme
-(detect-ground entity tilemap)
+(detect-on-solid entity tilemap #!optional other-entities)
#+end_src
-**Reads**: =#:gravity?=, =#:x=, =#:y=, =#:width=, =#:height=
+**Reads**: =#:gravity?=, =#:x=, =#:y=, =#:width=, =#:height=, =#:vy=; when =other-entities= is passed, each other entity's =#:solid?=, position, and size
-**Writes**: =#:on-ground?= (set to #t if tile found 1px below feet, else #f)
+**Writes**: =#:on-ground?= (set to =#t= if supported by a solid tile probe and/or by another solid's top surface, else =#f=)
-**Description**: Probes 1 pixel directly below the entity's feet (bottom edge) to see if it's standing on a tile. The probe checks both corners of the entity's width to handle partial overlaps. Only works if =#:gravity?= is true.
+**Description**: Despite the =?=-suffix, this returns an **updated entity** (it sets =#:on-ground?=), not a boolean. Ground is **either** (1) a solid tile one pixel below the feet (probe at both lower corners of the AABB, same as before), **or** (2) when =other-entities= is a non-=#f= list, resting on another solid entity's **top** (horizontal overlap, feet within a few pixels of that entity's top, and vertical speed small enough that we treat the body as supported—so moving platforms and crates count). Omit =other-entities= (or pass =#f=) to keep tile-only behavior. Only runs when =#:gravity?= is true. If =tilemap= is =#f=, the tile probe is skipped and only entity support applies when a list is provided.
-Used by =apply-jump= to decide whether jump is allowed. Call this at the end of each physics frame, after all collision resolution.
+Used by =apply-jump= (via =#:on-ground?= on the **next** frame). Call **after** tile collision and **after** =resolve-entity-collisions= when using entity support, so positions and velocities are settled.
** resolve-entity-collisions
@@ -219,11 +219,7 @@ Used by =apply-jump= to decide whether jump is allowed. Call this at the end of
**Writes**: For colliding pairs: =#:x=, =#:y=, =#:vx=, =#:vy= (pushed apart, velocities set to ±1)
-**Description**: Performs all-pairs AABB overlap detection. For each pair of entities where BOTH have =#:solid? #t=, if they overlap:
-
-1. Calculate overlap on both X and Y axes
-2. Push apart along the axis with smaller overlap (to avoid getting stuck in corners)
-3. Set each entity's velocity along that axis to push them in opposite directions
+**Description**: Performs all-pairs AABB overlap detection. For each pair of entities where BOTH have =#:solid? #t=, if they overlap: if one has =#:immovable? #t=, only the other entity is displaced along the shallow overlap axis (and its velocity on that axis is zeroed); if both are immovable, the pair is skipped. Otherwise the two bodies are pushed apart along the smaller overlap axis and their velocities on that axis are set to ±1.
Entities without =#:solid?= or with =#:solid? #f= are skipped. Returns a new entity list with collisions resolved.
@@ -334,7 +330,7 @@ update: (lambda (game dt)
;; Resolve tile collisions on y-axis
(player (resolve-tile-collisions-y player tm))
;; Check if standing on ground
- (player (detect-ground 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))
@@ -353,7 +349,7 @@ update: (lambda (game dt)
7. **resolve-tile-collisions-x**: if hit a tile, snap #:x and zero #:vx
8. **apply-velocity-y**: add #:vy to #:y (move up/down)
9. **resolve-tile-collisions-y**: if hit a tile, snap #:y and zero #:vy
-10. **detect-ground**: probe 1px below feet, set #:on-ground? for next frame's jump check
+10. **detect-on-solid**: set #:on-ground? from tiles and/or other solids (optional entity list), for next frame's jump check
* Top-Down Example
@@ -412,7 +408,7 @@ update: (lambda (game dt)
(lambda (e) (resolve-tile-collisions-x e tm))
apply-velocity-y
(lambda (e) (resolve-tile-collisions-y e tm))
- (lambda (e) (detect-ground e tm)))
+ (lambda (e) (detect-on-solid e tm)))
;; Then resolve entity-entity collisions
(scene-resolve-collisions scene)))
#+end_src
@@ -423,7 +419,7 @@ update: (lambda (game dt)
- =apply-gravity= (all entities fall)
- =apply-velocity-x=, =resolve-tile-collisions-x= (move and collide on x-axis)
- =apply-velocity-y=, =resolve-tile-collisions-y= (move and collide on y-axis)
- - =detect-ground= (set #:on-ground? for next frame)
+ - =detect-on-solid= (set #:on-ground? for next frame)
2. **scene-resolve-collisions**: after all entities are moved and collided with tiles, resolve entity-entity overlaps (boxes pushing apart)
@@ -451,11 +447,11 @@ Same for other functions that take tilemap. The =scene-update-entities= macro ap
;; ... rest of pipeline
#+end_src
-You only need =apply-jump=, =apply-acceleration=, and =apply-gravity=. =detect-ground= is needed to prevent double-jumping.
+You only need =apply-jump=, =apply-acceleration=, and =apply-gravity=. =detect-on-solid= is needed to prevent double-jumping.
** No Gravity
-For top-down or shmup games, skip =apply-jump=, =apply-acceleration=, =apply-gravity=, and =detect-ground=. Just do velocity + tile collision.
+For top-down or shmup games, skip =apply-jump=, =apply-acceleration=, =apply-gravity=, and =detect-on-solid=. Just do velocity + tile collision.
** Knockback
@@ -510,7 +506,7 @@ For large games, consider spatial partitioning (grid, quadtree) to cull entity p
** Double-Jump / Can't Jump
-- Ensure =detect-ground= is called after all collision resolution
+- Ensure =detect-on-solid= is called after tile collision and, when using the optional entity list, after =resolve-entity-collisions=
- Verify =#:on-ground?= is checked in =apply-jump= (not hardcoded)
- Make sure you're checking =input-pressed?= (not =input-held?=) for jump