369 lines
11 KiB
Racket
369 lines
11 KiB
Racket
#lang scribble/doc
|
|
|
|
@(require "shared.ss"
|
|
"port.ss"
|
|
scribble/manual
|
|
(for-label scheme
|
|
(only-in 2htdp/universe on-tick on-draw)
|
|
(prefix-in htdp: teachpack/htdp/world)
|
|
(prefix-in htdp: htdp/image)
|
|
(prefix-in 2htdp: teachpack/2htdp/universe)
|
|
(prefix-in 2htdp: 2htdp/image)
|
|
(only-in lang/htdp-beginner check-expect)))
|
|
|
|
@; -----------------------------------------------------------------------------
|
|
|
|
@title[#:tag "htdp-port"]{Porting World Programs to Universe}
|
|
|
|
@author{Matthias Felleisen, Robby Findler}
|
|
|
|
@; -----------------------------------------------------------------------------
|
|
@section{The World is Not Enough}
|
|
|
|
With the June 2009 release, we started deprecating the world teachpack; instead
|
|
we recommended the use of the universe teachpack. With the January 2010 release,
|
|
we are also introducing a new image teachpack and, in support of this second
|
|
teachpack, we have separated out the image functionality from the
|
|
functionality for world programs.
|
|
|
|
In this document, we explain how to port programs that assume the old world
|
|
teachpack into this new setting, one step at a time. Most importantly,
|
|
programs must now import @emph{two} teachpacks insteead of one:
|
|
@port[
|
|
@(begin
|
|
#reader scribble/comment-reader
|
|
(schemeblock
|
|
(require #,(schememodname htdp/world))
|
|
))
|
|
@; ---------------------------------
|
|
@(begin
|
|
#reader scribble/comment-reader
|
|
(schemeblock
|
|
(require #,(schememodname 2htdp/universe))
|
|
(require #,(schememodname htdp/image))
|
|
))
|
|
]
|
|
The table shows the old style on the left and the new style on the
|
|
right. If your programs imported teachpacks via the drscheme teachpack
|
|
menu, we recommend that you use the @scheme[require] form from now on;
|
|
alternatively, you use the drscheme menu @emph{twice} to import the
|
|
functions from two teachpacks.
|
|
|
|
In the next section, we first explain how to port world programs so that
|
|
they use the universe teachpack and the @emph{old} image teachpack. In the
|
|
section after that, we list suggestions for changing programs so that they
|
|
no longer rely on the old image functionality but the new one.
|
|
|
|
In order to distinguish between the various pieces of functionality, we
|
|
uniformly prefix old functionality with "htdp:" and new functionality with
|
|
"2htdp:". There is no need to use these prefixes in your programs of
|
|
course.
|
|
|
|
@; -----------------------------------------------------------------------------
|
|
@section{Porting World Programs}
|
|
|
|
Here is the first program from the documentation for the world teachpack:
|
|
@(begin
|
|
#reader scribble/comment-reader
|
|
(schemeblock
|
|
(require #,(schememodname htdp/world))
|
|
|
|
;; Number -> Scene
|
|
(define (create-UFO-scene height)
|
|
(htdp:place-image UFO
|
|
50 height
|
|
(htdp:empty-scene 100 100)))
|
|
|
|
;; Scene
|
|
(define UFO
|
|
(htdp:overlay
|
|
(htdp:circle 10 'solid 'red)
|
|
(htdp:rectangle 40 4 'solid 'red)))
|
|
|
|
;; --- run program run
|
|
(htdp:big-bang 100 100 (/1 28) 0)
|
|
(htdp:on-tick-event add1)
|
|
(htdp:on-redraw create-UFO-scene)
|
|
))
|
|
This program defines a function for placing a @scheme[UFO] into a 100 by
|
|
100 scene, where @scheme[UFO] is a defined image. The world program itself
|
|
consists of three lines:
|
|
@itemize[
|
|
@item{the first one creates the 100 by 100 scene, specifies a rate of 28
|
|
images per second, and @scheme[0] as the initial world description;}
|
|
@item{the second one says that for each clock tick, the world (a number) is
|
|
increased by @scheme[1]; and}
|
|
@item{the last line tells drscheme to use @scheme[create-UFO-scene] as the
|
|
function that renders the current world as a scene.}
|
|
]
|
|
|
|
Let us now convert this program into the universe setting, step by
|
|
step, staring with the @scheme[require] specification, which is converted
|
|
as above:
|
|
@port[
|
|
@schemeblock[(require #,(schememodname htdp/world))]
|
|
@; ---------------------------------
|
|
@(begin
|
|
#reader scribble/comment-reader
|
|
(schemeblock
|
|
(require #,(schememodname 2htdp/universe))
|
|
(require #,(schememodname htdp/image))
|
|
))
|
|
]
|
|
|
|
The function that renders the world as a scene remains the same:
|
|
@port[
|
|
@(begin
|
|
#reader scribble/comment-reader
|
|
(schemeblock
|
|
;; Number -> Scene
|
|
(define (create-UFO-scene height)
|
|
(htdp:place-image
|
|
UFO
|
|
50 height
|
|
(htdp:empty-scene 100 100)))
|
|
))
|
|
@; ---------------------------------
|
|
@(begin
|
|
#reader scribble/comment-reader
|
|
(schemeblock
|
|
;; Number -> Scene
|
|
(define (create-UFO-scene height)
|
|
(htdp:place-image
|
|
UFO
|
|
50 height
|
|
(htdp:empty-scene 100 100)))
|
|
))
|
|
]
|
|
|
|
For the image constant we switch from symbols to strings:
|
|
@port[
|
|
@(begin
|
|
#reader scribble/comment-reader
|
|
(schemeblock
|
|
;; Scene
|
|
(define UFO
|
|
(htdp:overlay
|
|
(htdp:circle
|
|
10 'solid 'red)
|
|
(htdp:rectangle
|
|
40 4 'solid 'red)))
|
|
))
|
|
@; ---------------------------------
|
|
@(begin
|
|
#reader scribble/comment-reader
|
|
(schemeblock
|
|
;; Scene
|
|
(define UFO
|
|
(htdp:overlay
|
|
(htdp:circle
|
|
10 "solid" "red")
|
|
(htdp:rectangle
|
|
40 4 "solid" "red")))
|
|
))
|
|
]
|
|
Strictly speaking, this isn't necessary, but we intend to replace symbols
|
|
with strings whenever possible because strings are more common than
|
|
symbols.
|
|
|
|
The most important change concerns the lines that launch the world program:
|
|
@port[
|
|
@schemeblock[
|
|
(htdp:big-bang 100 100 (/1 28) 0)
|
|
(htdp:on-tick-event add1)
|
|
(htdp:on-redraw create-UFO-scene)
|
|
]
|
|
@; ---------------------------------
|
|
@schemeblock[
|
|
(2htdp:big-bang
|
|
0
|
|
(on-tick add1)
|
|
(on-draw create-UFO-scene))
|
|
]
|
|
]
|
|
They are turned into a single expression that comes with as many clauses
|
|
as there are lines in the old program. As you can see, the
|
|
@scheme[big-bang] expression from the universe teachpack no longer
|
|
requires the specification of the size of the scene or the rate at which
|
|
the clock ticks (though it is possible to supply the clock rate if the default
|
|
is not satisfactory).
|
|
Furthermore, the names of the clauses are similar to
|
|
the old names but shorter.
|
|
|
|
|
|
The other big change concerns key event handling and mouse event
|
|
handling. The respective handlers no longer accept symbols and chars but
|
|
strings only. Here is the first key event handler from the documentation
|
|
of the world teachpack:
|
|
|
|
@port[
|
|
@schemeblock[
|
|
(define (change w a-key-event)
|
|
(cond
|
|
[(key=? a-key-event 'left)
|
|
(world-go w -DELTA)]
|
|
[(key=? a-key-event 'right)
|
|
(world-go w +DELTA)]
|
|
[(char? a-key-event)
|
|
w]
|
|
[(key=? a-key-event 'up)
|
|
(world-go w -DELTA)]
|
|
[(key=? a-key-event 'down)
|
|
(world-go w +DELTA)]
|
|
[else
|
|
w]))]
|
|
@; ---------------------------------
|
|
@schemeblock[
|
|
(define (change w a-key-event)
|
|
(cond
|
|
[(key=? a-key-event "left")
|
|
(world-go w -DELTA)]
|
|
[(key=? a-key-event "right")
|
|
(world-go w +DELTA)]
|
|
[(= (string-length a-key-event) 1)
|
|
w]
|
|
[(key=? a-key-event "up")
|
|
(world-go w -DELTA)]
|
|
[(key=? a-key-event "down")
|
|
(world-go w +DELTA)]
|
|
[else
|
|
w]))
|
|
]]
|
|
Note how the @scheme[char?] clause changed. Since all chars are now
|
|
represented as strings containing one ``letter'', the program on the right
|
|
just checks the length of the string. Otherwise, we simply change all
|
|
symbols into strings.
|
|
|
|
If you ever recorded your programs' work via an animated gif, you can still
|
|
do so. Instead of adding a fifth argument to @scheme[big-bang], however,
|
|
you will need to add a clause of the shape @scheme[(record? x)].
|
|
|
|
Finally, the universe teachpack implements a richer functionality than the
|
|
world teachpack.
|
|
|
|
@; -----------------------------------------------------------------------------
|
|
@section{Porting Image Programs}
|
|
|
|
The universe library also comes with a new image library, @schememodname[2htdp/image].
|
|
Using the old image
|
|
library still works fine with @schememodname[2htdp/universe], but the
|
|
new image library provides a number of improvements, including faster
|
|
image comparison (especially useful in @scheme[check-expect] expressions),
|
|
rotating images, scaling images, curves, a number of new polygon shapes,
|
|
and more control over line drawing.
|
|
|
|
To use the new image library in isloation:
|
|
|
|
@port[
|
|
@(begin
|
|
#reader scribble/comment-reader
|
|
(schemeblock
|
|
(require #,(schememodname htdp/image))
|
|
))
|
|
@; ---------------------------------
|
|
@(begin
|
|
#reader scribble/comment-reader
|
|
(schemeblock
|
|
(require #,(schememodname 2htdp/image))
|
|
))
|
|
]
|
|
|
|
and to use the new image library with the universe teachpack:
|
|
|
|
@port[
|
|
@(begin
|
|
#reader scribble/comment-reader
|
|
(schemeblock
|
|
(require #,(schememodname htdp/world))
|
|
))
|
|
@; ---------------------------------
|
|
@(begin
|
|
#reader scribble/comment-reader
|
|
(schemeblock
|
|
(require #,(schememodname 2htdp/universe))
|
|
(require #,(schememodname 2htdp/image))
|
|
))]
|
|
|
|
@bold{Overlay vs Underlay}
|
|
|
|
The @scheme[htdp:overlay] function places its first argument
|
|
under its second (and subsequent) arguments and so in
|
|
@schememodname[2htdp/image], we decided to call that
|
|
function @scheme[2htdp:underlay].
|
|
|
|
@port[(schemeblock
|
|
(htdp:overlay
|
|
(htdp:rectangle
|
|
10 20 "solid" "red")
|
|
(htdp:rectangle
|
|
20 10 "solid" "blue")))
|
|
(schemeblock
|
|
(2htdp:underlay
|
|
(2htdp:rectangle
|
|
10 20 "solid" "red")
|
|
(2htdp:rectangle
|
|
20 10 "solid" "blue")))]
|
|
|
|
@bold{No more pinholes}
|
|
|
|
The concept of pinholes from @schememodname[htdp/image]
|
|
has no correspondance in @schememodname[2htdp/image]
|
|
(we do expect to bring back pinholes in @schememodname[2htdp/image]
|
|
eventually, but they will not be as pervasive as they are
|
|
in @scheme[htdp/image]).
|
|
|
|
Instead of
|
|
a special position in the image that overlay operations
|
|
are sensitive to,
|
|
@schememodname[2htdp/image] has a family of overlay operations,
|
|
that overlay images based on their centers or their edges.
|
|
|
|
Since the default position of the pinhole is in the center
|
|
for most images and the default for overlaying and underlaying
|
|
images in @scheme[2htdp/image] is based on the center,
|
|
simple examples (like the one above) behave the same
|
|
in both libraries.
|
|
|
|
But, consider this expression that overlays two images on
|
|
their upper-left corners, written using both libraries.
|
|
|
|
@port[@schemeblock[(htdp:overlay
|
|
(htdp:put-pinhole
|
|
(htdp:rectangle 10 20 "solid" "red")
|
|
0 0)
|
|
(htdp:put-pinhole
|
|
(htdp:rectangle 20 10 "solid" "blue")
|
|
0 0))]
|
|
@schemeblock[(2htdp:underlay/align
|
|
"left"
|
|
"top"
|
|
(2htdp:rectangle
|
|
10 20 "solid" "red")
|
|
(2htdp:rectangle
|
|
20 10 "solid" "blue"))]]
|
|
|
|
In the @schememodname[2htdp/image] version, the programmer
|
|
uses @scheme[2htdp:underlay/align] to specify where
|
|
the images should be lined up, instead of using the pinhole.
|
|
|
|
@bold{Outlines in different places}
|
|
|
|
The outline style shapes are now shifted by one pixel for @schememodname[2htdp/image]
|
|
images as compared to @schememodname[htdp/image].
|
|
This means that these two rectangles draw the same sets of pixels.
|
|
|
|
@port[@schemeblock[(htdp:rectangle
|
|
11 11 "outline" "black")]
|
|
@schemeblock[(2htdp:rectangle
|
|
10 10 "outline" "black")]]
|
|
|
|
See also @secref["nitty-gritty"].
|
|
|
|
@bold{Star changed}
|
|
|
|
The @scheme[2htdp:star] function is a completely different
|
|
function from @scheme[htdp:star]. Both produce stars based,
|
|
on polygons, but @scheme[2htdp:star] always produces a five-pointed
|
|
star. See also @scheme[2htdp:star-polygon] for more general star
|
|
shapes.
|