15-112: Fundamentals of Programming and Computer Science
Class Notes: Step Animations


  1. Import File (stepAnimation.py)
  2. Static (not changing) Square Animation
  3. Sweeping Square Animation
  4. Wraparound Square Animation
  5. Faster Wraparound Square Animation
  6. Horizontal Bouncing Square Animation
  7. 2d Bouncing Circle Animation
  8. Changing Other Properties
  9. Extra Keyword Parameters

  1. Import File (stepAnimation.py)
    To run these examples, download stepAnimation.py and save it in the same folder where you are editing and running your animation.

  2. Static (not changing) Square Animation
    import stepAnimation
    
    def staticSquareAnimation(canvas, width, height, step):
        left = 0
        canvas.create_rectangle(left, 0, left+20, 20, fill="blue")
    
    stepAnimation.run(staticSquareAnimation)
    

  3. Sweeping Square Animation
    import stepAnimation
    
    def sweepingSquareAnimation(canvas, width, height, step):
        left = step
        canvas.create_rectangle(left, 0, left+20, 20, fill="blue")
    
    stepAnimation.run(sweepingSquareAnimation)
    

    again, with custom window size
    stepAnimation.run(sweepingSquareAnimation, width=400, height=100)
    

    again, with custom initial speed (timerDelay is in milliseconds)
    stepAnimation.run(sweepingSquareAnimation, timerDelay=1)
    

  4. Wraparound Square Animation
    import stepAnimation
    
    def wraparoundSquareAnimation(canvas, width, height, step):
        left = step % width
        canvas.create_rectangle(left, 0, left+20, 20, fill="blue")
    
    stepAnimation.run(wraparoundSquareAnimation, width=200, timerDelay=1)
    

  5. Faster Wraparound Square Animation
    import stepAnimation
    
    def fasterWraparoundSquareAnimation(canvas, width, height, step):
        left = 5*step % width
        canvas.create_rectangle(left, 0, left+20, 20, fill="blue")
    
    stepAnimation.run(fasterWraparoundSquareAnimation, width=200, timerDelay=1)
    

  6. Horizontal Bouncing Square Animation
    import stepAnimation
    
    def bouncingSquareAnimation(canvas, width, height, step):
        halfPeriod = 50 # steps until we reach the right side
        step = step % (2*halfPeriod)
        if (step < halfPeriod):
            m = width/halfPeriod
            left = m*step
        else:
            m = -width/halfPeriod
            left = m*(step-halfPeriod)+width
        canvas.create_rectangle(left, 0, left+20, 20, fill="blue")
    
    stepAnimation.run(bouncingSquareAnimation, width=400, height=100, timerDelay=8)
    

    again with some interesting alternative ways of computing the zig-zag pattern:
    import stepAnimation
    import math
    
    def bouncingSquareAnimation0(canvas, width, height, step):
        halfPeriod = 50 # steps until we reach the right side
        step = step % (2*halfPeriod)
        if (step < halfPeriod):
            m = width/halfPeriod
            left = m*step
        else:
            m = -width/halfPeriod
            left = m*(step-halfPeriod)+width
        canvas.create_rectangle(left, 0, left+20, 20, fill="blue")
    
    def bouncingSquareAnimation1(canvas, width, height, step):
        # This variation uses abs() to create a sawtooth or zig-zag pattern.
        halfPeriod = 50
        step = step % (2*halfPeriod)
        left = width * (1 - float(abs(step - halfPeriod))/halfPeriod)
        canvas.create_rectangle(left, 0, left+20, 20, fill="blue")
    
    def bouncingSquareAnimation2(canvas, width, height, step):
        # Thanks to Sunny G for this clever idea!
        # acos(cos(x)) zig-zags with the base period of 0 <= x <= 2*pi,
        # and with 0 <= y <= pi, so we just adjust these scales as needed.
        halfPeriod = 50
        left = math.acos(math.cos(step*math.pi/halfPeriod))*width/math.pi
        canvas.create_rectangle(left, 0, left+20, 20, fill="blue")
    
    def bouncingSquareAnimations(canvas, width, height, step):
        # All at once!
        #################################
        halfPeriod = 50 # steps until we reach the right side
        step = step % (2*halfPeriod)
        if (step < halfPeriod):
            m = width/halfPeriod
            left = m*step
        else:
            m = -width/halfPeriod
            left = m*(step-halfPeriod)+width
        canvas.create_rectangle(left, 10, left+20, 30, fill="red")
        #################################
        left = width * (1 - float(abs(step - halfPeriod))/halfPeriod)
        canvas.create_rectangle(left, 40, left+20, 60, fill="blue")
        #################################
        # Note that this version still works without mod'ing the step above!
        left = math.acos(math.cos(step*math.pi/halfPeriod))*width/math.pi
        canvas.create_rectangle(left, 70, left+20, 90, fill="green")
    
    stepAnimation.run(bouncingSquareAnimations, width=400, height=100, timerDelay=8)
    

  7. 2d Bouncing Circle Animation
    import stepAnimation
    
    def bouncingCircleAnimation(canvas, width, height, step):
        # First do the horizontal direction
        halfPeriod = 50 # steps until we reach the right side
        step = step % (2*halfPeriod)
        if (step < halfPeriod):
            m = width/halfPeriod
            left = m*step
        else:
            m = -width/halfPeriod
            left = m*(step-halfPeriod)+width
        # Now by analogy do the vertical direction
        halfPeriod = 10 # steps until we reach the bottom side
        step = step % (2*halfPeriod)
        if (step < halfPeriod):
            m = height/halfPeriod
            top = m*step
        else:
            m = -height/halfPeriod
            top = m*(step-halfPeriod)+height
        canvas.create_oval(left, top, left+20, top+20, fill="blue")
    
    stepAnimation.run(bouncingCircleAnimation, width=400, height=100, timerDelay=8)
    

    or, if you prefer:
    import stepAnimation
    import math
    
    def bouncingCircleAnimation(canvas, width, height, step):
        left = math.acos(math.cos(step*math.pi/50))*width/math.pi
        top  = math.acos(math.cos(step*math.pi/10))*height/math.pi
        canvas.create_oval(left, top, left+20, top+20, fill="blue")
    
    stepAnimation.run(bouncingCircleAnimation, width=400, height=100, timerDelay=8)
    

  8. Changing Other Properties
    import stepAnimation
    from Tkinter import *
    
    def rgbString(red, green, blue):
        return "#%02x%02x%02x" % (red, green, blue)
    
    def changingPropertiesAnimation(canvas, width, height, step):
        # change the fill color
        fillColor = rgbString(0, step%256, 0)
        (cx, cy) = (width/4, height/2)
        r = min(width,height)/3
        canvas.create_oval(cx-r, cy-r, cx+r, cy+r, fill=fillColor)
    
        # change the text and anchor
        (cx, cy) = (width/2, height/2)
        canvas.create_oval(cx-5, cy-5, cx+5, cy+5, fill="green",width=0)
        option = ((step/50) % 4)
        if (option == 0): (text,anchor) = ("NE anchor", NE)
        elif (option == 1): (text,anchor) = ("CENTER anchor", CENTER)
        elif (option == 2): (text,anchor) = ("SW anchor", SW)
        else: (text,anchor) = ("E anchor", E)
        canvas.create_text(cx, cy, text=text, anchor=anchor)
    
        # change the outline width
        (cx, cy) = (width*3/4, height/2)
        outlineWidth = 1+((step/20)%10)
        canvas.create_oval(cx-r, cy-r, cx+r, cy+r,
                           fill="cyan", width=outlineWidth)
    
        # change the line endpoint
        x = step%width
        canvas.create_line(0, 0, x, height, fill="gray", width=3)
    
    stepAnimation.run(changingPropertiesAnimation, width=400, height=100, timerDelay=16)
    

  9. Extra Keyword Parameters
    import stepAnimation
    from Tkinter import *
    
    # This function takes two extra parameters: text and color
    def kwArgsDemoAnimation(canvas, width, height, step, text, color):
        left = step % width
        top = 20
        font = "Arial " + str(step%100) + " bold"
        canvas.create_text(left, 20, text=text, font=font, fill=color, anchor=NW)
    
    # And this is how you call it with values for those parameters:
    stepAnimation.run(kwArgsDemoAnimation, width=400, height=90, timerDelay=10,
                      text="Fantastic!", color="brown")