;;;; 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) (defvar box-a rl/Rectangle) ; moves by itself, bounces off the sides (defvar box-b rl/Rectangle) ; follows the mouse (defvar box-collision rl/Rectangle) ; their overlap, valid only while touching (defvar box-a-speed-x i32) (defvar paused bool) (defvar 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? :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))))