Lab 2 - Images, Animations and Worlds

Telling DrRacket that you want Images and Animations

For any DrRacket program for which you would like to create/manipulate images and also create animations we will add the following lines at the top of the definitions window

(require 2htdp/image)
(require 2htdp/universe)

Open the DrRacket documentation for 2htdp/image and read the documentation for the following functions

  1. circle; create examples of circles in DrRacket
  2. text; create examples of text in DrRacket
  3. square; create examples of squares in DrRacket
  4. rectangle; create examples of rectangles in DrRacket
  5. overlay/xy; create composite image using circles and rectangles, e.g., a simple car where a rectangle represents the car's body and 2 circles represent the car's wheels.

Creating Snapshots

Open DrRacket's documentation for 2htdp/image and read the section "Placing Images & Scenes".

  1. Create an empty scene first.
  2. Create a shape (e.g., a circle) and place it in the center of your scene.
  3. Place the composite image that you created in the previous section and place it in the bottom right corner of your scene.
  4. Create Snapshots of a ball that is placed in the center of your scene and moves horizontally from left to right. Create at least 5 snapshots.

Animations from Snapshots and the concept of a world

Open the DrRacket documentation for 2htdp/universe and read the documentation stating at section "Interactions"

  1. Our "world" will represent the number of ticks passed
    ;; World is a positive number (current time) 
  2. Create a function that will calculate the next world
    ;; World -> World 
    ;; calculates the next world (increments the time)
    (define (next-world w)
      (add1 w))
    
  3. Create a function that will create an image snapshot from a world
    ;; World -> Image
    ;; draw the image for snapshot time w in the middle
    ;;   of a  200x200 scene
    (define (world-draw w)
      (place-image (circle w "solid" "black")
                   100 100
                   (empty-scene 200 200)))
    
  4. Genesis! Lookup big-bang in DrRacket's documentation.
    ;; We start at time 1, use next-world to update the world at each
    ;; tick, and use world-draw to render the world as a scene:
    (big-bang 1
      (on-tick next-world)
      (on-draw world-draw))
    
Modify the above animation so that:
  1. The circle does not grow in size but it remains of the same size in the center of the scene.
  2. Every tick of the clock makes the circle move horizontally (left to right) by 15 points.
  3. Every tick of the clock makes the circle move vertically (bottom to top) by 15 points.

The world is not enough!

Read the documentation on Posns

  1. Using the second animation from the preceding question (moving the ball horizontally), alter your program to use a posn in order to represent the location of you ball. Change your representation of the World to be this posn. Update all function so that the animation is working as before. Note: Use the Design Recipe!
  2. Using the third animation from the preceding question (moving the ball vertically), alter your program to use a posn in order to represent the location of you ball. Change your representation of the World to be this posn. Update all function so that the animation is working as before. Note: Use the Design Recipe!

Bonus Round: A simple Game

Paste the following code in a new definitions window

(require 2htdp/universe)
(require 2htdp/image)

(define ball (circle 10 'outline 'red))
(define canvas (empty-scene 500 500))
(define speed 5)

;; Direction is one of: 
;; - 'up
;; - 'down
;; - 'left 
;; - 'right

;; World contains position, speed and direction 
;; where 
;; - position is a Posn 
;; - speed is a Number 
;; - direction is a Direction
(define-struct w (coord speed direction))

;; initial-wold has the ball in the center, speed and moving to the left
(define initial-world 
  (make-w (make-posn 250 250)
          speed
          'left))

;; tick : World -> World 
;; Given a world w create a new world w' that has the same speed and direction as w but update 
;; its position using using speed and direction.
(define (tick world) 
  (make-w (change-position (w-coord world) (w-speed world) (w-direction world))
          (w-speed world)
          (w-direction world)))

;; change-position : Posn Speed Direction -> Posn 
;; given a posn, speed and direction return the new position (as a Posn) 
;; moved due to speed and direction 
;; Examples 
;; (change-position (make-posn 1 1) 10 'left) => (make-posn -9 1)
;; (change-position (make-posn 1 1) 10 'right) => (make-posn 11 1)
;; (change-position (make-posn 1 1) 10 'up) => (make-posn 1 -9)
;; (change-position (make-posn 1 1) 10 'down) => (make-posn 1 11)

(define (change-position coord speed direction)
  (cond 
    [(symbol=? direction 'right) (make-posn (+ (posn-x coord) speed)
                                            (posn-y coord))]
    [(symbol=? direction 'left) (make-posn (- (posn-x coord) speed)
                                           (posn-y coord))]
    [(symbol=? direction 'up) (make-posn (posn-x coord)
                                         (- (posn-y coord) speed))]
    [(symbol=? direction 'down) (make-posn (posn-x coord)
                                           (+ (posn-y coord) speed))]))


(check-expect (change-position (make-posn 1 1) 10 'left)
              (make-posn -9 1))
(check-expect (change-position (make-posn 1 1) 10 'right)
              (make-posn 11 1))
(check-expect (change-position (make-posn 1 1) 10 'up)
              (make-posn 1 -9))             
(check-expect (change-position (make-posn 1 1) 10 'down)
              (make-posn 1 11))

;; draw-scene : World -> Image 
(define (draw-scene w) 
  (place-image ball 
               (posn-x (w-coord w))
               (posn-y (w-coord w))
               canvas)) 


(big-bang initial-world 
          (on-tick tick)
          (on-draw draw-scene))

Save the code and run.

  1. Read the documentation on on-key. Design a function called keypress that consumes a World and a key and produces a new World such that
    • if the key is the string "up" then the ball must move speed units up in the scene
    • if the key is the string "down" then the ball must move speed units down in the scene
    • if the key is the string "left" then the ball must move speed units left in the scene
    • if the key is the string "right" then the ball must move speed units right in the scene
    The ball keeps moving in the new direction until another key press alters the balls direction. The speed remains the unchanged.
  2. Read the documentation on stop-when. Change your program so that the game terminates when the ball hits the bounds of the scene.