Three shapes, two text, three textures, one models and one core, picked for binding surface rather than for how they look. shapes-basic-shapes brings in six draw families nothing had called — the circle and rectangle gradients, the triangles, all three poly draws — and is the first call in the corpus to pass two Colors or three Vector2s at once. shapes-collision-area is get-collision-rec, the only binding that takes two Rectangles and answers a third, on a frame path. shapes-following-eyes is the raymath gap measured rather than worked around: every line of it is vector arithmetic written without a vector library, the way the C writes it. text-input-box drains get-char-pressed's queue, which no example had read, and needed a MouseCursor defenum for set-mouse-cursor. text-writing-anim replaces TextSubtext — unbindable, it answers a pointer into a rotating static buffer — with (string (slice b 0 n)), which is the same operation without the shared state. textures-image-generation runs nine Gen* calls and the gen/upload/unload-image path, all procedural, no file on disk. textures-fog-of-war needed a TextureFilter defenum: the smooth fog edge is entirely :bilinear on a 25x15 render texture, and it is also the first draw-texture-pro with a negative source height. textures-mouse-painting is the same render texture used as a document rather than as scratch, plus the round trip back off the GPU — load-image-from-texture, image-flip-vertical, export-image — which nothing had run. models-box-collisions is the counterexample to "a models example is a binding exercise": nothing in it is a Model, and one BoundingBox defstruct un-refuses four functions. core-3d-picking is the only caller anywhere for Ray and RayCollision, and picking is the inverse of the get-world-to-screen the corpus already had. Added to vendor/raylib: defstructs BoundingBox, Ray and RayCollision; defenums MouseCursor and TextureFilter with their mapping lines in bindings; hand-written declare-c for SetMouseCursor, SetTextureFilter, DrawCubeV, DrawSphere, DrawSphereWires, DrawRay and GetScreenToWorldRay, each excluded from the generated half on the rule bindings already states. generated.flan regenerated against raylib 5.5: 272 declarations, 117 refused, every defstruct, hand-written declare-c and mapped constant agreeing with the header.
130 lines
5.3 KiB
Plaintext
130 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)
|
|
|
|
(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/begin-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)
|
|
|
|
(rl/end-drawing)))
|