Posts tagged animate

Running Man

:: animation, animate, running man, icons

Have you ever noticed the little man in the bottom right corner of DrRacket?

At first sight he looks hand drawn, but the appearance deceives. The little guy is in fact ray traced. Neil Toronto the man behind the ray tracing code, was inspired by the animation of the main character in the Commodore 64 classic Impossible Mission.

Buried in the documentation of the icons library, one finds the function running-stickman-icon. The function can be used to generate frames of a running man animation - it even allows us to change colors and size of the running man.

The first parameter of running-stickman-icon is the time, t, a number between 0 and 1. Let’s see 10 frames of the default running man.

> (require images/icons/stickman)
> (for/list ([t (in-range 0 1 1/10)])
    (running-stickman-icon t))

(list image image image image image image image image image image)

The default man is a little small, but we can easily change both the size and the colors of the man.

> (require images/icons/stickman)
> (running-stickman-icon 0 #:height 128
                           #:head-color "white"
                           #:arm-color  "gray"
                           #:body-color "lightblue")

image

It is now easy to create an animation of the running man. First we need a function render-man that given a frame number will produce an image. Then the function animate from 2htdp/image can be used to display the animation.

To get a fluent motion we will use N=28 frames in one cycle of the animation. Frame 0, 28, 56 and so forth will be the same. If n is the frame number (of the animation), then (remainder n N) is the frame number in the 0 to N-1 range. Divide by n to get the time t in the interval [0 ,1].

(define N 28)
(define (render-man n)
  (define t (/ (remainder n N) N))
  (freeze (running-stickman-icon t #:height 128
                                   #:head-color "white"
                                   #:arm-color  "gray"
                                   #:body-color "lightblue")))

Since the result of running-stickman-icon is a bitmap% object, we need to "freeze" it in order to use it with 2htdp/universe.

The running man is now ready for action:

(require images/icons/stickman 2htdp/image 2htdp/universe)
(define N 28)
(define (render-man n) ...)
(animate render-man)

Those of you who tried the above in DrRacket are probably not too impressed.

Can you spot the problem?

The animation is slow and stutters. For each frame the ray tracer is activated to produce an image. Since animate shows 28 frames pr second, the function render-man is not allowed to use more than 1/28 second to generate each image - and for large heights the ray tracer is not fast enough.

The solution is to prerender the images of the running man before starting the animation. This way each image is generated only once.

(require images/icons/stickman 2htdp/image 2htdp/universe)
(define N 28)
(define (render-man n) ...)
(define men (for/vector ([n N]) (render-man n)))
(define (man n) (vector-ref men (remainder n N)))
(animate man)