Animations Lab

 


Introduction

The objective of this lab is to become familiar with using lists in animations. (The heart of this lab is Part 2.)



Part 1: Using Lists to Display an Animation

We are going to experiment with another method for viewing animations. Up until this point, we have been repeatedly copying the background onto the canvas, calculating where we want to put some type of object or objects, copying them onto the canvas, and then showing the canvas. The disadvantage of this approach is that the rate the animation is displayed is impacted by the time spent setting up the canvas. An alternative is to set up all of the individual frames of our animation in advance, then show the animation by looping through the completed frames. The following function takes a list of pictures as a parameter, along with a frame rate, and displays the pictures as an animation:

#----------------------------------------------------------------------
#playMovie - Play a list of pictures as a movie.
#movie - A list of pictures.   
#frameRate - The number of frames that should be displayed per second. 
#            Higher numbers will result in faster animations.
#----------------------------------------------------------------------
def playMovie(movie, frameRate):
  import time
  canvas = duplicatePicture(movie[0])
  toSleep = max(1.0/frameRate, 0)  
  for index in range(len(movie)):
    if isinstance(movie[index], Picture):
      copyPictureInto(movie[index],canvas,0,0)
      repaint(canvas)
      time.sleep(toSleep)
  1. Copy the playMovie function into your .py file, and copy the function copyPictureInto from the Support Code.
  2. Functions for setting up full animations will look very similar to the animation functions we have been writing all along. The only difference is that instead of displaying each frame in the function, we will place the frames in a list. Copy the following code and run the function in JES. The function returns a list of pictures that can be passed to playMovie. (The explanation of what is happening is below.)
    def moveRectInLine():
      canvas = makeEmptyPicture(300,300, red)
      rectSize = 20
    
      # Set up a list and initialize it to all zeros
      picList = [0] * getWidth(canvas)
      count = 0
    
      # Create the new pictures and save them in the list
      for x in range(0, getWidth(canvas) - rectSize, 10):
        addRectFilled(canvas, x, 10, rectSize, rectSize, white)
        copyOfCanvas = duplicatePicture(canvas)
        picList[count] = copyOfCanvas
        addRectFilled(canvas, x, 10, rectSize, rectSize, red)
        count = count + 1
      return picList
    
  3. So what did we do?
    • We first created an empty picture and specified the size of the box.
    • We then set up a list, called picList, to be all zeros. The list was set up to be getWidth(pict) elements long because that is the upper limit on how many times the box might move horizontally.
    • We set up a variable called count that keeps track of how many pictures have been added to the list.
    • In the loop that does the moving, we "painted" the rectangle on the canvas, then saved a copy of the canvas in the list at the next available index.
    • We then "erased" the rectangle that was moving and incremented the count by 1.
    • Finally, we returned the resulting list.
  4. Optional: Modify your function to move a box along the diagonal so that it saves all the pictures in a list first, and then returns the list.

Part 2: Colors and Animations

So far in our animations, we have only seen how to move objects on a canvas. In this section, we will experiment with a sunset animation and a fadeout animation.
  1. Copy the following program, slowFadeOut, to JES. This function saves the new pictures in a list, and then returns the list.
    This function takes a long time to process so you should run it on small files. You may use functions you have written previously to make your own files smaller.
    
    # Slow Fadeout
    # The original background, the new background and 
    # the original picture are the parameters.
    # Be sure to try this out with small pictures!
    #PARAMETERS:
    # background -    a picture of an empty background. 
    # newBackground - a picture of some other scene that will become the 
    #                 new background.
    # person - A picture that matches background, with the addition of a
    # person (or other object).
    def slowFadeOut(background, newBackground, person):
      # Set up a list and initialize it to all zeros
      picList = [0] * 10
      count = 0
    
      # Only 10 frames or it takes too long
      for threshold in range (1, 101, 10):
        canvas = duplicatePicture(person) 
        printNow("Frame number: " + str(count))
        swapbg(canvas, background, newBackground, threshold)
        #copy the picture into the list
        copyOfCanvas = duplicatePicture(canvas)
        picList[count] = copyOfCanvas
        count = count + 1
      return picList
    
    
    # Swap Background Program with a threshold of closeness for colors
    def swapbg(person, bg, newbg, threshold):
    
      # get all pixels in the picture and their colors
      for x in range(getWidth(person)):
        for y in range(getHeight(person)):
          personPixel = getPixel(person, x, y)
          personColor = getColor(personPixel)
          bgpx = getPixel(bg, x, y)
          bgColor = getColor(bgpx)
    
          # check if the difference in color is within the threshold
          if (distance(personColor, bgColor) < threshold):
            # if so, change the color to the new background's color
            bgcolor = getColor(getPixel(newbg, x, y))
            setColor(personPixel, bgcolor)
    
    
  2. Modify the following program, slowSunset, so that it creates a list of all zeros, saves the new pictures in this list, and then returns the list. You will need to copy the makeSunset function from the notes on Pictures and Loops. Modify makeSunset to multiply by 0.8 instead of by 0.70. When you call the function, use a small file, such as the file beach-smaller.jpg file from the MediaSources directory to save time.
    def slowSunset(picture):
      count = 0
      canvas = duplicatePicture(picture)
      show(canvas)
      # Only 10 frames or it takes too long
      for x in range (1, 101, 10): 
        printNow("Frame number: " + str(count))
        canvas = makeSunset(canvas)
        repaint(canvas)
        count = count + 1
    

Submit your results

  1. Submit the file you created in this lab to Kit.