The trio the author decided on 2026-09-20 is now all built: def is CL's defparameter — its initialiser runs on every daemon re-run, unguarded, so an edited initialiser repaints the same storage on C-c C-c plus re-run — defonce (Clojure's name for CL's defvar, per the author) initialises once behind the .init~once. flag, and defconst stays the image. One parse arm reads both forms; the difference is Ast.reinit, carried to Tast.global's grerun. Emit.startup_plan gives a def no guard flag, and Check.check_global lifts every def initialiser — zero and literal included — into global/<n>, so the host's startup reaches it through the function cell and a re-evaluated def swaps it (Session's def_inits; Emit.redefinition declares the cell for a non-sibling target). The old defvar spelling is refused with the rename and both compiling spellings, and every program, test, doc and editor list is swept — except sand.flan, the author's live WIP, whose seven defvar lines are flagged in FIX.org and keep its three dependent tests red on this branch.
128 lines
5.3 KiB
Plaintext
128 lines
5.3 KiB
Plaintext
;;;; raylib [shapes] example - collision area
|
|
;;;;
|
|
;;;; examples/shapes/shapes_collision_area.c. Picked for one call:
|
|
;;;; get-collision-rec, which is the only binding in the package that takes
|
|
;;;; two Rectangles and answers a third. Everything else in the corpus that
|
|
;;;; crosses a struct either passes one in (Camera2D, Color) or gets one back
|
|
;;;; (get-mouse-position, fade) — this is the first per-frame call doing both
|
|
;;;; at once, and the returned struct comes back through the shim's `out`
|
|
;;;; pointer rather than in registers, which is a different lowering again.
|
|
;;;;
|
|
;;;; It is also the only headless-adjacent thing in the file: both
|
|
;;;; collision-recs? and get-collision-rec are pure arithmetic over their
|
|
;;;; arguments and need no window at all. The acceptance table already asserts
|
|
;;;; the pair; what this adds is the same two calls on a frame path with one
|
|
;;;; rectangle driven by the mouse, where a permuted Rectangle would put the
|
|
;;;; green overlap patch somewhere the two boxes are not.
|
|
;;;;
|
|
;;;; Both TextFormats go through examples/digits.flan the way the core ports
|
|
;;;; do it: draw the literal part, then the number at x plus its width.
|
|
|
|
(import rl "vendor:raylib")
|
|
(import d "digits.flan")
|
|
|
|
(defconst screen-width 800)
|
|
(defconst screen-height 450)
|
|
|
|
;; The top strip the collision message is drawn into, and the floor box B is
|
|
;; not allowed above.
|
|
(defconst screen-upper-limit 40)
|
|
|
|
(defonce box-a rl/Rectangle) ; moves by itself, bounces off the sides
|
|
(defonce box-b rl/Rectangle) ; follows the mouse
|
|
(defonce box-collision rl/Rectangle) ; their overlap, valid only while touching
|
|
(defonce box-a-speed-x i32)
|
|
(defonce paused bool)
|
|
(defonce collision bool)
|
|
|
|
(defn main [] ()
|
|
(rl/init-window screen-width screen-height
|
|
"raylib [shapes] example - collision area")
|
|
(defer (rl/close-window))
|
|
|
|
(set box-a (rl/Rectangle {.x 10.0
|
|
.y (- (/ (f32 screen-height) 2.0) 50.0)
|
|
.width 200.0 .height 100.0}))
|
|
(set box-a-speed-x 4)
|
|
|
|
(set box-b (rl/Rectangle {.x (- (/ (f32 screen-width) 2.0) 30.0)
|
|
.y (- (/ (f32 screen-height) 2.0) 30.0)
|
|
.width 60.0 .height 60.0}))
|
|
|
|
;; A fresh Rectangle is four zeroes, which is the C's `= { 0 }`. It is never
|
|
;; drawn before the first collision sets it.
|
|
(set box-collision (rl/Rectangle {.x 0.0 .y 0.0 .width 0.0 .height 0.0}))
|
|
|
|
(set paused false)
|
|
(set collision false)
|
|
|
|
(rl/set-target-fps 60)
|
|
|
|
(until (rl/window-should-close?)
|
|
;; Update
|
|
(when (not paused)
|
|
(set (.x box-a) (+ (.x box-a) (f32 box-a-speed-x))))
|
|
|
|
;; Bounce at either edge. The test is on the far edge going right and on
|
|
;; the near one going left, so the box reverses on whichever it reaches.
|
|
(when (or (>= (+ (.x box-a) (.width box-a)) (f32 (rl/get-screen-width)))
|
|
(<= (.x box-a) 0.0))
|
|
(set box-a-speed-x (* box-a-speed-x -1)))
|
|
|
|
;; Box B is centred on the mouse and then clamped back inside the play
|
|
;; area — which is the window minus the top strip.
|
|
(set (.x box-b) (- (f32 (rl/get-mouse-x)) (/ (.width box-b) 2.0)))
|
|
(set (.y box-b) (- (f32 (rl/get-mouse-y)) (/ (.height box-b) 2.0)))
|
|
|
|
(if (>= (+ (.x box-b) (.width box-b)) (f32 (rl/get-screen-width)))
|
|
(set (.x box-b) (- (f32 (rl/get-screen-width)) (.width box-b)))
|
|
(when (<= (.x box-b) 0.0) (set (.x box-b) 0.0)))
|
|
|
|
(if (>= (+ (.y box-b) (.height box-b)) (f32 (rl/get-screen-height)))
|
|
(set (.y box-b) (- (f32 (rl/get-screen-height)) (.height box-b)))
|
|
(when (<= (.y box-b) (f32 screen-upper-limit))
|
|
(set (.y box-b) (f32 screen-upper-limit))))
|
|
|
|
(set collision (rl/collision-recs? box-a box-b))
|
|
|
|
;; Only meaningful while they touch: raylib answers a zero rectangle for
|
|
;; two boxes that do not, and the C leaves the previous one in place
|
|
;; rather than reading that back. This follows it.
|
|
(when collision (set box-collision (rl/get-collision-rec box-a box-b)))
|
|
|
|
(when (rl/key-pressed? :key-space) (set paused (not paused)))
|
|
|
|
;; Draw
|
|
(rl/with-drawing
|
|
(rl/clear-background rl/raywhite)
|
|
|
|
(rl/draw-rectangle 0 0 screen-width screen-upper-limit
|
|
(if collision rl/red rl/black))
|
|
|
|
(rl/draw-rectangle-rec box-a rl/gold)
|
|
(rl/draw-rectangle-rec box-b rl/blue)
|
|
|
|
(when collision
|
|
;; The overlap itself, drawn over both boxes. This patch landing
|
|
;; anywhere other than where the gold and the blue cross is what a
|
|
;; permuted Rectangle would look like.
|
|
(rl/draw-rectangle-rec box-collision rl/lime)
|
|
|
|
(rl/draw-text "COLLISION!"
|
|
(- (/ (rl/get-screen-width) 2)
|
|
(/ (rl/measure-text "COLLISION!" 20) 2))
|
|
(- (/ screen-upper-limit 2) 10) 20 rl/black)
|
|
|
|
;; The C's TextFormat("Collision Area: %i", ...). Both dimensions are
|
|
;; truncated to int before multiplying, as the C's two casts do.
|
|
(let [x (- (/ (rl/get-screen-width) 2) 100)
|
|
y (+ screen-upper-limit 10)]
|
|
(set x (+ x (d/draw-piece "Collision Area: " x y 20 rl/black)))
|
|
(d/draw-int (* (i32 (.width box-collision)) (i32 (.height box-collision)))
|
|
x y 20 rl/black)))
|
|
|
|
(rl/draw-text "Press SPACE to PAUSE/RESUME" 20 (- screen-height 35) 20
|
|
rl/lightgray)
|
|
|
|
(rl/draw-fps 10 10))))
|