105 lines
4.8 KiB
Plaintext
105 lines
4.8 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
|
|
;;;; check-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.fln 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.fln"
|
|
|
|
const screen-width = 800
|
|
const screen-height = 450
|
|
|
|
;; The top strip the collision message is drawn into, and the floor box B is
|
|
;; not allowed above.
|
|
const screen-upper-limit = 40
|
|
|
|
once box-a: rl/Rectangle ; moves by itself, bounces off the sides
|
|
once box-b: rl/Rectangle ; follows the mouse
|
|
once box-collision: rl/Rectangle ; their overlap, valid only while touching
|
|
once box-a-speed-x: i32
|
|
once paused: bool
|
|
once collision: bool
|
|
|
|
fn main() -> ()
|
|
rl/init-window(screen-width, screen-height,
|
|
"raylib [shapes] example - collision area")
|
|
defer rl/close-window()
|
|
box-a = rl/Rectangle{.x 10.0, .y f32(screen-height) / 2.0 - 50.0, .width 200.0, .height 100.0}
|
|
box-a-speed-x = 4
|
|
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.
|
|
box-collision = rl/Rectangle{.x 0.0 .y 0.0 .width 0.0 .height 0.0}
|
|
paused = false
|
|
collision = false
|
|
rl/set-target-fps(60)
|
|
until rl/window-should-close()
|
|
;; Update
|
|
if not paused
|
|
box-a.x += 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.
|
|
if box-a.x + box-a.width >= f32(rl/get-screen-width()) or box-a.x <= 0.0
|
|
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.
|
|
box-b.x = f32(rl/get-mouse-x()) - box-b.width / 2.0
|
|
box-b.y = f32(rl/get-mouse-y()) - box-b.height / 2.0
|
|
if box-b.x + box-b.width >= f32(rl/get-screen-width())
|
|
box-b.x = f32(rl/get-screen-width()) - box-b.width
|
|
elif box-b.x <= 0.0
|
|
box-b.x = 0.0
|
|
if box-b.y + box-b.height >= f32(rl/get-screen-height())
|
|
box-b.y = f32(rl/get-screen-height()) - box-b.height
|
|
elif box-b.y <= f32(screen-upper-limit)
|
|
box-b.y = f32(screen-upper-limit)
|
|
collision = rl/check-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.
|
|
if collision
|
|
box-collision = rl/get-collision-rec(box-a, box-b)
|
|
if rl/is-key-pressed(:key-space)
|
|
paused = not paused
|
|
;; Draw
|
|
rl/with-drawing:
|
|
rl/clear-background(rl/raywhite)
|
|
rl/draw-rectangle(0, 0, screen-width, screen-upper-limit,
|
|
if collision then rl/red else rl/black)
|
|
rl/draw-rectangle-rec(box-a, rl/gold)
|
|
rl/draw-rectangle-rec(box-b, rl/blue)
|
|
if 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
|
|
x += d/draw-piece("Collision Area: ", x, y, 20, rl/black)
|
|
d/draw-int(i32(box-collision.width) * i32(box-collision.height), 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)
|