#---------------------------------------------------------------------- # # Introduction to animations and creation of movies # # Copyright (C) February 15, 2017 -- Dr. William T. Verts #---------------------------------------------------------------------- import time # Needed for time.sleep function #---------------------------------------------------------------------- # Here is a general purpose circle painting routine. It has two # default parameters, one for the outline color and the other for the # interior color. This means that the circle function can be called # in three different ways: # Circle(Canvas, Xc, Yc, R, blue, cyan) # blue line, cyan body # Circle(Canvas, Xc, Yc, R, blue) # blue line, white body # Circle(Canvas, Xc, Yc, R) # black line, white body #---------------------------------------------------------------------- def Circle(Canvas, Xcenter, Ycenter, Radius, LineColor=black, InsideColor=white): addOvalFilled(Canvas, Xcenter-Radius, Ycenter-Radius, 2*Radius, 2*Radius, InsideColor) addOval (Canvas, Xcenter-Radius, Ycenter-Radius, 2*Radius, 2*Radius, LineColor) return #---------------------------------------------------------------------- # Draw a radius 50 circle at the center of the screen #---------------------------------------------------------------------- def Main1(): Canvas = makeEmptyPicture(800, 600) show(Canvas) Circle(Canvas, 400, 300, 50, blue, cyan) repaint(Canvas) return #---------------------------------------------------------------------- # Same as Main1, but constants now exposed as of variables #---------------------------------------------------------------------- def Main2(): Canvas = makeEmptyPicture(800, 600) show(Canvas) X = 400 Y = 300 Radius = 50 Circle(Canvas, X, Y, Radius, blue, cyan) repaint(Canvas) return #---------------------------------------------------------------------- # Make the ball crawl off-screen to the lower right (goes forever), # leaving a trail of slime behind. You'll need to hit the STOP button! #---------------------------------------------------------------------- def Main3(): Canvas = makeEmptyPicture(800, 600) show(Canvas) X = 400 Y = 300 Radius = 50 while (True): Circle(Canvas, X, Y, Radius, blue, cyan) X = X + 1 Y = Y + 1 repaint(Canvas) return #---------------------------------------------------------------------- # Same as last version, but direction of travel now stored in variables # that can be tested or changed to get the ball to go in different # directions. #---------------------------------------------------------------------- def Main4(): Canvas = makeEmptyPicture(800, 600) show(Canvas) X = 400 Y = 300 Radius = 50 XD = 1 YD = 1 while (True): Circle(Canvas, X, Y, Radius, blue, cyan) X = X + XD Y = Y + YD repaint(Canvas) return #---------------------------------------------------------------------- # Bounce the ball off of the walls. There are several problems with # this code: # 1: We still leave a 'trail of slime' # 2: The ball bounces really fast, giving flicker # 3: The ball bounces off of its center, instead of its edge #---------------------------------------------------------------------- def Main5(): Canvas = makeEmptyPicture(800, 600) show(Canvas) X = 400 Y = 300 Radius = 50 XD = 1 YD = 1 while (True): Circle(Canvas, X, Y, Radius, blue, cyan) X = X + XD Y = Y + YD if (X > getWidth(Canvas)): XD = -1 elif (X < 0): XD = 1 if (Y > getHeight(Canvas)): YD = -1 elif (Y < 0): YD = 1 repaint(Canvas) return #---------------------------------------------------------------------- # To get rid of the trail of slime, clear the screen just before # painting the ball by filling a rectangle the size of the screen. # The flicker, if anything, is worse. #---------------------------------------------------------------------- def Main6(): Canvas = makeEmptyPicture(800, 600) show(Canvas) X = 400 Y = 300 Radius = 50 XD = 1 YD = 1 while (True): addRectFilled(Canvas, 0, 0, getWidth(Canvas), getHeight(Canvas), white) Circle(Canvas, X, Y, Radius, blue, cyan) X = X + XD Y = Y + YD if (X > getWidth(Canvas)): XD = -1 elif (X < 0): XD = 1 if (Y > getHeight(Canvas)): YD = -1 elif (Y < 0): YD = 1 repaint(Canvas) return #---------------------------------------------------------------------- # Instead of an explicit rectangle, you can use the JES function # setAllPixelsToAColor instead, which is a more efficient method. #---------------------------------------------------------------------- def Main7(): Canvas = makeEmptyPicture(800, 600) show(Canvas) X = 400 Y = 300 Radius = 50 XD = 1 YD = 1 while (True): setAllPixelsToAColor(Canvas, white) Circle(Canvas, X, Y, Radius, blue, cyan) X = X + XD Y = Y + YD if (X > getWidth(Canvas)): XD = -1 elif (X < 0): XD = 1 if (Y > getHeight(Canvas)): YD = -1 elif (Y < 0): YD = 1 repaint(Canvas) return #---------------------------------------------------------------------- # By adding a little delay after the repaint, we can reduce the # flicker. The time.sleep function takes in a time in seconds and # does nothing for that time interval. However, the sleep function # is in the time library, which must be imported at the top of the # program (see the line at the top: import time). The delay of 0.005 # seconds is 1/200th of a second, just enough for the computer's # display to settle before the erase-draw-repaint cycle starts again. #---------------------------------------------------------------------- def Main8(): Canvas = makeEmptyPicture(800, 600) show(Canvas) X = 400 Y = 300 Radius = 50 XD = 1 YD = 1 while (True): setAllPixelsToAColor(Canvas, white) Circle(Canvas, X, Y, Radius, blue, cyan) X = X + XD Y = Y + YD if (X > getWidth(Canvas)): XD = -1 elif (X < 0): XD = 1 if (Y > getHeight(Canvas)): YD = -1 elif (Y < 0): YD = 1 repaint(Canvas) time.sleep(0.005) return #---------------------------------------------------------------------- # By incorporating the radius into the tests for the edge-detection, # the ball now bounces properly. # # All animations should now follow this same basic strategy: # Loop while (True): # Clear the screen setAllPixelsToAColor... # Draw objects on screen Circles/Lines/etc.... # Update object positions X=X+XD, etc.... # repaint the screen repaint(Canvas) # sleep for a while time.sleep(___) # #---------------------------------------------------------------------- def Main9(): Canvas = makeEmptyPicture(800, 600) show(Canvas) X = 400 Y = 300 Radius = 50 XD = 1 YD = 1 while (True): setAllPixelsToAColor(Canvas, white) Circle(Canvas, X, Y, Radius, blue, cyan) X = X + XD Y = Y + YD if (X > getWidth(Canvas)-Radius): XD = -1 elif (X < Radius): XD = 1 if (Y > getHeight(Canvas)-Radius): YD = -1 elif (Y < Radius): YD = 1 repaint(Canvas) time.sleep(0.005) return #---------------------------------------------------------------------- # Instead of a infinite while-loop, we can use a for-loop to control # the overall number of frames of animation. Loop control variable I # will contain the number of the current frame. #---------------------------------------------------------------------- def Main10(): Canvas = makeEmptyPicture(800, 600) show(Canvas) X = 400 Y = 300 Radius = 50 XD = 1 YD = 1 for I in range(1000): setAllPixelsToAColor(Canvas, white) Circle(Canvas, X, Y, Radius, blue, cyan) X = X + XD Y = Y + YD if (X > getWidth(Canvas)-Radius): XD = -1 elif (X < Radius): XD = 1 if (Y > getHeight(Canvas)-Radius): YD = -1 elif (Y < Radius): YD = 1 repaint(Canvas) time.sleep(0.005) return #---------------------------------------------------------------------- # In this final version, we save each frame to a file called # SAVE00000.jpg, SAVE00001.jpg, SAVE00002.jpg, etc. I recommend # creating a folder on your desktop called FRAMES to save those images, # and open that folder in the new pickAFolder call. # The new code inside the loop is to convert the frame number stored # in I into a 5-character string, where the leading characters are all # "0", and as many as are needed are padded to bring the length up to # a total of 5 characters. The filename is then constructed from the # folder, the literal string "SAVE", the 5-character zero-padded # number, and the literal string ".jpg" (note that JES does not like # the capitalized ".JPG" so make sure to leave this as lower case). # The canvas is then written to the named file. Because the loop runs # for 1000 cycles, the folder FRAMES will end up with 1000 individual # .jpg image files. The last two lines before the return create a # movie object from all the frames, and then write it out as an Apple # Quicktime movie file called MOVIE.mov (you can name it whatever you # want as long as it has a .mov extension). Once the movie has been # created, all the 1000 .jpg files can be deleted, and you will have # a nice little movie to show - the movie is stand-alone, and does not # need the Python program to run! #---------------------------------------------------------------------- def Main11(): Folder = pickAFolder() Canvas = makeEmptyPicture(800, 600) show(Canvas) X = 400 Y = 300 XD= 1 YD= 1 Radius = 50 for I in range(1000): setAllPixelsToAColor(Canvas, white) Circle(Canvas, X, Y, Radius, blue, cyan) X = X + XD Y = Y + YD if (X > getWidth(Canvas)-Radius): XD = -1 elif (X < Radius): XD = 1 if (Y > getHeight(Canvas)-Radius): YD = -1 elif (Y < Radius): YD = 1 repaint(Canvas) time.sleep (0.005) S = str(I) while (len(S) < 5): S = "0" + S Filename = "SAVE" + S + ".jpg" writePictureTo(Canvas, Folder + Filename) MyMovie = makeMovieFromInitialFile(Folder + "SAVE00000.jpg") writeQuicktime(MyMovie, Folder + "MOVIE.mov") return