Learning objectives
The amount of programming we have learned so far is already enough to build interesting programs. This lab will:
- give you practice writing functions and conditionals;
- give you practice writing a testing plan;
- show you how animations can be created from functions;
All of these come back on later assignments and projects, so make sure you understand what you are writing rather than just finishing as fast as you can.
You may well not get through all of this lab, and that is fine. Work with your partner, and understand the code you write rather than racing to the last task.
Setup
- Find a partner. This lab is pair work throughout.
- Create a new file in Pyret (name is up to you) and set the context to dcic2024 (under the Pirate menu).
- Make a copy of the written answer worksheet, share it with your partner(s), and submit the link to it in the worksheet submission form (you can do this before filling anything in).
Part 1Describing Game Behaviors
Here is a brief video of someone playing a game. The player controls a drone that moves left and right above the forest floor. Embers from a wildfire (orange dots) fall from the sky. The player tries to catch the embers with the drone. The game ends either when an ember hits the ground or when all embers have been extinguished.
The data in this game are the x-y coordinates of the drone and each of the embers. We'll call the collection of embers the "fire set". Working in small groups, propose a set of statements about how these data change as the game is played. For example:
- If the player presses the right arrow, the drone's x-coordinate increases.
- A new ember can be added to the fire set at any time. All new embers start with a y-coordinate of 0.
Extend this set of statements to cover the rest of the gameplay. Put your answers in your worksheet document. Even though you brainstormed in pairs or small groups, write the statements in your documents individually. Being able to capture behavior ideas as precise statements is a key skill for the course.
Checkpoint
Call a TA over to discuss your plan after about 10 minutes. If you are waiting for a TA, start the next part.
Part 2Creating Animations from Functions
Now, you'll learn how to create a simpler game for yourself (we'll come back to the embers game later)
Step 1Generating Animation Images
We are going to animate a gif of Eve alighting on a landing pad in Pyret — perhaps you are an animation programmer at Pixar working on the sequel to the critically acclaimed film Wall-E.

Take a few minutes to understand this gif.
- What elements do you see on the screen?
- What is moving? What is not moving?
Expressions for frames
In class we have talked about identifying the structure of a single image, then using that structure to write a program that produces the image. Here we have an animation, not a single still image. What is the structure of an animation?
An animation is a sequence of images that some tool — a program, a film projector — flips through quickly, creating the illusion of motion. Here is an example sequence of those images, usually called frames, from our robot lander.



We will start by drawing one frame from this animation.
To do that we need images for the navy background, the landing pad, and Eve herself. The background is just a rectangle. Pyret has a useful function image-url for loading images when you do not want to build a whole graphic from scratch. It takes the url of a picture on the web and produces a Pyret Image; once loaded, you can manipulate it the way you would any other Image.
The following code loads the images we used to generate the frames. If you prefer different ones, feel free to replace our urls — but do not spend more than a few minutes looking.
LANDING-PAD-URL = "https://i.imgur.com/emcz1qe.png"
ROBOT-URL = "https://i.imgur.com/tAHzdNP.png"
robot = image-url(ROBOT-URL)
landing-pad = image-url(LANDING-PAD-URL)
BOOST = 40
HEIGHT = 500
WIDTH = 750
background = rectangle(WIDTH, HEIGHT, "solid", "navy")
# from Additional Game Features
SOLVED-URL = "https://www.syfy.com/sites/syfy/files/styles/1200x680_hero/public/2017/06/best-pixar-movie-romance.jpg"
Copy the code above into your Pyret file. Then write an expression that generates the frame image for a robot at y-coordinate 100 and an x-coordinate half the width of the background. If your code is right, you should get an image close to the ones above. Remember the landing pad.
Note: You will probably find
place-image
more useful than overlay-xy: it lets you fix one image (the
background) and put another (the landing pad) on top of it at a
coordinate. You can nest calls to place-image, just as you have
before with overlay-xy.
Note: The origin of the background grid — the point at (0,0) — is the top left
corner of the image, so increasing y moves down the image.
Hint: You can use scale to make the robot or the landing pad larger or smaller.
A function to generate a frame
We said animations are made from a sequence of images flipped through quickly. Ignore the flipping aspect. Focus first on generating images in which the robot is at a different y-coordinate each time.
Discuss with your partner: where specifically would the expression you wrote for Task 2 be edited to place the robot at a different y-coordinate?
Now let us make a function that generates robot frames for different y-coordinates.
Create a function called draw-robot that takes one Number input, representing the y-coordinate, and produces the frame Image with the robot at that y-coordinate. You do not need a where block for this one — we will come back to that. Remember the landing pad. Generate a sequence of images by hand by making the following calls in the interactions window:
draw-robot(0)
draw-robot(20)
draw-robot(40)
draw-robot(60)
... Checkpoint
Call a TA over once you have written your frame generator function and created some frames.
Step 2Generating Coordinates for a Sequence of Frames
To program an animation, we need to generate the frames automatically, not by hand in the interactions window. Note that to generate the frames by hand, we wrote the same expression over an over, changing only the coordinate. But that coordinate changed each time according to a pattern. If we could represent that pattern as a function, maybe a program could keep generating new y-coordinates automatically.
Add the following to your file. You do not need a where block for now.
fun next-y(y :: Number) -> Number:
doc: "generate y coordinate for next image"
y + 20
endStep back and think about what draw-robot and next-y together let us do. Given an initial y-coordinate, we could draw the first frame. We could use next-y to get the next coordinate and draw the second frame. We could repeat that to keep generating images.
In other words, these two functions define an animation. If we could get Pyret to use them to generate the images and flip through them, we would be done. Fortunately, Pyret has such a feature.
Stop and write down any questions you have at this point in your worksheet. Discuss them with your partner, or ask a TA.
Step 3Making the Animation
Pyret has something called a Reactor that generates sequences of images according to a pattern. Add the following to your file, then run it.
include reactors # put this line at the top of your file
# put the following part at the bottom of your file, under everything else
robot-reactor = reactor:
init: 0, # the initial y-coord value
to-draw: draw-robot,
on-tick: next-y
end
interact(robot-reactor)
You should now see something like the first animation we showed you. The robot will fly straight past the landing pad and off the bottom of the screen — you will get a chance to fix that later.
What is a reactor?
A Reactor is another type of data in Pyret — like a String, Number, Image, Boolean, or Table — that keeps track of data for games and animations. Under the hood, interact runs a Reactor in a loop, updating the image being drawn using the to-draw and on-tick functions. For the robot-lander, the reactor has the following components:
init: 0— the initial y-coordinate. This is the initial value of what will change frame by frame.to-draw: draw-robot— the function that returns an image based on the current y-coordinate.on-tick: next-y— the function that takes the y-coordinate for a frame and returns the coordinate for the next one, tick by tick. Its first input is theinitvalue.

