cs111
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Help
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    --- title: Lab 02 tags: Labs-F21, 2021 --- # Lab 2: Reactors/Animations For this lab, we suggest you have a shared Google Doc between you and your partner for written answers, and a Pyret file for your code. ## Learning Objective The objective of this lab is to show how animations can be created from functions and conditionals. Animations also give us another example of how we can break down a seemingly complicated computation into smaller steps that we already know how to solve. We will practice breaking down the problem of creating an animation step by step using the skills that we've developed throughtout the semester so far. After that, we'll learn a Pyret tool (the `reactor`) that can help us automate some of the process of creating an animation. If you don't feel comfortable with the concept of a reactor after working on this lab, come to [TA hours](https://cs.brown.edu/courses/csci0111/fall2020/calendar.html)! The content of this lab will be important for Project 2, and your TAs would love to help in any way they can. ## Problem 1 -- Generating Animation Images In this lab, we're going to animate a gif of a space robot alighting on a landing pad in Pyret -- perhaps you could imagine that you're an animation programmer at Pixar Animation Studios working on the sequel to the critically acclaimed film, [Wall-E](https://en.wikipedia.org/wiki/WALL-E). ![](https://imgur.com/lcnma6F.gif) Take a few minutes to understand this gif: 1. What elements do you see on the screen? 2. What is moving? What is not moving? Write down your answers to these questions in your Google Doc. ### Problem 1.1 -- Frame by Frame In class, we've talked about identifying the structure of a single image, then using that to write a program to produce the image. Here, we have an animation, not a single still image. What is the structure of an animation? **Discuss with your partner**: what might the structure of an animation be? Are there simpler pieces that one could combine somehow to get an animation? Write down an answer in your Google Doc. *Only read on after you've written something down ...* An animation is actually a sequence of images that some tool (a program or film projector) flips through quickly (creating the *illusion* of motion). Here's an example sequence of these images (usually called *frames*) from our robot lander: ![Frame 1: robot at top, landing pad at bottom.](https://imgur.com/QNmQbfr.png =300x) ![Frame 2: robot slightly lower, landing pad at bottom.](https://imgur.com/HSuru7t.png =300x) ![Frame 3: robot on landing pad, landing pad at bottom.](https://imgur.com/Sl5ocHO.png =300x) **Discuss with your partner**: answer the following questions in your google doc: - visually, what is the same and what is different across these three images? - based on what you know about writing expressions that produce images, what specific pieces of data would differ across expressions that would produce these three images? ### Problem 1.2 -- Frame Generator You will now start to build your animation! Smooth animations require many, many frames (Pixar movies use between 24-60 frames per second!). We could build our animation by writing expressions that generate images for each frame. But creating these images is repetitive -- since only the `y`-coordinate of our robot is changing, do we really need to generate the frames one-by-one? What do we usually do when we find we are repeating the same code multiple times? **Task:** Stop and discuss your response with your partner. *Only read on after you've discussed with your partner ...* Rather than generating frames one-by-one using expressions, you will build a function that can generate any number of frames. **Building Frames** The following section gives you the resources to create the Wall-E-themed frames we displayed earlier in the lab. Think back to your list of the elements of the animation from earlier in the lab: we need the navy background, an image for the landing pad, and an image for the robot. The background is just a `rectangle`. Now we need the robot and landing pad. Pyret has a useful function <code>image-url</code> for loading images when you don’t want to build an entire graphic from scratch _(URL stands for "Universal Resource Locator"... a web address!)_. <code>image-url</code> takes in the url of a picture from the web and outputs it as a Pyret Image. Once it’s loaded, you can manipulate it the way you would any other Image. Our version used these images: ``` 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) HEIGHT = 500 WIDTH = 750 background = rectangle(WIDTH, HEIGHT, "solid", "navy") ``` You’re welcome to find (or build!) your own, or just copy our code to get started. **Building the Function** **Task:** First, think about the input and output of your function to produce a frame. Discuss with your partner what the function signature should be. **Task:** Create a function called `falling-robot` that takes one `Number` input (representing the `y` coordinate) and produces the frame image with the robot at this `y`-coordinate. ***Hint:*** You might find the function [`place-image`](https://www.pyret.org/docs/latest/image.html#%28part._image_place-image%29) more useful than `overlay-xy`, as it allows you to fix one image (e.g., the background) and put another (e.g., the landing pad) on top of it using 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 at the top left corner of the image. Therefore, increasing `y` values is equivalent to moving down on the image. ***Hint:*** You can use the `scale` function to make your robot/landing pad larger or smaller. ***Hint:*** Experiment first to create a single expression that generates the image that you want at *some* coordinate, then move that code into the body of the function and use the function input parameter for the `y` coordinate instead. ___ ### CHECKPOINT: **Call a TA over once you've written your frame generator function.** ___ ## Problem 2 -- Connecting the Images With `falling-robot`, we can generate an entire sequence of images, for example by writing: ``` falling-robot(0) falling-robot(20) falling-robot(40) falling-robot(60) falling-robot(80) ... ``` This sequence of expressions creates all the frame images for an animation, but we still seem to be writing (roughly) the same expression over and over. If we want to automatically generate animations, it would be great to have a program *generate the sequence*, not just the individual images. **Task -- Discuss with your partner:** Previously, we have looked at multiple expressions to see whether they differ in a few spots. This time, we want to ask a more sophisticated question: is there a *pattern across those differences*? Look at the sequence of `falling-robot` calls just above. Do you see any sort of pattern across each consecutive pair of `falling-robot` calls? Hopefully you noticed that the `y` coordinate is increasing by 20 from one expression to the next. The same computation (increase by 20) over and over? That also sounds like a function! For example: ``` fun update-coord(y :: Number) -> Number: doc: "generate y coordinate for next image" y + 20 end ``` Step back and think about what the combination of `falling-robot` and `update-coord` will let us do. If we have an initial value of the `y` coordinate, we could use it to draw the first frame. We could use `update-coord` to get the next coordinate and draw the second frame. We could repeat this sequence to continue generating images. In other words, these two functions define an animation! If we could get Pyret to use our functions to generate the images and flip through them, we'd be done. Fortunately, Pyret has such a feature. **Task:** Stop and note any questions you have about where we are at this point. Write them down and discuss them within your pair. ## Problem 3 -- Making the Animation: The Reactor We now have two functions that work with `y`-coordinates: `falling-robot` produces an image at one `y`-coordinate, while `update-coord` produces the next `y`-coordinate at which to draw an image. If we can make these two functions work together, we can get an animation without us having to create images by hand. Luckily, Pyret has something called a `Reactor` that coordinates these functions for us. Add the following code to your file, then run it: ``` include reactors # put this at the top of your file # put this underneath your falling-robot and update-coord functions my-reactor = reactor: init: 0, # the initial y-coord value to-draw: falling-robot, on-tick: update-coord end interact(my-reactor) ``` You should now see something like the first animation we showed you! (the robot will fly past the landing pad and go off the bottom of the screen -- we'll fix that later) ![](https://imgur.com/lcnma6F.gif) ### What's a Reactor? A reactor is a special value in Pyret that has different components that play a part in creating the animation you see when you call `interact` on the reactor. Let's look at what the components of the reactor are doing: * `init: 0` -- the <ins>init</ins>ial y-coordinate for our reactor; this is the initial value of what will be changing frame by frame * `to-draw: falling-robot` -- the function that returns an image based on the current `y`-coordinate * `on-tick: update-coord` -- the function that produces the next `y`-coordinate for our reactor, frame by frame (tick by tick). Its first input will be the `init` value. Here's a visual of what the reactor is doing: ![Breakdown of a reactor.](https://i.imgur.com/kHfVFoR.png) **Task:** Look at the Reactor diagram and the code. Note any observations or things you are curious about regarding reactors in your Google doc. ___ ### CHECKPOINT: **Call over a TA once you reach this point.** ___ ### Problem 3.1: From Animations to Interactive Games What's the difference between an animation and an interactive game? In a game, how elements move are influenced by what a player does (like pressing keys). So far, our reactor uses `update-coord` to move the robot every few milliseconds. Now, we want to have the `y` coordinate be influenced by key presses (keeping the robot in the air longer as it falls). Specifically, we want to modify our reactor so that if a user presses the `"b"` key, the robot gets a "boost", which reduces its `y`-coordinate by 40 pixels. To do this, we need the following function, which Pyret will call whenever a key gets pressed. It returns the next `y` coordinate based on which key got pressed: ``` fun boost-robot(y :: Number, key :: String) -> Number: doc: "if the key is 'b', lower coord by 40; otherwise leave coord alone end ``` **Task:** Create a good set of `where` examples for this function. **Task:** Write the function. **Task:** Add the `boost-robot` function to your reactor like this: ``` my-reactor = reactor: init: init-coord, to-draw: falling-robot, on-tick: update-coord, on-key: boost-robot end ``` Try playing your new game! **Optional Task:** If you want to, extend your `boost-robot` to also recognize key `"t"`, which "turbo boosts" the robot upwards 150 pixels. (Or you can go on to some of the other options to extend your animation.) **Reflecting on Functions** Let's step back. up until now, we have created functions for two main purposes: - Give a name to repeated expressions (to enable reuse) - Add clarity by naming intermediate computations While we motivated writing functions from the first purpose at the start of lab, reactors seem to use functions for a slightly different purpose: they bundle up a computation so that another piece of code (that you didn't write) can use it when needed. Here, the reactor needs to know what you want to do when a key is pressed, what image it should draw, etc. The reactor knows how to make animations (draw pictures, update coordinates, repeat), but only YOU (the animation designer) know the details that you want. Hence, the function becomes a communication mechanism: you give details to another piece of code that performs a common task. **Task:** Discuss this with your partner: does this new use of functions make sense? What questions do you have, whether about functions or reactors? Put your questions in this [Google Form](https://docs.google.com/forms/d/e/1FAIpQLSesjQZ1EYgQaUNdEzuUp7nNc0SscwrqM-ptjd2t9D5oOOzk_g/viewform?usp=sf_link) (so Kathi and Milda can review them). ___ ### CHECKPOINT: **Call over a TA once you reach this point.** ___ ### Problem 3.2: Additional Features Here are some additional features you can implement if you have time. You could also come up with your own (remember, you can include more behaviors with additional keys). ***Wrap-around:*** What happens if the robot misses the landing pad? Would the robot tragically crash to the ground? (Try this out using your current reactor.) Modify your `on-tick` function so that if the robot goes off the bottom of the screen, it starts again from the top (PHEW!). ***Collisions:*** Write a function `found-landing-pad` that takes in a `y`-coordinate representing the position of the robot and returns a `Boolean` indicating whether the robot has landed on (or _collided with_) the landing pad. Add it to your reactor like this: ``` my-reactor = reactor: init: init-coord, to-draw: falling-robot, on-tick: update-coord, on-key: boost-robot, stop-when: found-landing-pad end ``` Next, congratulate yourself for successfully scoring a robot on your landing pad by modifying `to-draw` so that if there is a `collision` (`found-landing-pad` returns true), the image becomes a congratulatory image of your choice. ___ ### CHECKPOINT: **Call over a TA once you reach this point.** ___ ## Robot saved! Thanks to your excellent space-navigating skills, you were able to rescue the falling robot from its demise! Safely on your landing pad, you can now sit back, relax, and enjoy.

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully