Chapter 3

User-controlled Exploding Stars

The goal of this part is to integrate the animated stars from the previous chapter into the world.ss teachpack.

This is the data definition for world that we will use.

;; a world is:
;;  - empty
;;  - (cons animation world)

Design the tock function:

;; tock : world -> world
;; to remove the first element from each list in `world', 
;; and then to remove any empty lists from `world'.
(define (tock world) ...)

;; examples as tests (to get you started; you must make more)
(equal? (tock empty) empty)
(equal? (tock (list (list (make-frame 1 2 (make-explosion 1 2 'red)))
                    (list (make-frame 1 2 (make-explosion 1 2 'red))
                          (make-frame 20 20 (make-explosion 5 5 'blue)))))
        (list (list (make-frame 20 20 (make-explosion 5 5 'blue)))))

The tock function must be written as the composition of two functions, one that removes the first element for each list in world and one that removes any empty lists from world.

Next, design the world->image function:

;; night-sky : image
(define night-sky (nw:rectangle world-size world-size 'solid 'black))

;; world->image : world -> image
;; to render the first frame in each animation in `world',
;; and to superimpose them together on the `night-sky'
(define (world->image world) ...)

To create the animation itself, you should define a key event handler that transforms a key event into a particular firework. The key event handler has this signature:

;; handle-key : world (char or symbol) -> world
(define (handle-key w c) ...)

Search in Help Desk for on-key-event for an explanation of how it is used.

This function should check to see if c is a character, and if the character is between #\a and #\y, using the char<=? function. If it is, the character can be converted to a number between 0 and 24:

;; c->n : character -> number
;; to convert a character between #\a and #\y to a number between 0 and 24
(define (c->n c) (- (char->integer c) (char->integer #\a)))

Then, that number can be converted into two numbers, one that can be used to pick a particular kind of firework, and one that can be used to pick the position of the firework:

;; first-num : number[0-24] -> number[0-4]
(define (first-num n) (modulo n 5))

;; second-num : number[0-24] -> number[0-4]
(define (second-num n) (quotient n 5))

To pick the location of the firework, use these functions (that I got from a geometry text). They correspond to five equally spaced spots around a circle of radius 100, centered on the world's image.

;; num->x-coordinate : integer[0-4] -> number[0-world-size]
;; to compute an x coordinate for the n-th firework position
(define (num->x-coordinate n) (scale-coordinate (cos (n->angle n))))

;; num->y-coordinate : integer[0-4] -> number[0-world-size]
;; to compute an y coordinate for the n-th firework position
(define (num->y-coordinate n) (scale-coordinate (sin (n->angle n))))

;; helper functions
(define (n->angle n) (- (* (/ n 5) 2 pi) (/ pi 2)))
(define (scale-coordinate c) (floor (+ (/ world-size 2) (* 100 c))))

Once the number conversion functions are set, the handle-key function should add the new animation it creates to world, making a world with one more animation in it. Each key you type should produce a slightly different firework, either in a different position, or with a different color.

Once everything is well-tested, put it all together to play with world.ss (you may wish to adjust the constant 0.2 a little, in order to speed up the animations, if your computer is faster than mine):

;; run program, run
(big-bang (+ world-size 2)
          (+ world-size 2)
          0.2
          empty)
(on-tick-event tock)
(on-redraw world->image)
(on-key-event handle-key)