#lang s-exp "../moby-lang.ss"
(define-struct world
(posn r vel target-posn score))
(define WIDTH 300)
(define HEIGHT 460)
(define TARGET-RADIUS 30)
(define-struct vel (x y))
(define initial-world
(make-world (make-posn (quotient WIDTH 2)
(quotient HEIGHT 2))
30
(make-vel 0 0)
(make-posn 0 0)
0))
(define (tick w)
(cond
[(collide? w)
(make-world (posn+vel (world-posn w)
(world-vel w))
30
(world-vel w)
(make-random-posn)
(add1 (world-score w)))]
[else
(make-world (posn+vel (world-posn w)
(world-vel w))
(- (world-r w) 1/2)
(world-vel w)
(world-target-posn w)
(world-score w))]))
(define (tilt w azimuth pitch roll)
(make-world (world-posn w)
(world-r w)
(make-vel roll (- pitch))
(world-target-posn w)
(world-score w)))
(define (render w)
(maybe-add-game-over
w
(place-image/posn
(text (format "Score: ~a" (world-score w))
20 "black")
(make-posn 20 20)
(place-image/posn
(circle TARGET-RADIUS "solid" "red")
(world-target-posn w)
(place-image/posn
(circle (world-r w) "solid" "blue")
(world-posn w)
(empty-scene WIDTH HEIGHT))))))
(define (maybe-add-game-over w a-scene)
(cond
[(game-ends? w)
(place-image/posn
(text "GAME OVER" 30 "red")
(make-posn 20 100)
a-scene)]
[else
a-scene]))
(define (collide? w)
(< (distance (world-posn w)
(world-target-posn w))
(+ TARGET-RADIUS (world-r w))))
(define (game-ends? w)
(<= (world-r w) 1))
(define (make-random-posn)
(make-posn (random WIDTH)
(random HEIGHT)))
(define (posn+vel a-posn a-vel)
(make-posn (clamp (+ (posn-x a-posn)
(vel-x a-vel))
0 WIDTH)
(clamp (+ (posn-y a-posn)
(vel-y a-vel))
0 HEIGHT)))
(define (clamp x a b)
(cond [(> x b) b]
[(< x a) a]
[else x]))
(define (distance posn-1 posn-2)
(sqrt
(+ (sqr (- (posn-x posn-1)
(posn-x posn-2)))
(sqr (- (posn-y posn-1)
(posn-y posn-2))))))
(define (place-image/posn img a-posn a-scene)
(place-image img
(posn-x a-posn)
(posn-y a-posn)
a-scene))
(js-big-bang initial-world
(on-tick 1/20 tick)
(on-tilt tilt)
(on-redraw render)
(stop-when game-ends?))