We will create animations using a tool called a reactor. A reactor allows us to write an animation in terms of three (and one optional) things:
- some initial value, such as a
- an update function that transforms the value into its next value every clock tick, such as moving the
- a rendering function that turns the value into an
- an optional condition that determines when the animation stop.
Here's an example that moves a circle from left to right, stopping when the the circle gets to the point (300, 0).
val travellingCircle = Reactor.init(Point(-300, 0)) .withOnTick(pt => Point(pt.x + 1, pt.y)) .withRender(pt => Image.circle(10).at(pt)) .withStop(pt => pt.x >= 300)
(We could write the
onTick function as
pt -> pt + Vec(1,0) if we're comfortable with vector arithmetic.)
This constructs a reactor but it does not draw it. To do this we must call the
run method, passing a
Frame that tells the reactor how big to make the window it draws on. Here's an example:
This generates the animation shown in Figure reactor:travelling.
Here's an another example that moves a circle in a circular orbit. This time the animation has no stopping condition, so it continues forever.
val orbitingCircle = Reactor.init(Point(0, 300)) .withOnTick(pt => pt.rotate(2.degrees)) .withRender(pt => Image.circle(10).at(pt))
We run this reactor in the same way.
This generates the animation shown in Figure reactor:orbit.
Exercise: Rose Curve
Make an animation where an image moves in a rose curve (we saw the rose curve in an earlier chapter). Be as creative as you wish. You might find it fun to change the background of the
Frame on which you draw the animation; a dark background is often more effective than a light one. You can do this by calling the
background method on
Frame. For example, here is how you'd create a 600 by 600 frame with a dark blue background.
Remember you will need to import
doodle.reactor._ to make the reactor library available.