diff options
Diffstat (limited to 'docs/physics.org')
| -rw-r--r-- | docs/physics.org | 40 |
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 |
