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.
134 lines
5.9 KiB
Plaintext
134 lines
5.9 KiB
Plaintext
;;;; raylib [models] example - box collisions
|
|
;;;;
|
|
;;;; examples/models/models_box_collisions.c. The previous lane's finding was
|
|
;;;; that the whole models category is refused by the importer for want of a
|
|
;;;; defstruct, and that a models example is therefore mostly a binding
|
|
;;;; exercise. That is true of the twenty that load a Model — but not of this
|
|
;;;; one, which is why it is here: nothing in it is a Model, a Mesh or a
|
|
;;;; Material. It is two cubes, a sphere and one aggregate the package did not
|
|
;;;; describe.
|
|
;;;;
|
|
;;;; That aggregate is BoundingBox, and it is two Vector3s and nothing else —
|
|
;;;; no owned pointer, no array, no lifetime. One `defstruct` in
|
|
;;;; vendor/raylib/raylib.flan un-refuses four raylib functions at once
|
|
;;;; (CheckCollisionBoxes, CheckCollisionBoxSphere, DrawBoundingBox and
|
|
;;;; GetRayCollisionBox), and that is the cheapest widening of the 3D surface
|
|
;;;; available anywhere in the tree. Ray and RayCollision went in beside it
|
|
;;;; for examples/core-3d-picking.flan and for the same reason.
|
|
;;;;
|
|
;;;; So the answer to "is a models example just a binding exercise" is: the
|
|
;;;; ones that need Model are, and this one is the counterexample. What
|
|
;;;; separates them is not the category, it is whether the struct owns memory.
|
|
;;;;
|
|
;;;; What it also exercises, and what needed hand-writing rather than
|
|
;;;; generating: draw-cube-v, draw-sphere and draw-sphere-wires. All three
|
|
;;;; were in the generated half already, and all three moved to the
|
|
;;;; hand-written one here on `bindings`'s own rule — they are inside a frame,
|
|
;;;; in an example that ships in examples/. draw-cube-v in particular was
|
|
;;;; named there as generated *because nothing called it*; something calls it
|
|
;;;; now.
|
|
;;;;
|
|
;;;; The collision maths is written twice in the C, once per test, building
|
|
;;;; the player's box inline both times. It is a function here for the reason
|
|
;;;; the eyes example gives: two copies of the same eight expressions cannot
|
|
;;;; be checked against each other by reading them.
|
|
|
|
(import rl "vendor:raylib")
|
|
|
|
(defconst screen-width 800)
|
|
(defconst screen-height 450)
|
|
|
|
(defvar camera rl/Camera3D)
|
|
|
|
(defvar player-position rl/Vector3)
|
|
(defvar player-size rl/Vector3)
|
|
(defvar player-color rl/Color)
|
|
|
|
(defvar enemy-box-pos rl/Vector3)
|
|
(defvar enemy-box-size rl/Vector3)
|
|
(defvar enemy-sphere-pos rl/Vector3)
|
|
|
|
(defconst enemy-sphere-size f32 1.5)
|
|
|
|
;; A box centred on `centre` with the given extents. raylib's BoundingBox is
|
|
;; min-corner/max-corner, not centre/size, and every collision call in the
|
|
;; family takes the corner form — so this is the conversion the C writes out
|
|
;; longhand at each of its two call sites.
|
|
(defn box-around [centre rl/Vector3 size rl/Vector3] rl/BoundingBox
|
|
(rl/BoundingBox
|
|
{.min (rl/Vector3 {.x (- (.x centre) (/ (.x size) 2.0))
|
|
.y (- (.y centre) (/ (.y size) 2.0))
|
|
.z (- (.z centre) (/ (.z size) 2.0))})
|
|
.max (rl/Vector3 {.x (+ (.x centre) (/ (.x size) 2.0))
|
|
.y (+ (.y centre) (/ (.y size) 2.0))
|
|
.z (+ (.z centre) (/ (.z size) 2.0))})}))
|
|
|
|
(defn main [] ()
|
|
(rl/init-window screen-width screen-height
|
|
"raylib [models] example - box collisions")
|
|
(defer (rl/close-window))
|
|
|
|
;; The C writes this camera as a brace initialiser with a trailing 0 for the
|
|
;; projection, which is CAMERA_PERSPECTIVE. Named here, because the defenum
|
|
;; exists precisely so that the 0 does not have to be remembered.
|
|
(set camera (rl/Camera3D {.position (rl/Vector3 {.x 0.0 .y 10.0 .z 10.0})
|
|
.target (rl/Vector3 {.x 0.0 .y 0.0 .z 0.0})
|
|
.up (rl/Vector3 {.x 0.0 .y 1.0 .z 0.0})
|
|
.fovy 45.0
|
|
.projection :perspective}))
|
|
|
|
(set player-position (rl/Vector3 {.x 0.0 .y 1.0 .z 2.0}))
|
|
(set player-size (rl/Vector3 {.x 1.0 .y 2.0 .z 1.0}))
|
|
(set player-color rl/green)
|
|
|
|
(set enemy-box-pos (rl/Vector3 {.x -4.0 .y 1.0 .z 0.0}))
|
|
(set enemy-box-size (rl/Vector3 {.x 2.0 .y 2.0 .z 2.0}))
|
|
(set enemy-sphere-pos (rl/Vector3 {.x 4.0 .y 0.0 .z 0.0}))
|
|
|
|
(rl/set-target-fps 60)
|
|
|
|
(until (rl/window-should-close?)
|
|
;; Update. The arrow keys move on the XZ plane, and the C's else-if chain
|
|
;; means only one direction applies per frame — diagonal movement is not
|
|
;; possible, deliberately.
|
|
(cond
|
|
(rl/key-down? :right) (set (.x player-position) (+ (.x player-position) 0.2))
|
|
(rl/key-down? :left) (set (.x player-position) (- (.x player-position) 0.2))
|
|
(rl/key-down? :down) (set (.z player-position) (+ (.z player-position) 0.2))
|
|
(rl/key-down? :up) (set (.z player-position) (- (.z player-position) 0.2)))
|
|
|
|
(let [player-box (box-around player-position player-size)
|
|
hit (or (rl/check-collision-boxes player-box
|
|
(box-around enemy-box-pos enemy-box-size))
|
|
(rl/check-collision-box-sphere player-box enemy-sphere-pos
|
|
enemy-sphere-size))]
|
|
(set player-color (if hit rl/red rl/green)))
|
|
|
|
;; Draw
|
|
(rl/begin-drawing)
|
|
(rl/clear-background rl/raywhite)
|
|
|
|
(rl/begin-mode-3d camera)
|
|
|
|
(rl/draw-cube enemy-box-pos (.x enemy-box-size) (.y enemy-box-size)
|
|
(.z enemy-box-size) rl/gray)
|
|
(rl/draw-cube-wires enemy-box-pos (.x enemy-box-size) (.y enemy-box-size)
|
|
(.z enemy-box-size) rl/darkgray)
|
|
|
|
;; draw-sphere is draw-sphere-ex at 16 rings and 16 slices; the wires form
|
|
;; takes them because the tessellation is only visible in the wireframe.
|
|
(rl/draw-sphere enemy-sphere-pos enemy-sphere-size rl/gray)
|
|
(rl/draw-sphere-wires enemy-sphere-pos enemy-sphere-size 16 16 rl/darkgray)
|
|
|
|
(rl/draw-cube-v player-position player-size player-color)
|
|
|
|
(rl/draw-grid 10 1.0)
|
|
|
|
(rl/end-mode-3d)
|
|
|
|
(rl/draw-text "Move player with arrow keys to collide" 220 40 20 rl/gray)
|
|
|
|
(rl/draw-fps 10 10)
|
|
|
|
(rl/end-drawing)))
|