;; ;; ;; UPDATED UFO CODE v3 ;; ;; ;; Constants (define UFO (overlay (circle 6 'solid 'green) (rectangle 36 3 'solid 'green))) ;; makes the UFO image (define BACKGROUND (nw:rectangle 250 400 'solid 'blue)) ;; makes the blue background (define AUP (overlay/xy (rectangle 16 4 'solid 'red) 0 -5 (rectangle 2 8 'solid 'red))) ;; makes the AUP image (define MISSILE (text "\3" 18 'pink));;(rectangle 2 8 'solid 'yellow)) ;; makes the MISSLE (define BOMB (rectangle 8 2 'solid 'yellow)) ;; makes the BOMB (define BOMBSPEED 8) ;; the speed of the bombs (define BOMBCHANCE 8) ;; Percent chance of dropping a bomb (define MISSILESPEED 12) ;; the speed of the missile (define MISSILEMAX 5) ;; most amount of missiles on the screen at once (define UFOSPEEDX 25) ;; makes the ufo move at x pixels across (define UFOSPEEDY 4) ;; makes the ufo move down x pixels (define AUPSPEED 4) ;; makes the AUP move across x pixels at a time (define WIN-TEXT (text "YOU WIN\1FOR NOW" 18 'white)) (define LOSE-TEXT (overlay/xy (text " ALL YOUR BASE" 14 'red) 0 16 (text "ARE BELONG TO US" 14 'red))) ;; A LOM is one of ;; - empty ;; - (cons Missile LOM) ;; a LOB is one of ;; - empty ;; - (cons Bomb LOB) ;; A GameState is one of ;; - 'Win ;; - 'Lose ;; - 'Play (define-struct ufo (pic p dir lob)) ;; a ufo is (make-ufo Image Posn Symbol LOB) (define-struct aup (pic p dir)) ;; a aup is (make-aup Image Posn Symbol) (define-struct missile (pic p)) ;; a missle is (make-missle Image Posn) (define-struct bomb (pic p)) ;; a bomb is (make-bomb Image Posn) (define-struct world (ufo aup lom state)) ;; a world is (make-world ufo aup LOM GameState) (define startworld (make-world (make-ufo UFO (make-posn 125 20) 'right empty) (make-aup AUP (make-posn 10 395) 'right) empty 'Play)) ;; starting world ;; end-screen: Image -> Image ;; Displays img ontop of a black background (define (end-screen img) (place-image (overlay/xy (rectangle 250 400 'solid 'black) (round (- 0 (/ (image-width img) 2))) (round (- 0 (/ (image-height img) 2))) img) 125 200 (empty-scene 250 400))) ;; BOMB FUNCTIONS ;; draw-bomb: LOB -> Image ;; Puts all the bombs into an image (define (draw-bomb lob) (foldl (lambda (b sc) (place-image BOMB (posn-x (bomb-p b)) (posn-y (bomb-p b)) sc)) (empty-scene 250 400) lob)) ;; next-bomb: LOB -> LOB ;; Updates the position of bombs ;; it's faster to remove bombs as you go through the first time, than ;; to reiterate through the list and remove them (define (next-bomb lob) (local ((define (good? b) (< (posn-y (bomb-p b)) 395)) (define (move b lst) (cond [(good? b) (cons (make-bomb (bomb-pic b) (make-posn (posn-x (bomb-p b)) (min 395 (round ;;weird gravity (* (posn-y (bomb-p b)) (+ (* BOMBSPEED 1/75) 1)))))) lst)] [else lst]))) (foldr move empty lob))) ;; drop-bomb?: LOB Posn -> LOB ;; Randomly determines to drop a bomb, and if so adds it to LOB at posn p (define (drop-bomb? lob p) (cond [(< (random 100) BOMBCHANCE) (cons (make-bomb BOMB p) lob)] [else lob])) ;; bomb-collision: LOB Aup -> Boolean ;; determines if there is a collision between the bombs and the aup (define (bomb-collision lob a) (local ((define (collision? b) (and (<= (posn-y (aup-p a)) (+ (posn-y (bomb-p b)) (round (/ (image-height BOMB) 2)))) (>= (posn-y (aup-p a)) (- (posn-y (bomb-p b)) (round (/ (image-height BOMB) 2)))) (>= (+ (posn-x (bomb-p b)) (round (/ (image-width BOMB) 2))) (- (posn-x (aup-p a)) 8)) (<= (- (posn-x (bomb-p b)) (round (/ (image-width BOMB) 2))) (+ (posn-x (aup-p a)) 8))))) (ormap collision? lob))) ;; UFO FUNCTIONS ;; draw-ufo: ufo -> Image ;; draw the ufo ;; Given: (draw-ufo (make-ufo UFO (make-posn 120 100))) ;; Wanted: (place-image UFO 120 100 (empty-scene 250 400)) (define (draw-ufo ufo1) (place-image UFO (posn-x (ufo-p ufo1)) (posn-y (ufo-p ufo1)) (empty-scene 250 400))) ;; move-ufo: Posn Symbol -> Posn ;; moves the ufo in direction dir ('left, 'right, 'down) (define (move-ufo p dir) (cond [(symbol=? dir 'left) (make-posn (- (posn-x p) UFOSPEEDX) (posn-y p))] [(symbol=? dir 'right) (make-posn (+ (posn-x p) UFOSPEEDX) (posn-y p))] [(symbol=? dir 'down) (make-posn (posn-x p) (+ UFOSPEEDY (posn-y p)))])) ;; next-ufo: ufo -> ufo ;; make the next ufo depending on if the current one has hit the edge or not (define (next-ufo ufo1) (cond [(symbol=? 'right (ufo-dir ufo1)) (cond [(< (posn-x (ufo-p ufo1)) 240) (make-ufo UFO (move-ufo (ufo-p ufo1) 'right) 'right (next-bomb (drop-bomb? (ufo-lob ufo1) (ufo-p ufo1))))] [else (make-ufo UFO (move-ufo (ufo-p ufo1) 'down) 'left (next-bomb (drop-bomb? (ufo-lob ufo1) (ufo-p ufo1))))])] [(symbol=? 'left (ufo-dir ufo1)) (cond [(> (posn-x (ufo-p ufo1)) 10) (make-ufo UFO (move-ufo (ufo-p ufo1) 'left) 'left (next-bomb (drop-bomb? (ufo-lob ufo1) (ufo-p ufo1))))] [else (make-ufo UFO (move-ufo (ufo-p ufo1) 'down) 'right (next-bomb (drop-bomb? (ufo-lob ufo1) (ufo-p ufo1))))])])) ;; ufo-land?: Ufo -> Boolean ;; Determines if our new martian overlords have landed (define (ufo-land? u) (cond [(>= (posn-y (ufo-p u)) 394) true] [else false])) ;; MISSILE FUNCTIONS ;; draw-missle: LOM -> Image ;; draw the missle from the AUP (define (draw-missile lom) (foldl (lambda (m sc) (place-image (missile-pic m) (posn-x (missile-p m)) (posn-y (missile-p m)) sc)) (empty-scene 250 400) lom)) ;; move-missile: LOM -> LOM ;; Updates the positions of all missiles ;; FIRE ZE MISSILES! (but i am le tired) (define (move-missiles lom) (local ((define (good? m) (> (posn-y (missile-p m)) -8)) (define (move m lst) (cond [(good? m) (cons (make-missile MISSILE (make-posn (posn-x (missile-p m)) (- (posn-y (missile-p m)) MISSILESPEED))) lst)] [else lst]))) (foldl move empty lom))) ;; count-missile: LOM -> Number ;; counts the number of missiles (define (count-missiles lom) (foldl (lambda (x y) (+ 1 y)) 0 lom)) ;; missile-collision: LOM Ufo -> Boolean ;; determines if there is a collision between the missiles and the ufo (define (missile-collision lom u) (local ((define (collision? m) (and (<= (posn-y (ufo-p u)) (+ (posn-y (missile-p m)) (round (/ (image-height MISSILE) 2))));; top of missile (>= (posn-y (ufo-p u)) (- (posn-y (missile-p m)) (round (/ (image-height MISSILE) 2))));; bottom of missile (>= (+ (posn-x (missile-p m)) (round (/ (image-width MISSILE) 2)));; left side of ship (- (posn-x (ufo-p u)) 9)) (<= (- (posn-x (missile-p m)) (round (/ (image-width MISSILE) 2)));; right side of ship (+ (posn-x (ufo-p u)) 9))))) (ormap collision? lom))) ;; fire-missile: World Symbol -> World ;; fire a missle if symbol is 'up (define (fire-missile world1 s) (make-world (world-ufo world1) (world-aup world1) (cons (make-missile MISSILE (make-posn (posn-x (aup-p (world-aup world1))) (posn-y (aup-p (world-aup world1))))) (world-lom world1)) (world-state world1))) ;; AUP FUNCTIONS ;; draw-aup: aup -> Image ;; draw the aup ;; Given: (draw-aup (make-aup AUP (make-posn 8 395) 'right)) ;; Wanted: (place-image AUP 8 395 (empty-scene 250 400)) (define (draw-aup aup1) (place-image AUP (posn-x (aup-p aup1)) (posn-y (aup-p aup1)) (empty-scene 250 400))) ;; next-aup: aup -> aup ;; make the next aup depending on direction ;; (next-aup (make-aup AUP (make-posn 10 395) 'right)) ;; --> (make-aup AUP (make-posn 15 395) 'right) (define (next-aup aup1) (cond [(and (symbol=? (aup-dir aup1) 'right) (<= (posn-x (aup-p aup1)) 242)) (make-aup AUP (make-posn (+ AUPSPEED (posn-x (aup-p aup1))) (posn-y (aup-p aup1))) 'right)] [(and (symbol=? (aup-dir aup1) 'left) (>= (posn-x (aup-p aup1)) 8)) (make-aup AUP (make-posn (- (posn-x (aup-p aup1)) AUPSPEED) (posn-y (aup-p aup1))) 'left)] [else aup1])) ;; move-right: World Symbol -> World ;; move the AUP right (define (move-right world1 s) (make-world (world-ufo world1) (make-aup AUP (make-posn (+ AUPSPEED (posn-x (aup-p (world-aup world1)))) (posn-y (aup-p (world-aup world1)))) 'right) (world-lom world1) (world-state world1))) ;; move-left: World Symbol -> World ;; move the AUP left (define (move-left world1 s) (make-world (world-ufo world1) (make-aup AUP (make-posn (- (posn-x (aup-p (world-aup world1))) AUPSPEED) (posn-y (aup-p (world-aup world1)))) 'left) (world-lom world1) (world-state world1))) ;; WORLD FUNCTIONS ;; game-state : world -> GameState ;; returns the current state of the world (define (game-state w) (cond [(boolean=? true (missile-collision (world-lom w) (world-ufo w))) 'Win] [(or (boolean=? true (bomb-collision (ufo-lob (world-ufo w)) (world-aup w))) (boolean=? true (ufo-land? (world-ufo w)))) 'Lose] [else (world-state w)])) ;; key-check: World Symbol -> World ;; check if a key is pressed and perform an action depending on what one (define (key-check world1 s) (cond [(symbol=? 'Play (world-state world1)) (cond [(symbol? s) (cond ;; move right [(symbol=? s 'right) (move-right world1 s)] ;; move left [(symbol=? s 'left) (move-left world1 s)] ;; fire the missile [(and (symbol=? s 'up) (< (count-missiles (world-lom world1)) MISSILEMAX)) (fire-missile world1 s)] [else world1])] [else world1])] [else world1])) ;; draw-world: World -> Image ;; draw the world (define (draw-world world1) (cond [(symbol=? (world-state world1) 'Win) (end-screen WIN-TEXT)] [(symbol=? (world-state world1) 'Lose) (end-screen LOSE-TEXT)] [else (overlay BACKGROUND (draw-ufo (world-ufo world1)) (draw-aup (world-aup world1)) (draw-missile (world-lom world1)) (draw-bomb (ufo-lob (world-ufo world1))))])) ;; missing tests ;; tests added ;; next-world: World -> World ;; make the next world (define (next-world world1) (cond [(symbol=? 'Play (world-state world1)) (make-world (next-ufo (world-ufo world1)) (next-aup (world-aup world1)) (move-missiles (world-lom world1)) (game-state world1))] [else (make-world (world-ufo world1) (world-aup world1) empty (game-state world1))])) ;; Can't test next-world because the BOMB dropper is random so ;; it changes every time ;; TESTS #| 'make-bomb-test (equal? (next-bomb (list (make-bomb BOMB (make-posn 25 75)) (make-bomb BOMB (make-posn 70 150)))) (list (make-bomb BOMB (make-posn 25 83)) (make-bomb BOMB (make-posn 70 166)))) 'next-ufo-test ;; we test the positions of the UFOs because ufo-lob changes at random (equal? (ufo-p (next-ufo (make-ufo UFO (make-posn 240 30) 'right empty))) (make-posn 240 34)) (equal? (ufo-p (next-ufo (make-ufo UFO (make-posn 10 64) 'left empty))) (make-posn 10 68)) 'next-aup-tests (equal? (next-aup (make-aup AUP (make-posn 121 395) 'right)) (make-aup AUP (make-posn 125 395) 'right)) (equal? (next-aup (make-aup AUP (make-posn 10 395) 'left)) (make-aup AUP (make-posn 6 395) 'left)) 'move-missiles-test (equal? (move-missiles (list (make-missile MISSILE (make-posn 25 -10)) (make-missile MISSILE (make-posn 34 200)))) (list (make-missile MISSILE (make-posn 34 188)))) 'count-missiles-test (equal? 2 (count-missiles (list (make-missile MISSILE (make-posn 25 -10)) (make-missile MISSILE (make-posn 34 200))))) 'missile-collision-test (equal? true (missile-collision (list (make-missile MISSILE (make-posn 100 100))) (make-ufo UFO (make-posn 109 102) 'right empty))) 'bomb-collision-test (equal? (bomb-collision (list (make-bomb BOMB (make-posn 100 395))) (make-aup AUP (make-posn 96 395) 'right)) true) 'ufo-land-tests (equal? (ufo-land? (make-ufo UFO (make-posn 125 20) 'right empty)) false) (equal? (ufo-land? (make-ufo UFO (make-posn 125 396) 'right empty)) true) 'game-state-tests (equal? (game-state (make-world (make-ufo UFO (make-posn 125 20) 'right empty) (make-aup AUP (make-posn 10 395) 'right) empty 'Play)) 'Play) (equal? (game-state (make-world (make-ufo UFO (make-posn 109 102) 'right empty) (make-aup AUP (make-posn 10 395) 'right) (list (make-missile MISSILE (make-posn 100 100))) 'Play)) 'Win) (equal? (game-state (make-world (make-ufo UFO (make-posn 125 396) 'right empty) (make-aup AUP (make-posn 10 395) 'right) (list (make-missile MISSILE (make-posn 100 100))) 'Play)) 'Lose) 'move-right-test (equal? (move-right (make-world (make-ufo UFO (make-posn 125 20) 'right empty) (make-aup AUP (make-posn 10 395) 'right) empty 'Play) 'right) (make-world (make-ufo UFO (make-posn 125 20) 'right empty) (make-aup AUP (make-posn 14 395) 'right) empty 'Play)) 'move-left-test (equal? (move-left (make-world (make-ufo UFO (make-posn 125 20) 'right empty) (make-aup AUP (make-posn 10 395) 'right) empty 'Play) 'left) (make-world (make-ufo UFO (make-posn 125 20) 'right empty) (make-aup AUP (make-posn 6 395) 'left) empty 'Play)) 'fire-missile-test (equal? (fire-missile (make-world (make-ufo UFO (make-posn 125 20) 'right empty) (make-aup AUP (make-posn 10 395) 'right) empty 'Play) 'up) (make-world (make-ufo UFO (make-posn 125 20) 'right empty) (make-aup AUP (make-posn 10 395) 'right) (cons (make-missile MISSILE (make-posn 10 395)) empty) 'Play)) 'key-check-test (equal? (key-check startworld 'left) (make-world (make-ufo UFO (make-posn 125 20) 'right empty) (make-aup AUP (make-posn 6 395) 'left) empty 'Play)) 'draw-aup-test (equal? (draw-aup (world-aup startworld)) (place-image AUP 10 395 (empty-scene 250 400))) 'draw-bomb-test (equal? (draw-bomb (list (make-bomb BOMB (make-posn 120 300)))) (place-image BOMB 120 300 (empty-scene 250 400))) 'draw-ufo-test (equal? (draw-ufo (make-ufo UFO (make-posn 100 200) 'left empty)) (place-image UFO 100 200 (empty-scene 250 400))) 'draw-missile-test (equal? (draw-missile (list (make-missile MISSILE (make-posn 200 200)))) (place-image MISSILE 200 200 (empty-scene 250 400))) 'draw-world-tests (equal? (draw-world (make-world (make-ufo UFO (make-posn 125 20) 'right empty) (make-aup AUP (make-posn 10 395) 'right) empty 'Win)) (end-screen WIN-TEXT)) (equal? (draw-world (make-world (make-ufo UFO (make-posn 125 20) 'right empty) (make-aup AUP (make-posn 10 395) 'right) empty 'Lose)) (end-screen LOSE-TEXT)) |# ;; BIG BANG -- uncomment to run (big-bang 250 400 (/ 1 60) startworld) (on-tick-event next-world) (on-redraw draw-world) (on-key-event key-check)