• No results found

Animation Run the example program, backAndForth0.py The whole program is shown below

In document Python 3 Hands-Oon.pdf (Page 76-80)

Objects and Methods

2.3. MAD LIBS REVISITED

2.4.8. Animation Run the example program, backAndForth0.py The whole program is shown below

for convenience. Then each individual new part of the code is discussed individually: ’’’Test animation and depth.

’’’

from graphics import * import time

def main():

winWidth = 300

6Actually, lists are even trickier, because the elements of a list are arbitrary: There can still be issues of dependence

between the original and cloned list if the elements of the list are themselves mutable, and then you choose to mutate an element.

winHeight = 300

win = GraphWin(’Back and Forth’, winWidth, winHeight) win.setCoords(0, 0, winWidth, winHeight)

rect = Rectangle(Point(200, 90), Point(220, 100)) rect.setFill("blue") rect.draw(win) cir1 = Circle(Point(40,100), 25) cir1.setFill("yellow") cir1.draw(win) cir2 = Circle(Point(150,125), 25) cir2.setFill("red") cir2.draw(win)

for i in range(46): # animate cir1 to the right cir1.move(5, 0)

time.sleep(.05)

for i in range(46): # animate cir1 to the left cir1.move(-5, 0)

time.sleep(.05)

# Wait for a final click to exit

Text(Point(winWidth/2, 20), ’Click anywhere to quit.’).draw(win) win.getMouse()

win.close()

main()

Read the discussion below of pieces of the code from the program above. Do not try to execute fragments alone.

There is a new form of import statement: from graphics import *

import time

The program uses a function from the time module. The syntax used for the time module is actually the safer and more typical way to import a module. As you will see later in the program, the sleep function used from the time module will be referenced as time.sleep(). This tells the Python interpreter to look in the time module for the sleep function.

If we had used the import statement from time import *

then the sleep function could just be referenced with sleep(). This is obviously easier, but it obscures the fact that the sleep function is not a part of the current module. Also several modules that a program imports might have functions with the same name. With the individual module name prefix, there is no ambiguity. Hence the form import moduleName is actually safer than from moduleName import *.

You might think that all modules could avoid using any of the same function names with a bit of planning. To get an idea of the magnitude of the issue, have a look at the number of modules available to Python. Try the following in the in the Shell (and likely wait a number of seconds):

help(’modules’)

Without module names to separate things out, it would be very hard to totally avoid name collisions with the enormous number of modules you see displayed, that are all available to Python!

Back to the current example program: The main program starts with standard window creation, and then makes three objects:

2.4. GRAPHICS 78

rect = Rectangle(Point(200, 90), Point(220, 100)) rect.setFill("blue") rect.draw(win) cir1 = Circle(Point(40,100), 25) cir1.setFill("yellow") cir1.draw(win) cir2 = Circle(Point(150,125), 25) cir2.setFill("red") cir2.draw(win)

Zelle’s reference pages do not mention the fact that the order in which these object are first drawn is significant. If objects overlap, the ones which used the draw method later appear on top. Other object methods like setFill or move do not alter which are in front of which. This becomes significant when cir1 moves. The moving cir1 goes over the rectangle and behind cir2. (Run the program again if you missed that.)

The animation starts with the code for a simple repeat loop: for i in range(46): # animate cir1 to the right

cir1.move(5, 0) time.sleep(.05)

This very simple loop animates cir1 moving in a straight line to the right. As in a movie, the illusion of continuous motion is given by jumping only a short distance each time (increasing the horizontal coordinate by 5). The time.sleep function, mentioned earlier, takes as parameter a time in seconds to have the program sleep, or delay, before continuing with the iteration of the loop. This delay is important, because modern computers are so fast, that the intermediate motion would be invisible without the delay. The delay can be given as a decimal, to allow the time to be a fraction of a second.

The next three lines are almost identical to the previous lines, and move the circle to the left (-5 in the horizontal coordinate each time).

for i in range(46): # animate cir1 to the left cir1.move(-5, 0)

time.sleep(.05)

The window closing lines of this program include a slight shortcut from earlier versions. Text(Point(winWidth/2, 20), ’Click anywhere to quit.’).draw(win)

The text object used to display the final message only needs to be referred to once, so a variable name is not necessary: The result of the Text object returned by the constructor is immediately used to draw the object. If the program needed to refer to this object again, this approach would not work.

The next example program, backAndForth1.py, it just a slight variation, looking to the user just like the last version. Only the small changes are shown below. This version was written after noticing how similar the two animation loops are, suggesting an improvement to the program: Animating any object to move in a straight line is a logical abstraction well expressed via a function.

The loop in the initial version of the program contained a number of arbitrarily chosen constants, which make sense to turn into parameters. Also, the object to be animated does not need to be cir1, it can be any of the drawable objects in the graphics package. The name shape is used to make this a parameter:

def moveOnLine(shape, dx, dy, repetitions, delay): for i in range(repetitions):

shape.move(dx, dy) time.sleep(delay)

Then in the main function the two similar animation loops are reduced to a line for each direction: moveOnLine(cir1, 5, 0, 46, .05)

Make sure you see these two lines with function calls behave the same way as the two animation loops in the main program of the original version.

Run the next example version, backAndForth2.py. The changes are more substantial here, and the display of the whole program is followed by display and discussion of the individual changes:

’’’Test animation of a group of objects making a face. ’’’

from graphics import * import time

def moveAll(shapeList, dx, dy):

’’’ Move all shapes in shapeList by (dx, dy).’’’ for shape in shapeList:

shape.move(dx, dy)

def moveAllOnLine(shapeList, dx, dy, repetitions, delay): ’’’Animate the shapes in shapeList along a line. Move by (dx, dy) each time.

Repeat the specified number of repetitions.

Have the specified delay (in seconds) after each repeat. ’’’ for i in range(repetitions): moveAll(shapeList, dx, dy) time.sleep(delay) def main(): winWidth = 300 winHeight = 300

win = GraphWin(’Back and Forth’, winWidth, winHeight)

win.setCoords(0, 0, winWidth, winHeight) # make right side up coordinates!

rect = Rectangle(Point(200, 90), Point(220, 100)) rect.setFill("blue") rect.draw(win) head = Circle(Point(40,100), 25) head.setFill("yellow") head.draw(win) eye1 = Circle(Point(30, 105), 5) eye1.setFill(’blue’) eye1.draw(win)

eye2 = Line(Point(45, 105), Point(55, 105)) eye2.setWidth(3)

eye2.draw(win)

mouth = Oval(Point(30, 90), Point(50, 85)) mouth.setFill("red")

mouth.draw(win)

2.4. GRAPHICS 80

In document Python 3 Hands-Oon.pdf (Page 76-80)