Figure out how to make the robot land slower or faster. What would you change in your current code? Try it out.
Look at the reactor diagram and the code. Note any observations, or things you are curious about, in your worksheet.
The punchline is that you could replace draw-robot and next-y with any functions and get an animation in which a single piece of information changes between frames — change the background, change the images, have the robot fly upwards instead. In two or three weeks we will learn how to make animations where several pieces of information change, and we will come back to reactors then, before you use them on Project 2. For now, note that functions are the basis of character movement in animations, so you can already do a lot with what you have learned.
Step 4From Animations to Interactive Games
What is the difference between an animation and an interactive game? In a game, how elements move is influenced by what a player does — pressing keys, for instance. So far our reactor uses next-y to move the robot every few milliseconds. What if we wanted to let a person press the "b" key to boost the robot upward (by reducing its y-coordinate by 40 pixels)?
Add the following code to your file. It is the start of a function that produces a new "boosted" y-coordinate depending on which key has been pressed. Keys are strings like "A","n", or "=".
fun boost-robot(y :: Number, key :: String) -> Number:
doc: "if the key is 'b', lower coord by 40; otherwise return y as given"
...
end
Create a good set of where examples for this function.
Finish the function. Since the output differs based on the input, you will need a conditional.
Hint: Use the BOOST constant that we had you copy into your file.
Add boost-robot to your reactor by adding the on-key line below to your reactor; the rest is the same as before. Then run the code and play your new game.
my-reactor = reactor:
init: 0, # the initial y-coord value
to-draw: draw-robot,
on-tick: next-y,
on-key: boost-robot
endOptional
If you have time, extend boost-robot to also recognize the "t" key, which turbo boosts the robot upwards by 160 pixels. Think about how you can use BOOST to do it. Or skip ahead to the other ways to extend your animation.
Checkpoint
Call a TA over once you reach this point.
Back to the Embers: Generating and auditing reactor code
Now that you've worked with a reactor, prompt Gemini to create the embers game in the Pyret Level Beginner Gem. For the first try, just give Gemini the description at the top of the "Describing Game Behaviors" section. Copy and paste the produced code into a new Pyret file and try to run it. Make notes in your worksheet about how the generated code does or does not behave as you expected.
Now have a conversation with Gemini about the code. Give Gemini one of the behavior statements that you wrote and ask it to explain how the code satisfies that behavior. Are you convinced? Answer the corresponding questions in the worksheet.
Open the Gemini link afresh (with a new session). Prompt Gemini to again generate the game, but this time include all of your behavioral statements as part of the prompt. Again, copy over the code and play the game. Do you notice differences? Answer the corresponding questions in the worksheet.
Getting help
In lab, flag down a TA. You do not have to be stuck to do it, and you do not have to have tried everything first — that is what they are in the room for. Ask early: a pair that spends forty minutes on a typo has lost the part of the lab that was worth doing.
Your partner counts too. Saying out loud what you think the code does is most of debugging, and it is faster than waiting.
After lab, short questions go on Ed, and anything longer is better brought to office hours.
Comments or concerns?
If you have comments or concerns, submit them on the anonymous feedback form. Sign in with your Brown Google account to open it; your email address is not recorded.