(use-modules (chickadee) (chickadee math vector) (chickadee math rect) (chickadee math grid) (chickadee render font) (chickadee render sprite) (chickadee render texture) (chickadee render tiled) (chickadee render color) (chickadee render shapes) (oop goops)) (define-class () (pos #:init-keyword #:pos #:getter get-pos) (size #:init-keyword #:size #:getter get-size) (draw-offset #:init-keyword #:draw-offset #:getter get-draw-offset) (y-vel #:init-value 0.0 #:getter get-y-vel #:setter set-y-vel!) (face-direction #:init-keyword #:face-dir #:setter set-face-direction! #:getter get-face-direction) (animation-step #:init-value 0 #:getter get-animation-step #:setter set-animation-step!) (sprite #:init-keyword #:sprite #:getter get-sprite)) (define (draw-animal animal) (define (face-row dir) (if (> 0 dir) 4 12)) (draw-sprite (texture-atlas-ref (get-sprite animal) (+ (face-row (get-face-direction animal)) (truncate (/ (get-animation-step animal) 4)))) (vec2- (get-screen-pos animal) (get-draw-offset animal)))) ;; -------------- Initial game state -------------- (define llama #f) (define tile-map #f) (define view-pos #v(0.0 0.0)) (define grid (make-grid 16)) (define show-hitboxes #f) (define (load) (set! llama (make #:pos #v(200.0 200.0) #:size #v(128.0 128.0) #:draw-offset #v(15 12) #:face-dir 1 #:sprite (split-texture (load-image "llama_walk.png") 80 80 #:spacing 48 #:margin 24))) (grid-add grid 'llama 200.0 200.0 50.0 64.0) (set! tile-map (load-tile-map "llama.tmx")) ;; Add objects from map to grid (define (add-to-grid obj) (let ((shape (map-object-shape obj))) (grid-add grid (map-object-id obj) (rect-x shape) (- (rect-y shape) (rect-height shape)) (rect-width shape) (rect-height shape)))) (let ((objects (object-layer-objects (vector-ref (tile-map-layers tile-map) 1)))) (for-each (lambda (obj) (add-to-grid obj)) objects))) ;; ------------------------------------------------ (define (draw alpha) (draw-tile-map tile-map #:position (vec2* view-pos -1.0)) (draw-animal llama) (when show-hitboxes (let ((col (make-color 0.0 0.0 0.7 0.8))) (for-each-item (lambda (item rect) (draw-filled-rect (rect-move-by-vec2 rect (vec2* view-pos -1)) col)) grid)))) (define (get-screen-pos animal) (vec2- (get-pos animal) view-pos)) (define (rect-xy rect) #v((rect-x rect) (rect-y rect))) (define (get-screen-rect animal) (let ((screen-pos (get-screen-pos animal))) (make-rect (vec2-x screen-pos) (vec2-y screen-pos) (vec2-x (get-size animal)) (vec2-y (get-size animal))))) (define (overshoot small-rect big-rect) (let ((moved-small-rect (rect-clamp small-rect big-rect))) (vec2- (rect-xy small-rect) (rect-xy moved-small-rect)))) (define (update tstep) (let ((x-vel 0.0)) (define (slide-llama-only a b) (if (eq? a 'llama) slide #f)) (when (key-pressed? 'right) (set-face-direction! llama 1) (set! x-vel 1.0) (set-animation-step! llama (floor-remainder (+ (get-animation-step llama) -1) 16))) (when (key-pressed? 'left) (set-face-direction! llama -1) (set! x-vel -1.0) (set-animation-step! llama (floor-remainder (- (get-animation-step llama) 1) 16))) (vec2-add! (get-pos llama) #v((* x-vel tstep 0.2) 0.0)) (grid-move grid 'llama (get-pos llama) slide-llama-only)) ;; Gravity (define (slide-llama-only-and-zero-yvel a b) (if (eq? a 'llama) (lambda (item item-rect other other-rect goal) (set-y-vel! llama 0.0) (slide item item-rect other other-rect goal)) #f)) (set-y-vel! llama (- (get-y-vel llama) 0.4)) (vec2-add! (get-pos llama) #v(0.0 (get-y-vel llama))) (grid-move grid 'llama (get-pos llama) slide-llama-only-and-zero-yvel) ;; Ensure llama is near centre of screen (let ((fovea (make-rect 150.0 150.0 350.0 350.0)) (llama-rect (get-screen-rect llama))) (unless (rect-within? llama-rect fovea) (vec2-add! view-pos (overshoot llama-rect fovea))))) (define (key-press key scancode modifier repeat?) (case key ((q) (abort-game)) ((f1) (set! show-hitboxes (not show-hitboxes))) ((space) (unless repeat? (set-y-vel! llama 8.0))))) (run-game #:window-title "Hey Llama!" #:load load #:draw draw #:key-press key-press #:update-hz 60 #:update update)