;; **************************************** ;; * Csu 211 : 4/7/2008 ;; * Final Few Lectures Code... ;; * The making of "Asteroids" ;; **************************************** ;; Structures ;; **************************************** ;; The Ship... (define-struct ship (x y rad boost dir)) ;; The Bullets... (define-struct bull (x y dir)) ;; The Asteroids (Objects)... (define-struct obj (x y size dir)) ;; The Whole World (define-struct world (ship lob loo)) ;; Screen Size (define size 500) ;; pt-from: Number Number Number Number -> Posn ;; Calculate the point starting at (x,y) moving 'dist' in the direction ;; of 'rad' radians (define (pt-from x y rad dist) (make-posn (+ x (* (cos rad) dist)) (+ y (* (sin rad) dist)))) ;; draw-boost: Number Number Posn Posn Number Scene -> Scene ;; Draw the boosters onto the given Scene (define (draw-boost rad x y lp rp i scn) (cond [(< i 1) scn] [else (local ((define cbp (pt-from x y (+ rad pi) (+ 15 (* 4 i)))) (define color (cond [(even? i) 'red] [else 'orange]))) (add-line (add-line (draw-boost rad x y lp rp (- i 1) scn) (posn-x cbp) (posn-y cbp) (posn-x lp) (posn-y lp) color) (posn-x cbp) (posn-y cbp) (posn-x rp) (posn-y rp) color))])) ;; ship-image: Number Number Boolean Scene -> Scene ;; Draw the image of the ship @ (x,y) poiting in 'rad' direction with ;; possible boosters into the given scene. (define (ship-image rad x y bst scn) (local ((define tp (pt-from x y rad 30)) (define lp (pt-from x y (- rad (* pi 4/5)) 20)) (define rp (pt-from x y (+ rad (* pi 4/5)) 20))) (add-line (add-line (add-line (cond [(not bst) scn] [else (draw-boost (+ rad .1) x y lp rp 7 (draw-boost (- rad .15) x y lp rp 7 scn))]) (posn-x tp) (posn-y tp) (posn-x lp) (posn-y lp) 'black) (posn-x tp) (posn-y tp) (posn-x rp) (posn-y rp) 'black) (posn-x lp) (posn-y lp) (posn-x rp) (posn-y rp) 'black))) ;; draw-lob: (listof O-or-B) (O-or-B -> Number) (O-or-B -> Number) ;; (O-or-B -> Number) Symbol Scene -> Scene ;; Draw a list of Objects or Bullets into the given scene using the accessor ;; functions to pull out the needed fields. (define (draw-lob lob get-x get-y get-sz color scn) (local ((define (one b scn) (place-image (circle (get-sz b) 'solid color) (get-x b) (get-y b) scn))) (foldl one scn lob))) ;; draw: World -> Scene ;; Draw the world into the empty scene (define (draw w) (draw-lob (world-loo w) obj-x obj-y obj-size 'black (draw-lob (world-lob w) bull-x bull-y (lambda (b) 5) 'magenta (shrink (ship-image (ship-rad (world-ship w)) (ship-x (world-ship w)) (ship-y (world-ship w)) (ship-boost (world-ship w)) (empty-scene size size)) 0 0 size size)))) ;; doSym: World Symbol -> World ;; React to a key press of up/down/left/right (define (doSym w s) (make-world (make-ship (ship-x (world-ship w)) (ship-y (world-ship w)) (+ (ship-rad (world-ship w)) (cond [(symbol=? 'right s) (/ pi 8)] [(symbol=? 'left s) (- (/ pi 8))] [else 0])) (cond [(symbol=? 'down s) true] [(symbol=? 'release s) false] [else (ship-boost (world-ship w))]) (ship-dir (world-ship w))) (cond [(symbol=? 'up s) (local ((define bst (pt-from (ship-x (world-ship w)) (ship-y (world-ship w)) (ship-rad (world-ship w)) 35))) (cons (make-bull (posn-x bst) (posn-y bst) (ship-rad (world-ship w))) (world-lob w)))] [else (world-lob w)]) (world-loo w))) ;; key: World Symbol-or-Char -> World ;; React to a key event (define (key w s/c) (cond [(symbol? s/c) (doSym w s/c)] [else w])) ;; move-lob: (O-or-B -> Number) (O-or-B -> Number) (O-or-B -> Number) ;; (O-or-B Number Number Number -> O-or-B) (listof O-or-B) -> (listof O-or-B) ;; Move all the objects/bullets in the given list base on their directions (define (move-lob get-x get-y get-dir make lob) (local ((define (one b) (local ((define nxt (pt-from (get-x b) (get-y b) (get-dir b) 5))) (make b (posn-x nxt) (posn-y nxt) (get-dir b))))) (map one lob))) ;; filt-lob: (listof Bullet) -> (listof Bullet) ;; Filter the bullet list to only those still on the screen (define (filt-lob lob) (filter (lambda (b) (and (< (bull-x b) size) (> (bull-x b) 0) (< (bull-y b) size) (> (bull-y b) 0))) lob)) ;; tick: World -> World ;; React to a tick-event... move all the objects in the world (define (tick w) (local ((define oshp (world-ship w)) (define shp (move-ship (ship-rad oshp) (ship-x oshp) (ship-y oshp) (ship-boost oshp) (ship-dir oshp)))) (make-world shp (filt-lob (move-lob bull-x bull-y bull-dir (lambda (b x y d) (make-bull x y d)) (world-lob w))) (map check-obj (move-lob obj-x obj-y obj-dir (lambda (o x y d) (make-obj x y (obj-size o) d)) (world-loo w)))))) ;; check: Number -> Number ;; Wrap a number based on the size of the screen (define (check n) (cond [(< n 0) (+ n size)] [(> n size) 0] [else n])) ;; check-obj: Object -> Object ;; Wrap an Object based on the size of the screen (define (check-obj o) (make-obj (check (obj-x o)) (check (obj-y o)) (obj-size o) (obj-dir o))) ;; check-dir: Boolean Posn Number -> Posn ;; Update the direction of the ship if the boosters are firing (define (check-dir bst d rad) (cond [(not bst) d] [else (local ((define bdir (pt-from 0 0 rad 1))) (make-posn (+ (posn-x d) (posn-x bdir)) (+ (posn-y d) (posn-y bdir))))])) ;; move-ship: Number Number Number Boolean Posn -> Ship ;; Move the ship in the direction it's floating, and see if the ;; direction should change based on the booster (define (move-ship rad x y bst dir) (local ((define nx (check (+ x (posn-x dir)))) (define ny (check (+ y (posn-y dir)))) (define nd (check-dir bst dir rad))) (make-ship nx ny rad bst nd))) ;; make-list: Number -> (listof Object) ;; Make a list of random Objects to be shot by the ship (define (make-list n) (build-list n (lambda (i) (make-obj (random size) (random size) (+ 10 (random 10)) (* pi (random 10) 1/5))))) ;; Big bang and event stuff (big-bang size size .05 (make-world (make-ship (/ size 2) (/ size 2) 0 false (make-posn 0 0)) '() (make-list 5))) (on-redraw draw) (on-key-event key) (on-tick-event tick)