Use the Intermediate Student Language with lambda for this assignment.
You may use local within existing functions to
encapsulate recursion.
You should use "loops" (i.e., abstractions such as map
,
foldr
, filter
, etc.) wherever your
functions may benefit from them.
Develop Missile Defense. In this game you control an
artillery gun centered at the bottom of a 500x500 pixel canvas.
Clicking the mouse anywhere on the canvas causes one bullet to
be fired from the gun in that direction. The "enemy" is
simultaneously firing missiles at you. Unlike bullets, which
are always launched under your control from the gun, missiles are
launched randomly from invisible silos just above the top of the
canvas. There is a silo at every possible horizontal location
(i.e. missiles may start out at any in-bounds x coordinate),
and each missle has a random direction but always aims downwards
(possibly at an angle) so that, unless you shoot it down, it will
reach the bottom of the canvas without going out of bounds. Once
shot, both missiles and bullets travel in straight lines. A missile
is shot down when a bullet collides with it; in that case both the
bullet and the missile "explode" (i.e. disappear). Both bullets and
missiles are represented as circles, though their radii and color
should be different to distinguish them.
The goal of the game is to survive as long as possible. You start
out with an initial health count, which is decremented by one
each time a missile reaches all the way to the bottom of the canvas.
The game is over when your health count reaches zero. You should
display the health count on the screen and make the game end when it
reaches zero.
Here is an image of the game in play (but yours should show the
health count as well):
Data Definitions: Use these data definitions unless
you have a good reason for departing (e.g., you want to add extra
features like top-score list, animated explosions, smart missiles,
etc. -- first see the advice below):
;;; A Sprite is a (make-sprite Posn Posn Number String)
;;; where
;;; - LOC is the sprite's location
;;; - VEL is its velocity
;;; - SIZE is the radius of the sprite
;;; - COLOR is its color.
;;; Location, velocity and size are in computer-graphic/pixel coordinates.
;;; A sprite represents either an attacker's missile or a defender's
;;; anti-missile bullet.
(define-struct sprite (loc vel size color))
;;; A LOS (list of sprites) is one of:
;;; - empty
;;; - (cons Sprite LOS)
;;; A world structure is a (make-world LOS LOS Number)
;;; - missiles: the missiles attacking the player
;;; - bullets: the missiles launched by the player
;;; - health: current health of the player -- game-over if health <= 0
(define-struct world (missiles bullets health))
Top-Level Functions: We strongly suggest you use
these top-level functions:
;;; move-bullets: World -> World
;;; Move the bullets one time step and remove any that have gone off screen.
;;; move-missiles: World -> World
;;; Move the missiles one time step.
;;; remove-dead-missiles-and-bullets: World -> World
;;; Remove every missile that is touching some bullet and vice versa.
;;; detonate-missiles: World -> World
;;; Remove missiles that landed... and decrement the player's health if any did.
;;; maybe-fire-missle: World -> World
;;; If we haven't maxed out on missiles, launch another one.
Note the shared functionality in some of these. For example, both
move-bullets
and move-missiles
need to
advance every Sprite
in an LOS
. And both
move-bullets
and detonate-missiles
need to
cull out-of-bounds Sprite
s. You should implement helper
functions for operations like these so that you don't end up writing
the same Sprite
processing code in multiple places.
On-Tick Handler: Given those functions, this should
be the organization of your on-tick
handler:
;;; update-world: World -> World
;;; Step the world one tick.
- Move the bullets and remove offscreen ones.
- Move the missiles.
- Kill any destroyed missiles.
- Detonate the missiles that landed.
- Maybe launch another missile.
Some Advice: