(require 2htdp/universe)
universe
programming with
a secondary emphasis on compound struct
s. For today's
exercise, you will build an interactive scene displaying a flight over
Lake Michigan as seen from an airplane window. After putting together
some basic animation, you will modify the code to give your user (to a
very limited extent) the ability to control the plane's flight. The
simple toolkit you'll start learning today opens the door to a
challenging and essentially limitless realm of interactive visual
software.
Animation Essentials
DrRacket's universe
library enables you to create
interactive animations. In the universe
terminology,
a world is a value that characterizes the modeled world at a
given instant. The world may be modeled by a simple atomic piece of
data, such as a number, or by a piece of compound data, as in today's
exercise. The display is updated periodically to reflect the state of
the world as it changes. Note that a "world" is not a particular data
structure; it is whatever it needs to be to serve the application at
hand. Today's world model is a custom-designed struct, discussed in
more detail below.
A universe consists of the following components:
-
the value of the world in its initial state. For today's lab, we
will supply you with an initial world value
named
init-world
. - a "drawing function" of type
world -> scene
to render the world as a picture. (A scene is very much like an image, but engineered for use in animations. You operate on scenes with a different set of operators than images.) Today we'll call this functionrender
. -
a "time-step function" of type
world -> world
that consumes a world, and produces the value of the world as it stands one time-step later. Today we'll call this functiontick
.
read-key : world key -> world
to change the
world (or not) depending on keystrokes given by the user.
You will need to refer to the 2htdp/universe and 2htdp/image documentation while you work on this project.
Getting Started
Download airplane-starter.rkt and open it in Dr. Racket. As before, put your name and the name of the lab in a comment at the top. Read the code and try to understand what it means. To assist your understanding, evaluate the defined names and call functions freely in the interactions pane.
Pay special attention to the data definition for world
. A
world consists of three clouds and a sun. We will follow this
convention: the cloud c1
is closest to the
viewer, c2
is next closest, then c3
. The sun
is, of course, the farthest object in the sky, and must appear behind
all clouds at all times.
Part 1: Render the World
Call background
with different arguments to understand
what it does.
Read about the place-image function. You will need it.
Write a function place-sun : sun scene -> scene
to
draw a given sun in a given scene. Evaluate
(place-sun init-sun (background bg-width bg-height))
to make sure it's working.
Write a similar function place-cloud : cloud scene ->
scene
. Note we have provided a function cloud-pic
to draw clouds of a given size. Try it out with different clouds to
make sure it too is working.
Write a function overlay-wing : scene -> scene
to draw a
wing on top of the given scene. We have a provided
a wing-pic
to use as the wing image to overlay.
Use all these pieces to write a function render : world ->
scene
that displays the whole world: the sky and water, the
sun, three clouds, and the wing in the extreme foreground. Use the
constants bg-width
and bg-height
in drawing
the background. It is important to draw the objects in the right
order. Draw the sun first, for example, to make sure no clouds can
appear behind the sun and destroy the realism (such as it is) of the
illusion of depth.
You can test your function by rendering init-world
.
Part 2: Animate!
You will now add movement to the scene. The clouds should pass by the window at different rates of speed so there is a sense of depth to the animation. The sun and wing will both stay put.
Begin by implementing the following functions:
-
move-x : num pos -> pos
. Add the given number to the x-coordinate of the pos argument. For example, should return(move-x 1 (make-pos 1 2))
(make-pos 2 2)
. -
move-y
, similar. -
move-cloud-x : num cloud -> cloud
. A call to(move-cloud i c)
should move the cloud ci
pixels along thex axis.
Put this together into tick : world -> world
to manage
the time-step changes to the state of the world. In one time step the
clouds should all move to the left at different rates of
speed -- c1
fastest, then c2
,
then c3
-- and the sun should remain where it is.
Having written render
and tick
, you will be
able to view your animation as follows.
Paste this code at the bottom of your definitions:
(big-bang init-world (on-tick tick) (to-draw render))
Click run and enjoy!
Part 3: Take Control
You will now modify the program to support simple up-and-down control of your airplane. The modification centers around a function
read-key : world key -> world
The function should behave as follows:
- if the user types the up arrow, the plane "rises" and the clouds should appear to drop a little.
- if the user types the down arrow, the plane "lowers" and the clouds should appear to rise a little.
- if the user types any key other than those two, nothing should happen.
In read-key
, you can test the key argument by testing it with
the key=?
predicate and the strings "down"
and "up"
. In other words, if the user has just pressed
the up arrow, the test
(key=? k "up")
for key k
should evaluate to true
.
Note that, once again, to simulate depth, the closest cloud should always move up (and down) faster than the next closest.
Now modify the call to big-bang
as follows:
(big-bang init-world (on-tick tick) (to-draw render) (on-key read-key))
Enjoy again!
Enhancements
This a project that is well-suited to various enhancements. Here are a few suggestions, but understand this first:
- nothing "extra" that you do for this project must interfere with its normal function as specified above.
- no points will be awarded for enhancements. This is not extra credit. Do it exclusively because you want the experience.
Ideas:
- Make the clouds look more like real clouds. The ellipses we provide you with are not exactly realistic.
- Make the clouds "wrap around" so after they drift off at the left edge of the window, they reappear shortly thereafter at the right edge.
- Add a "sunset mode" that is activated and deactivated by
striking
s
.
Submit
Submit your work by clicking the CS151 Handin
button on
the DrRacket toolbar by 10 PM on Sunday (Oct 10). Make sure your work
is submitted as Lab2
. As always, feel free to mail the
lab instructors or the mailing list with any questions.