spook

A "game" for the 2023 Autumn Lisp Game Jam. Won first place! (from the bottom...)
Log | Files | Refs | LICENSE

commit ce1b8e15096c3b2911e67ff18dbdf25a74107609
parent b2a46bcfb8ede1eeb7416b495b924bb0c1612e21
Author: Yuval Langer <yuvallangerontheroad@gmail.com>
Date:   Fri, 10 Nov 2023 13:42:50 +0200

Use makers, getters, setters, and predicates for the alist objects.

Diffstat:
Mmain.scm | 344+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
1 file changed, 223 insertions(+), 121 deletions(-)

diff --git a/main.scm b/main.scm @@ -71,18 +71,26 @@ (define bad-brick-fill-style "rgb(200, 0, 0)") (define cloud-fill-style "#DDE7EE") (define cloud-fill-style "#bbb") -(define brick-width (/ (.width canvas) 3)) +(define number-of-lanes 3) +(define brick-width (/ (.width canvas) number-of-lanes)) +(define brick-half-width (/ brick-width 2)) (define brick-height 40) -(define player-width 40) -(define player-height 20) -(define cloud-width 150) -(define cloud-height 75) +(define brick-half-height (/ brick-height 2)) +(define player-half-width 20) +(define player-width (* 2 player-half-width)) +(define player-half-height 10) +(define player-height (* 2 player-half-height)) +(define player-speed-x 0.7) +(define cloud-half-width 75) +(define cloud-width (* 2 cloud-half-width)) +(define cloud-half-height 37) +(define cloud-height (* 2 cloud-half-height)) ;;; END Constants. (define (draw-player player) (set! (.fillStyle ctx) player-fill-style) - (draw-rect (assq-ref player 'x) - (assq-ref player 'y) + (draw-rect (- (element-center-x player) player-half-width) + (- (element-center-y player) player-half-height) player-width player-height)) @@ -106,23 +114,127 @@ (define (cursor-x cursor) (car cursor)) -(define (north element) (assq-ref element 'y)) -(define (south element) (+ (assq-ref element 'y) - (assq-ref element 'height))) -(define (west element) (assq-ref element 'x)) -(define (east element) (+ (assq-ref element 'x) - (assq-ref element 'width))) +;;; Makers: + +(define (make-player) + `((center-x . ,(/ (.width canvas) + 2)) + (center-y . ,(- (.height canvas) + 50)) + (half-width . ,player-half-width) + (half-height . ,player-half-height) + (velocity-x . 0) + (velocity-y . 0))) + +(define (make-new-cloud) + (let* ((cloud-y (random-uniform 10 + (/ (.height canvas) + 5)))) + `((center-x . ,(* -0.999 cloud-width)) + (center-y . ,cloud-y) + (half-width . ,cloud-half-width) + (half-height . ,cloud-half-height) + (velocity-x . 0.05) + (velocity-y . 0) + (idspispopd . #f)))) + +(define (make-new-falling-brick) + (let* ((zero-one-or-two (randint number-of-lanes))) + `((center-x . ,(* zero-one-or-two + (/ (.width canvas) + 3))) + (center-y . ,(/ (.height canvas) + 10)) + (half-width . ,brick-half-width) + (half-height . ,brick-half-height) + (velocity-x . 0) + (velocity-y . 0.25) + (idspispopd . #f) + (is-good . ,(if (= (randint 2) 0) + #t + #f))))) + +;;; END Makers. + +;;; Getters: + +(define (element-center-x element) (assq-ref element 'center-x)) +(define (element-left element) + (- (element-center-x element) + (element-half-width element))) +(define (element-right element) + (+ (element-center-x element) + (element-half-width element))) +(define (element-center-y element) (assq-ref element 'center-y)) +(define (element-top element) + (- (element-center-y element) + (element-half-height element))) +(define (element-bottom element) + (+ (element-center-y element) + (element-half-height element))) +(define (element-velocity-x element) (assq-ref element 'velocity-x)) +(define (element-velocity-y element) (assq-ref element 'velocity-y)) +(define (element-width element) (* 2 (element-half-width element))) +(define (element-half-width element) (assq-ref element 'half-width)) +(define (element-height element) (* 2 (element-half-height element))) +(define (element-half-height element) (assq-ref element 'half-height)) +(define (extents-x-low extents) (caar extents)) +(define (extents-x-high extents) (cdar extents)) +(define (extents-y-low extents) (cadr extents)) +(define (extents-y-high extents) (cddr extents)) + +;;; END Getters. + + +;;; Setters: + +(define (set-element-center-x! element value) + (assq-set! element 'center-x value)) +(define (set-element-center-y! element value) + (assq-set! element 'center-y value)) +(define (set-element-left! element value) + (assq-set! element + 'center-x + (+ (element-center-x element) + (element-half-width element)))) +(define (set-element-top! element value) + (assq-set! element + 'center-y + (+ (element-center-y element) + (element-half-height element)))) +(define (set-element-velocity-x! element value) + (assq-set! element 'velocity-x value)) +(define (set-element-velocity-y! element value) + (assq-set! element 'velocity-y value)) +(define (set-element-idspispopd! element value) + (assq-set! element 'idspispopd value)) + +;;; END Setters. + +;;; Predicates: + +(define (element-is-good? element) (assq-ref element 'is-good)) + +(define (element-idspispopd? element) (assq-ref element 'idspispopd)) + +(define (element-inside-canvas? element) + (and (<= 0 (element-right element)) + (<= (element-left) (.width canvas)) + (<= 0 (element-bottom element)) + (<= (element-top element) (.height canvas)))) (define (collision? element-a element-b) - (not (or (assq-ref element-b 'idspispopd) - (< (east element-a) - (west element-b)) - (< (east element-b) - (west element-a)) - (< (south element-a) - (north element-b)) - (< (south element-b) - (north element-a))))) + (not (or (element-idspispopd? element-b) + (< (element-right element-a) + (element-left element-b)) + (< (element-right element-b) + (element-left element-a)) + (< (element-bottom element-a) + (element-top element-b)) + (< (element-bottom element-b) + (element-top element-a))))) + +;;; END Predicates. ;;; Global variables: (~_~) (define last-loop-time 0) @@ -132,91 +244,82 @@ (define next-cloud-time 0) (define cursor (cons (/ (.width canvas) 2) (/ (.height canvas) 2))) -(define player - `((x . ,(/ (.width canvas) - 2)) - (y . ,(- (.height canvas) - 50)) - (width . ,player-width) - (height . ,player-height))) +(define player (make-player)) (define score 0) ;;; END Global variables. -(define (make-new-cloud) - (let* ((cloud-y (random-uniform 10 - (/ (.height canvas) - 5)))) - `((x . ,(* -0.999 cloud-width)) - (y . ,cloud-y) - (width . ,cloud-width) - (height . ,cloud-height) - (x-velocity . 0.05) - (y-velocity . 0) - (idspispopd . #f)))) +;;; Drawers: (define (draw-clouds clouds) (set! (.fillStyle ctx) cloud-fill-style) (for-each (lambda (cloud) - (draw-rect (assq-ref cloud 'x) - (assq-ref cloud 'y) - (assq-ref cloud 'width) - (assq-ref cloud 'height))) + (draw-rect (element-center-x cloud) + (element-center-y cloud) + (element-width cloud) + (element-height cloud))) clouds)) -(define (make-new-falling-brick) - (let* ((zero-one-or-two (randint 3))) - `((x . ,(* zero-one-or-two - (/ (.width canvas) - 3))) - (y . ,(/ (.height canvas) - 10)) - (width . ,brick-width) - (height . ,brick-height) - (x-velocity . 0) - (y-velocity . 0.25) - (idspispopd . #f) - (is-good . ,(if (= (randint 2) 0) - #t - #f))))) - (define (draw-falling-bricks bricks) (for-each (lambda (brick) - (if (assq-ref brick 'is-good) + (if (element-is-good? brick) (set! (.fillStyle ctx) good-brick-fill-style) (set! (.fillStyle ctx) bad-brick-fill-style)) - (draw-rect (assq-ref brick 'x) - (assq-ref brick 'y) - (assq-ref brick 'width) - (assq-ref brick 'height))) + (draw-rect (element-center-x brick) + (element-center-y brick) + (element-width brick) + (element-height brick))) bricks)) -(define (move-element! dt element) - (let* ((x (assq-ref element 'x)) - (x-velocity (assq-ref element 'x-velocity)) - (new-x (+ x (* x-velocity dt))) - (y (assq-ref element 'y)) - (y-velocity (assq-ref element 'y-velocity)) - (new-y (+ y (* y-velocity dt)))) - (assq-set! element - 'x - new-x) - (assq-set! element - 'y - new-y))) - -(define (move-elements! dt elements) - (map (cut move-element! dt <>) - elements)) +(define (draw-text) + (set! (.font ctx) "30px monospace") + (if (< score 0) + (set! (.fillStyle ctx) bad-brick-fill-style) + (set! (.fillStyle ctx) good-brick-fill-style)) + (%inline ".fillText" + ctx + score + 10 + 50)) + +(define (draw) + (clear-rect) + (draw-clouds clouds) + (draw-player player) + (draw-falling-bricks falling-bricks) + (draw-text)) -(define (element-inside-canvas? element) - (let* ((y (assq-ref element 'y)) - (x (assq-ref element 'x)) - (width (assq-ref element 'width)) - (height (assq-ref element 'height))) - (and (<= 0 (+ x width)) - (<= x (.width canvas)) - (<= 0 y) - (<= (+ y height) (.height canvas))))) +;;; END Drawers. + +(define (clip value low high) + ((o (min <> high) + (max <> min)) + value)) + +(define (move-element! dt element &optional clip-extents) + (let* ((previous-center-x (element-center-x element)) + (velocity-x (element-velocity-x element)) + (new-center-x (+ previous-center-x (* velocity-x dt))) + (clipped-new-center-x (if (void? clip-extents) + new-center-x + (clip new-center-x + (extents-x-low clip-extents) + (extents-x-high clip-extents)))) + (previous-center-y (element-center-y element)) + (velocity-y (element-velocity-y element)) + (new-center-y (+ previous-center-y (* velocity-y dt))) + (clipped-new-center-y (if (void? clip-extents) + new-center-y + (clip new-center-y + (extents-y-low clip-extents) + (extents-y-high clip-extents))))) + (set-element-center-x! element + clipped-new-center-x) + (set-element-center-y! element + clipped-new-center-y))) + +(define (move-elements! dt elements &optional extents) + (for-each (cut move-element! dt <> extents) + elements)) (define (filter-out-of-canvas-elements elements) (filter element-inside-canvas? @@ -237,29 +340,10 @@ (+ our-sum (car our-list))))))) -(define (draw-text) - (set! (.font ctx) "30px monospace") - (if (< score 0) - (set! (.fillStyle ctx) bad-brick-fill-style) - (set! (.fillStyle ctx) good-brick-fill-style)) - (%inline ".fillText" - ctx - score - 10 - 50)) - -(define (draw) - (draw-clouds clouds) - (draw-player player) - (draw-falling-bricks falling-bricks) - (draw-text)) - (define (loop time) (let* ((dt (- time last-loop-time))) (set! last-loop-time time) - (clear-rect) - (move-elements! dt falling-bricks) (move-elements! dt clouds) @@ -280,13 +364,33 @@ (random-uniform 750 1000)))) ;; Get input: - (assq-set! player - 'x - ((o (cut - <> (/ player-width 2)) - (cut max <> (/ player-width 2)) - (cut min <> (- (.width canvas) - (/ player-width 2)))) - (cursor-x cursor))) + (let* ((wanted-player-center-x (cursor-x cursor)) + (previous-player-center-x (element-center-x player)) + (ratsui-minus-matsui (- wanted-player-center-x + previous-player-center-x)) + (player-direction-x (cond + ((< (abs ratsui-minus-matsui) + 5) + 0) + ((> ratsui-minus-matsui + 0) + 1) + (else -1))) + (new-player-velocity-x (* player-direction-x + player-speed-x))) + (set-element-velocity-x! player new-player-velocity-x)) + (move-element! dt player (list (cons (+ 0 + (/ player-width + 2)) + (- (.width canvas) + (/ player-width + 2))) + (cons (+ 0 + (/ player-height + 2)) + (- (.height canvas) + (/ player-height + 2))))) (set! falling-bricks (filter-out-of-canvas-elements falling-bricks)) (set! clouds (filter-out-of-canvas-elements clouds)) @@ -294,10 +398,8 @@ (let ((bricks-collided (get-collided-bricks player falling-bricks))) (for-each (lambda (brick) - (assq-set! brick - 'idspispopd - #t) - (if (assq-ref brick 'is-good) + (set-element-idspispopd! brick #t) + (if (element-is-good? brick) (begin (set! score (+ score 1))) (begin