1 / 52

Chapter 24 – Multimedia

Chapter 24 – Multimedia. Outline 24.1 Introduction 24.2 Introduction to PyOpenGL 24.3 PyOpenGL examples 24.4 Introduction to Alice 24.5 Fox, Chicken and Seed Problem 24.6 Introduction to pygame 24.7 Python CD Player 24.8 Python Movie Player 24.9 Pygame Space Cruiser.

piercy
Télécharger la présentation

Chapter 24 – Multimedia

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 24 – Multimedia Outline24.1 Introduction24.2 Introduction to PyOpenGL24.3 PyOpenGL examples 24.4 Introduction to Alice 24.5 Fox, Chicken and Seed Problem 24.6 Introduction to pygame24.7 Python CD Player 24.8 Python Movie Player 24.9 Pygame Space Cruiser

  2. 24.1 Introduction • Rapid growth of the computing industry has brought multimedia to the desktop computer in the form of CD-ROMs, DVDs and streaming audio and video over the Web

  3. 24.2 Introduction to PyOpenGL • Module PyOpenGL • encapsulates the capabilities of the OpenGL Application Programming Interface • a library for rendering 2D and 3D graphics • OpenGL Utility Toolkit (GLUT), wxPython, Tkinter and FxPy provide an OpenGL context in which to display OpenGL-rendered graphics

  4. 24.2 Introduction to PyOpenGL • Module PyOpenGL includes Tkinter component Opengl, which displays OpenGL graphics and allows access to Tkinter components and layout managers • Opengl component has an event bound to each mouse button • Left mouse button: moving objects • Middle mouse button: rotating objects • Right mouse button: resizing objects

  5. 24.3 PyOpenGL Examples • Presents two PyOpenGL examples that create three-dimensional shapes • Figure 24.1 creates a rotating, colorful box • Figure 24.2 allows user to view different 3D GLUT shapes in different colors using a menu

  6. Create Opengl component and enable double buffering Pack Opengl component Set redraw method to update onscreen display each time the image changes Move camera away from the scene Keep track of degrees rotated Rotate 2 degrees Begin rotation with a call to self.update() Draws box on white background 1 # Fig 24.1: fig24_01.py 2 # Colored, rotating box (with open top and bottom). 3 4 from Tkinter import * 5 from OpenGL.GL import * 6 from OpenGL.Tk import * 7 8 class ColorBox( Frame ): 9 """A colorful, rotating box""" 10 11 def __init__( self ): 12 """Initialize GUI and OpenGL""" 13 14 Frame.__init__( self ) 15 self.master.title( "Color Box" ) 16 self.master.geometry( "300x300" ) 17 self.pack( expand = YES, fill = BOTH ) 18 19 # create and pack Opengl -- use double buffering 20 self.openGL = Opengl( self, double = 1 ) 21 self.openGL.pack( expand = YES, fill = BOTH ) 22 23 self.openGL.redraw = self.redraw # set redraw function 24 self.openGL.set_eyepoint( 20 ) # move away from object 25 26 self.amountRotated = 0# total degrees of rotation 27 self.increment = 2# rotate amount in degrees 28 self.update() # begin rotation 29 30def redraw( self, openGL ): 31 """Draw box on white background""" 32 fig24_01.py

  7. Set clearing color Clear color buffer Disable lighting Set each color with red, green and blue components Create list of tuples with form ( (vertex coordinates), color ) Instructs OpenGL to begin drawing a group of connected quadrilaterals Function glColor3f sets the drawing color Function glVertex3f draws the specified vertex Function glEnd indicates end of drawing 33 # clear background and disable lighting 34 glClearColor( 1.0, 1.0, 1.0, 0.0 ) # set clearing color 35 glClear( GL_COLOR_BUFFER_BIT ) # clear background 36 glDisable( GL_LIGHTING ) 37 38 # constants 39 red = ( 1.0, 0.0, 0.0 ) 40 green = ( 0.0, 1.0, 0.0 ) 41 blue = ( 0.0, 0.0, 1.0 ) 42 purple = ( 1.0, 0.0, 1.0 ) 43 44 vertices = \ 45 [ ( ( -3.0, 3.0, -3.0 ), red ), 46 ( ( -3.0, -3.0, -3.0 ), green ), 47 ( ( 3.0, 3.0, -3.0 ), blue ), 48 ( ( 3.0, -3.0, -3.0 ), purple ), 49 ( ( 3.0, 3.0, 3.0 ), red ), 50 ( ( 3.0, -3.0, 3.0 ), green ), 51 ( ( -3.0, 3.0, 3.0 ), blue ), 52 ( ( -3.0, -3.0, 3.0 ), purple ), 53 ( ( -3.0, 3.0, -3.0 ), red ), 54 ( ( -3.0, -3.0, -3.0 ), green ) ] 55 56 glBegin( GL_QUAD_STRIP ) # begin drawing 57 58 # change color and plot point for each vertex 59 for vertex in vertices: 60 location, color = vertex 61 apply( glColor3f, color ) 62 apply( glVertex3f, location ) 63 64 glEnd() # stop drawing 65 fig24_01.py

  8. Method update rotates the box Change rotation direction after box has rotated > 500 degrees Method glRotate rotates box self.increment degrees Box rotated around line through origin and (1.0, 1.0, 1.0) Update self.amountRotated Method tkRedraw updates display with rotated box Method after schedules self.update to be called every 10ms 66def update( self ): 67 """Rotate box""" 68 69if self.amountRotated >= 500: # change rotation direction 70 self.increment = -2# rotate left 71 elif self.amountRotated <= 0: # change rotation direction 72 self.increment = 2# rotate right 73 74 # rotate box around x, y, z axis ( 1.0, 1.0, 1.0 ) 75 glRotate( self.increment, 1.0, 1.0, 1.0 ) 76 self.amountRotated += self.increment 77 78 self.openGL.tkRedraw() # redraw geometry 79 self.openGL.after( 10, self.update ) # call update in 10ms 80 81 def main(): 82 ColorBox().mainloop() 83 84 if __name__ == "__main__": 85 main() fig24_01.py

  9. fig24_01.py

  10. Provides methods for creating 3D shapes Create and pack Opengl component and enable double buffering Enable auto-spin 1 # Fig. 24.2: fig24_02.py 2 # Demonstrating various GLUT shapes. 3 4 from Tkinter import * 5 import Pmw 6 from OpenGL.GL import * 7 from OpenGL.Tk import * 8from OpenGL.GLUT import * 9 10 class ChooseShape( Frame ): 11 """Allow user to preview different shapes and colors""" 12 13 def __init__( self ): 14 """Initialize GUI and OpenGL""" 15 16 Frame.__init__( self ) 17 Pmw.initialise() 18 self.master.title( "Choose a shape and color" ) 19 self.master.geometry( "300x300" ) 20 self.pack( expand = YES, fill = BOTH ) 21 22 # create and pack MenuBar 23 self.choices = Pmw.MenuBar( self ) 24 self.choices.pack( fill = X ) 25 26 # create and pack Opengl -- use double buffering 27 self.openGL = Opengl( self, double = 1 ) 28 self.openGL.pack( expand = YES, fill = BOTH ) 29 30 self.openGL.redraw = self.redraw # set redraw function 31 self.openGL.set_eyepoint( 20 ) # move away from object 32 self.openGL.autospin_allowed = 1# allow auto-spin 33 34 self.choices.addmenu( "Shape", None ) # Shape submenu 35 fig24_02.py

  11. glutWireCube(x) creates wire cube with sides of length x Dictionary with function names as keys and their possible arguments as values glutSolidCube(x) creates solid cube with sides of length x glutWireIcosahedron creates 20-sided wire shape glutSolidIcosahedron creates 20-sided solid shape glutWireCone and glutSolidCone draw cones glutWireTorus and glutSolidTorus draw tori glutWireTeapot and glutSolidTeapot draw teapots Add shape choices to Shape submenu as radiobutton menu items 36 # possible shapes and arguments 37 self.shapes = { "glutWireCube" : ( 3, ), 38"glutSolidCube": ( 3, ), 39"glutWireIcosahedron" : (), 40"glutSolidIcosahedron" : (), 41"glutWireCone" : ( 3, 3, 50, 50 ), 42 "glutSolidCone" : ( 3, 3, 50, 50 ), 43"glutWireTorus" : ( 1, 3, 50, 50 ), 44 "glutSolidTorus" : ( 1, 3, 50, 50 ), 45"glutWireTeapot" : ( 3, ), 46 "glutSolidTeapot" : ( 3, ) } 47 48 self.selectedShape = StringVar() 49 self.selectedShape.set( "glutWireCube" ) 50 51 sortedShapes = self.shapes.keys() 52 sortedShapes.sort() # sort names before adding to menu 53 54 # add items to Shape menu 55for shape in sortedShapes: 56 self.choices.addmenuitem( "Shape", "radiobutton", 57 label = shape, variable = self.selectedShape, 58 command = self.refresh ) 59 60 self.choices.addmenu( "Color", None ) # Color submenu 61 62 # possible colors and their values 63 self.colors = { "Black" : ( 0.0, 0.0, 0.0 ), 64 "Blue" : ( 0.0, 0.0, 1.0 ), 65 "Red" : ( 1.0, 0.0, 0.0 ), 66 "Green" : ( 0.0, 1.0, 0.0 ), 67 "Magenta" : ( 1.0, 0.0, 1.0 ) } 68 69 self.selectedColor = StringVar() 70 self.selectedColor.set( "Black" ) fig24_02.py

  12. Add color choices to submenu Colors as radiobutton menu items Obtain selected drawing color Set selected drawing color Obtain selected shape Draw selected shape 71 72 # add items to Color menu 73for color in self.colors.keys(): 74 self.choices.addmenuitem( "Color", "radiobutton", 75 label = color, variable = self.selectedColor, 76 command = self.refresh ) 77 78 def redraw( self, openGL ): 79 """Draw selected shape on white background""" 80 81 # clear background and disable lighting 82 glClearColor( 1.0, 1.0, 1.0, 0.0 ) # select clear color 83 glClear( GL_COLOR_BUFFER_BIT ) # paint background 84 glDisable( GL_LIGHTING ) 85 86 # obtain and set selected color 87 color = self.selectedColor.get() 88 apply( glColor3f, self.colors[ color ] ) 89 90 # obtain and draw selected shape 91 shape = self.selectedShape.get() 92 apply( eval( shape ), self.shapes[ shape ] ) 93 94 def refresh( self ): 95 self.openGL.tkRedraw() 96 97 def main(): 98 ChooseShape().mainloop() 99 100 if __name__ == "__main__": 101 main() fig24_02.py

  13. fig24_02.py

  14. 24.4 Introduction to Alice • Alice • 3D Interactive Graphics Programming Environment • Designed for Microsoft Windows operating systems • Provides an environment in which programmers can develop scripts to control the behavior of objects • Uses version of Python interpreter that treats Python as case insensitive

  15. 24.5 Fox, Chicken and Seed Problem • Present Fox, Chicken and Seed problem as a game to demonstrate programming with Alice • Rules: Alice Liddell needs to transport a fox, a chicken and a seed across the river with a small boat. The boat can accommodate only one additional passenger. The fox cannot be left alone with the chicken because the fox will eat the chicken; the chicken cannot be left alone with the seed for the same reason.

  16. 24.5 Fox, Chicken and Seed Problem • Initial scene created using the Alice environment and its predefined objects, including Alice Liddell, the fox, the hen, the flowerpot (the seed), the river and the boat

  17. Indicate camera should follow Alice Liddell object continuously Programmer-defined function animates each fish with a pause Function Loop calls its argument (a function) continuously Function DoTogether runs animations simultaneously Create two jumping fish animations Method Move specifies direction, amount and duration of the movement Method Turn specifies direction, amount and duration of the rotation Lists keep track of each object’s position Variable currentBank refers to the bank at which the boat is docked Callback for animal selection 1 ### We omit the code generated by Alice. ### 2 # Fig. 24.03: fig24_03.py 3 # Fox, Chicken and Seed problem. 4 5FollowTheBoat = Loop( camera.PointAt 6 ( AliceLiddell.dress.rthigh ) ) 7 8 # run the two animations together with a given pause time 9def AnimateWithPause( Animation1, Animation2, Object, time ): 10 11return Loop( DoInOrder( DoTogether( Animation1, Animation2 ), 12 Wait( time ) ) ) 13 14 # create two fish following a continuous animation pattern 15LoopingFish = Loop( AnimateWithPause 16 ( Fish.Move( Forward, 50, Duration = 5 ), 17 Fish.Turn( Down, 1, Duration = 5 ), Fish, 15 ) ) 18 19 LoopingFish2 = Loop( AnimateWithPause 20 ( Fish2.Move( Forward, 70, Duration = 8 ), 21 Fish2.Turn( Down, 1, Duration = 8 ), Fish2, 25 ) ) 22 23 # lists that keep track of object position. 24thisBank = [ "Fox", "Chicken", "Flower" ] 25 theBoat = [] 26 otherBank = [] 27 28currentBank = thisBank 29 targetBank = otherBank 30 selected = None 31 32 # animal select callback 33def animalSelect( value ): 34 fig24_03.py

  18. Put object into the boat Object stops when it reaches FishBoat.deck Move animal to the boat Remove object from boat Place object based on its size so that the objects on the shore do not overlap Determine whether currently selected object can be placed in boat Empty boat must be at the animal’s bank Remove selected animal from currentBank list Append selected animal to theBoat list Call function ObjectInBoat to put animal in the boat Determine if currently selected animal can be removed from boat Currently selected object must be in theBoat list and boat must have arrived at shore Remove object from theBoat list Append object to currentBank list Call ObjectOutOfBoat to remove animal from the boat 35 global selected 36 selected = value 37 38 # put object into the boat 39def ObjectInBoat( Object ): 40 41 Object.RespondToCollisionWith( FishBoat.deck, Object.Stop ) 42 Object.MoveTo( FishBoat.period ) 43 Object.Move( Down, 2, Duration = 3 ) 44 45 # get object out of the boat 46def ObjectOutOfBoat( Object ): 47 48 Object.RespondToCollisionWith( Ground, Object.Stop ) 49 Object.Move( Left, 1 - int( ( len( Object._name ) - 1 ) / 3 )) 50 Object.Move( Back, 7 ) 51 Object.Move( Down, 3, Duration = 3 ) 52 53 # put the currently selected object into the boat 54 def getIntoBoat(): 55 56if selected in currentBank and 57 ( len( theBoat ) == 0 ) and boatArrived(): 58 currentBank.remove( selected ) 59 theBoat.append( selected ) 60 ObjectInBoat( eval( selected ) ) 61 62 # remove currently selected object from the boat 63 def getOutOfBoat(): 64 65if selected in theBoat and boatArrived(): 66 theBoat.remove( selected ) 67 currentBank.append( selected ) 68 ObjectOutOfBoat( eval( selected ) ) 69 fig24_03.py

  19. Send boat to other shore Call function boatArrived to determine if boat still in transit Determine if an animal is on the boat by checking length of list theBoat Animate the boat’s movements across the river and docking Rotate the passenger with the boat Set the rotation so that it happens relative to the boat with AsSeenby Call checkRules with currentBank as an argument 1 second after boat leaves shore Switch currentBank pointer Function boatArrived returns 1 if boat has arrived, 0 otherwise Determine if rules have been violated 70 # send the boat to the other shore 71def toOtherShore(): 72 73ifnot boatArrived(): # boat is still in transit 74 return 75 76 global currentBank, thisBank, otherBank 77 78if len( theBoat ) == 1: # someone is on the boat 79 DoInOrder( eval( theBoat[ 0 ] ).Move( Forward, 16, 80 Duration = 3 ), eval( theBoat[ 0 ] ).Turn( Left, 1/2, 1, 81 AsSeenby = FishBoat ) ) 82 83 # move the boat and then set alarm to check rules 84 DoInOrder( FishBoat.move( Forward, 16, Duration = 3 ), 85 FishBoat.turn( Left, 1/2 ) ) 86 Alice.SetAlarm( 1, checkRules, ( currentBank ) ) 87 88if currentBank == thisBank: # switch the currentBank pointer 89 currentBank = otherBank 90 else: 91 currentBank = thisBank 92 93 # the boat has arrived 94def boatArrived(): 95 96 # check to see if the boat is at the shore 97 if AliceLiddell.DistanceTo( period ) < .01or 98 AliceLiddell.DistanceTo( period2 ) < .01: 99 return 1 100 else: 101 return 0 102 103 # check to see if the rules have been violated 104def checkRules( currentBank ): fig24_03.py

  20. Function destroy removes “eaten” object Call function finishGame with two animations and GAMEOVER if player lost Otherwise, call function finishGame with two animations and CONGRATULATIONS Destroy control panel Stop camera from following boat Method Place places camera relative to text object 105 106 Animation1 = DoInOrder() 107 Animation2 = DoInOrder() 108 109 if"Chicken"in currentBank: 110 111 # chicken eats flower 112 if"Flower"in currentBank: 113 Animation1 = DoInOrder( camera.PointAt( Flower ), 114 Flower.destroy() ) 115 116 # fox eats chicken 117 if"Fox"in currentBank: 118 Animation2 = DoInOrder( camera.PointAt( Chicken ), 119 Chicken.destroy() ) 120 121 # player has lost 122 if ( "Flower"in currentBank ) or 123 ( "Fox"in currentBank ): 124 finishGame( Animation1, Animation2, GAMEOVER ) 125 126 # player wins if nothing left on current bank 127 if len( currentBank ) == 0 and 128 not ( currentBank == targetBank ): 129 finishGame( Animation1, Animation2, CONGRATULATIONS ) 130 131 # game over, AnimationX defaults to an empty sequence 132 def finishGame( Animation1, Animation2, final ): 133 134 controlPanel.Destroy() 135 FollowTheBoat.stop() 136 final.Show() 137 DoInOrder( Animation1, Animation2, 138 DoInOrder( camera.Place( len( final._name ) + 2, 139 InFrontOf, final ), camera.PointAt( final ) ) ) fig24_03.py

  21. Function AControlPanel creates a control panel with the specified caption Create radio buttons and associate them with callback animalSelect Create button with specified caption Function SetCommand associates each button with a callback Set initial selection to the first element (the fox) 140 141 # create the control panel and buttons 142controlPanel = AControlPanel ( Caption = "Game Control Panel" ) 143 animalListBox = \ 144 controlPanel.MakeOptionButtonSet( List = thisBank[ : ], 145 Command = animalSelect) 146 buttonToBoat = \ 147 controlPanel.MakeButton( Caption = "Get into the boat" ) 148 buttonFromBoat = \ 149 controlPanel.MakeButton( Caption = "Get out of the boat" ) 150 buttonMoveBoat = \ 151 controlPanel.MakeButton( Caption = "Go to the other shore" ) 152 153 # associate buttons with callbacks 154buttonToBoat.SetCommand( getIntoBoat ) 155 buttonFromBoat.SetCommand( getOutOfBoat ) 156 buttonMoveBoat.SetCommand( toOtherShore ) 157 158 # initial selection defaults to the first element (the fox) 159animalListbox._children[ 0 ].SetValue( 1 ) 160 selected = "Fox" fig24_03.py

  22. 24.5 Fox, Chicken and Seed Problem Fig. 24.4 Screenshot of Alice world. (Courtesy of Carnegie Mellon University.)

  23. 24.6 Introduction to pygame • pygame • Set of modules written by Pete Shinners • Designed to create multimedia programs and games • Use the Simple DirectMedia Layer (SDL), a cross-platform library that provides a uniform API to access multimedia hardware

  24. 24.7 Python CD Player • Creating a simple CD-ROM player using pygame’s cdrom module • Module cdrom contains class CD and methods to initialize a CD-ROM subsystem • Class CD represents the user’s CD-ROM drive and its methods allow users to access an audio compact disc (CD) in a computer’s CD-ROM drive

  25. Initialize pygame.cdrom Method get_count returns number of CD-ROM drives Create CD object Stop CD, uninitialize pygame.cdrom and destroy GUI Determine if CD object has been initialized Method quit uninitializes pygame.cdrom 1 # Fig. 24.5: fig24_05.py 2 # Simple CD player using Tkinter and pygame. 3 4 import sys 5 import string 6 import pygame, pygame.cdrom 7 from Tkinter import * 8 from tkMessageBox import * 9 import Pmw 10 11 class CDPlayer( Frame ): 12 """A GUI CDPlayer class using Tkinter and pygame""" 13 14 def __init__( self ): 15 """Initialize pygame.cdrom and get CDROM if one exists""" 16 17 pygame.cdrom.init() 18 19if pygame.cdrom.get_count() > 0: 20 self.CD = pygame.cdrom.CD( 0 ) 21 else: 22 sys.exit( "There are no available CDROM drives." ) 23 24 self.createGUI() 25 self.updateTime() 26 27def destroy( self ): 28 """Stop CD, uninitialize pygame.cdrom and destroy GUI""" 29 30if self.CD.get_init(): 31 self.CD.stop() 32 33 pygame.cdrom.quit() 34 Frame.destroy( self ) 35 fig24_05.py

  26. Display number of track playing Display current time of track playing Create play/pause button Create stop button 36 def createGUI( self ): 37 """Create CDPlayer widgets""" 38 39 Frame.__init__( self ) 40 self.pack( expand = YES, fill = BOTH ) 41 self.master.title( "CD Player" ) 42 43 # display current track playing 44 self.trackLabel = IntVar() 45 self.trackLabel.set( 1 ) 46 self.trackDisplay = Label( self, font = "Courier 14", 47 textvariable = self.trackLabel, bg = "black", 48 fg = "green" ) 49 self.trackDisplay.grid( sticky = W+E+N+S ) 50 51 # display current time of track playing 52 self.timeLabel = StringVar() 53 self.timeLabel.set( "00:00/00:00" ) 54 self.timeDisplay = Label( self, font = "Courier 14", 55 textvariable = self.timeLabel, bg = "black", 56 fg = "green" ) 57 self.timeDisplay.grid( row = 0, column = 1, columnspan = 3, 58 sticky = W+E+N+S ) 59 60 # play/pause CD 61 self.playLabel = StringVar() 62 self.playLabel.set( "Play" ) 63 self.play = Button( self, textvariable = self.playLabel, 64 command = self.playCD, width = 10 ) 65 self.play.grid( row = 1, column = 0, columnspan = 2, 66 sticky = W+E+N+S ) 67 68 # stop CD 69 self.stop = Button( self, text = "Stop", width = 10, 70 command = self.stopCD ) fig24_05.py

  27. Create button that allows user to skip to previous track Create button that allows user to skip to next track Create button that allows user to eject CD Play or pause the CD if disc is loaded If disc has been ejected, reinitialize drive Determine if CD-ROM drive is empty Obtain number of CD tracks 71 self.stop.grid( row = 1, column = 2, columnspan = 2, 72 sticky = W+E+N+S ) 73 74 # skip to previous track 75 self.previous = Button( self, text = "<<|", width = 5, 76 command = self.previousTrack ) 77 self.previous.grid( row = 2, column = 0, sticky = W+E+N+S ) 78 79 # skip to next track 80 self.next = Button( self, text = “|>>", width = 5, 81 command = self.nextTrack ) 82 self.next.grid( row = 2, column = 1, sticky = W+E+N+S ) 83 84 # eject CD 85 self.eject = Button( self, text = "Eject", width = 10, 86 command = self.ejectCD ) 87 self.eject.grid( row = 2, column = 2, columnspan = 2, 88 sticky = W+E+N+S ) 89 90def playCD( self ): 91 """Play/Pause CD if disc is loaded""" 92 93 # if disc has been ejected, reinitialize drive 94ifnot self.CD.get_init(): 95 self.CD.init() 96 self.currentTrack = 1 97 98 # if no disc in drive, uninitialize and return 99if self.CD.get_empty(): 100 self.CD.quit() 101 return 102 103 # if a disc is loaded, obtain disc information 104 else: 105 self.totalTracks = self.CD.get_numtracks() fig24_05.py

  28. Determine if CD is paused Determine if CD is playing Play track if CD is not playing and not paused Pause disc if CD is playing Resume play if CD is paused Stop CD if disc is loaded Play track if disc is loaded 106 107 # if CD is not playing, play CD 108ifnot self.CD.get_busy() andnot self.CD.get_paused(): 109 self.CD.play( self.currentTrack - 1 ) 110 self.playLabel.set( "| |" ) 111 112 # if CD is playing, pause disc 113 elifnot self.CD.get_paused(): 114 self.CD.pause() 115 self.playLabel.set( "Play" ) 116 117 # if CD is paused, resume play 118 else: 119 self.CD.resume() 120 self.playLabel.set( "| |" ) 121 122def stopCD( self ): 123 """Stop CD if disc is loaded""" 124 125 if self.CD.get_init(): 126 self.CD.stop() 127 self.playLabel.set( "Play" ) 128 129def playTrack( self, track ): 130 """Play track if disc is loaded""" 131 132 if self.CD.get_init(): 133 self.currentTrack = track 134 self.trackLabel.set( self.currentTrack ) 135 fig24_05.py

  29. self.currentTrack–1 refers to current track Play CD’s next track if disc is loaded Play CD’s previous track if disc is loaded Eject CD from drive Display tkMessageBox asking whether CD should be ejected CD must be initialized before ejection Eject CD Uninitialize pygame.cdrom.CD object Update time display is disc is loaded 136 # start beginning of track 137 if self.CD.get_busy(): 138 self.CD.play( self.currentTrack - 1 ) 139 elif self.CD.get_paused(): 140 self.CD.play( self.currentTrack - 1 ) 141 self.playCD() # re-pause CD 142 143def nextTrack( self ): 144 """Play next track on CD if disc is loaded""" 145 146 if self.CD.get_init() and \ 147 self.currentTrack < self.totalTracks: 148 self.playTrack( self.currentTrack + 1 ) 149 150def previousTrack( self ): 151 """Play previous track on CD if disc is loaded""" 152 153 if self.CD.get_init() and self.currentTrack > 1: 154 self.playTrack( self.currentTrack - 1 ) 155 156def ejectCD( self ): 157 """Eject CD from drive""" 158 159 response = askyesno( "Eject pushed", "Eject CD?" ) 160 161 if response: 162 self.CD.init() # CD must be initialized to eject 163 self.CD.eject() 164 self.CD.quit() 165 self.trackLabel.set( 1 ) 166 self.timeLabel.set( "00:00/00:00" ) 167 self.playLabel.set( "Play" ) 168 169def updateTime( self ): 170 """Update time display if disc is loaded""" fig24_05.py

  30. Obtain track length Play next track if end of current track reached Display time in mm:ss/mm:ss format Alternate pause symbol and time in display Method updateTime called every 1000ms (1 second) 171 172 if self.CD.get_init(): 173 seconds = int( self.CD.get_current()[ 1 ] ) 174 endSeconds = int( self.CD.get_track_length( 175 self.currentTrack - 1 ) ) 176 177 # if reached end of current track, play next track 178if seconds >= ( endSeconds - 1 ): 179 self.nextTrack() 180 else: 181 minutes = seconds / 60 182 endMinutes = endSeconds / 60 183 seconds = seconds - ( minutes * 60 ) 184 endSeconds = endSeconds - ( endMinutes * 60 ) 185 186 # display time in format mm:ss/mm:ss 187 trackTime = string.zfill( str( minutes ), 2 ) + \ 188 ":" + string.zfill( str( seconds ), 2 ) 189 endTime = string.zfill( str( endMinutes ), 2 ) + \ 190 ":" + string.zfill( str( endSeconds ), 2 ) 191 192 if self.CD.get_paused(): 193 194 # alternate pause symbol and time in display 195ifnot self.timeLabel.get() == " || ": 196 self.timeLabel.set( " || " ) 197 else: 198 self.timeLabel.set( trackTime + "/" + endTime ) 199 200 else: 201 self.timeLabel.set( trackTime + "/" + endTime ) 202 203 # call updateTime method again after 1000ms ( 1 second ) 204 self.after( 1000, self.updateTime ) 205 fig24_05.py

  31. 206 def main(): 207 CDPlayer().mainloop() 208 209 if __name__ == "__main__": 210 main() fig24_05.py

  32. 24.8 Python Movie Player • Create a simple movie player with pygame’s movie module • Movie object represents an open moving pictures experts group (MPEG) file • Class Movie provides methods to play, stop, pause and rewind movies

  33. Movie constructor takes the movie file name as an argument and creates a Movie object Method get_size returns the movie’s size as a tuple of (width, height) Specify the width and height of the display as arguments to set_mode Method set_mode returns Surface object, a blank canvas on which the movie is displayed Set title of display window with method set_caption Display the mouse pointer over the window Locate play button image Convert play button image’s pixel format to the display’s format Return a Rect object covering surface of the play button image Set play button position by modifying Rect object’s center attribute Place play button image onto Surface object using method blit Method flip updates entire display Set output surface (Surface object screen) for the movie’s output Return Movie object and Rect object representing play button image 1 # Fig. 24.6: fig24_06.py 2 # Playing MPEG movie. 3 4 import os 5 import sys 6 import pygame, pygame.movie, pygame.font 7 import pygame.mouse, pygame.image 8 from pygame.locals import * 9 10 def createGUI( file ): 11 12 # load movie 13 movie = pygame.movie.Movie( file ) 14 width, height = movie.get_size() 15 16 # initialize display window 17 screen = pygame.display.set_mode( ( width, height + 100 ) ) 18 pygame.display.set_caption( "Movie Player" ) 19 pygame.mouse.set_visible( 1 ) 20 21 # play button 22 playImageFile = os.path.join( "data", "play.png" ) 23 playImage = pygame.image.load( playImageFile ).convert() 24 playImageSize = playImage.get_rect() 25 playImageSize.center = width / 2, height + 50 26 27 # copy play button to screen 28 screen.blit( playImage, playImageSize ) 29 pygame.display.flip() 30 31 # set output surface for the movie's video 32 movie.set_display( screen ) 33 34 return movie, playImageSize fig24_06.py

  34. User specifies movie file as a command-line argument Method pygame.init initializes every pygame module Method createGUI loads the MPEG movie and produces the display window Waits for and returns next Event object in the queue User issues command to close window Evaluates to true if right mouse button has been pressed Returns position of mouse pointer If the user pressed the right mouse button Determine if position is within play button image’s bounding rectangle Play movie 35 36 def main(): 37 38 # check command line arguments 39if len( sys.argv ) != 2: 40 sys.exit( "Incorrect number of arguments." ) 41 else: 42 file = sys.argv[ 1 ] 43 44 # initialize pygame 45 pygame.init() 46 47 # initialize GUI 48 movie, playImageSize = createGUI( file ) 49 50 # wait until player wants to close program 51 while1: 52 event = pygame.event.wait() 53 54 # close window 55if event.type == QUITor \ 56 ( event.type == KEYDOWNand event.key == K_ESCAPE ): 57 break 59 69 # click play button and play movie 61 pressed = pygame.mouse.get_pressed()[ 0 ] 62 position = pygame.mouse.get_pos() 63 64 # button pressed 65if pressed: 66 68if playImageSize.collidepoint( position ): 68 movie.play() 69 79 if __name__ == "__main__": fig24_06.py

  35. 71 main() fig24_06.py

  36. 24.9 Pygame Space Cruiser • Most applications developed with pygame are games • Following example uses pygame modules to create a simple “Space Cruiser” • Player has 60 seconds to navigate the space ship through an asteroid field • When the ship collides with an asteroid, five seconds are deducted from the remaining time; when the ship picks up an energy pack, five seconds are added to the timer • Keyboard’s arrow keys control the ship

  37. 24.9 Pygame Space Cruiser • Note that while the space ship appears to move across the screen, only the image displayed on the screen changes • The position of each asteroid changes, simulating space ship movement • Each space ship image has a gray background, which must be made transparent, so that only the space ship is displayed on the star field

  38. 24.9 Pygame Space Cruiser • Game also introduces collision detection with bounding rectangles and dirty rectangle animation

  39. Object to place on the screen Initializes object image and calculates bounding rectangle by calling get_rect Insert object on the screen by calling method blit Remove object by covering the image with the background PlayerSprite has 4 different states – moving right, moving down, moving left and crashed Constructor stores images and sets initial Player state 1 # Fig. 24.7: fig24_07.py 2 # Space Cruiser game using pygame. 3 4 import os 5 import sys 6 import random 7 import pygame, pygame.image, pygame.font, pygame.mixer 8 from pygame.locals import * 9 10class Sprite: 11 """An object to place on the screen""" 12 13def __init__( self, image ): 14 """Initialize object image and calculate rectangle""" 15 16 self.image = image 17 self.rectangle = image.get_rect() 18 19def place( self, screen ): 20 """Place the object on the screen""" 21 22 return screen.blit( self.image, self.rectangle ) 23 24def remove( self, screen, background ): 25 """Place the background over the image to remove it""" 26 27 return screen.blit( background, self.rectangle, 28 self.rectangle ) 29 30class Player( Sprite ): 31 """A Player Sprite with 4 different states""" 32 33def __init__( self, images, crashImage, 34 centerX = 0, centerY = 0 ): 35"""Store all images and set the initial Player state""" fig24_07.py

  40. Start space ship facing down Load Player image and calculate its bounding rectangle Call base class Sprite’s constructor with image file’s name Change Player image to face on position to the left Change Player image to face one position to the left 36 37 self.movingImages = images 38 self.crashImage = crashImage 39 self.centerX = centerX 40 self.centerY = centerY 41 self.playerPosition = 1# start player facing down 42 self.speed = 0 43 self.loadImage() 44 45def loadImage( self ): 46 """Load Player image and calculate rectangle""" 47 48 if self.playerPosition == -1: # player has crashed 49 image = self.crashImage 50 else: 51 image = self.movingImages[ self.playerPosition ] 52 53 Sprite.__init__( self, image ) 54 self.rectangle.centerx = self.centerX 55 self.rectangle.centery = self.centerY 56 57def moveLeft( self ): 58 """Change Player image to face one position to the left""" 59 60 if self.playerPosition == -1: # player has crashed 61 self.speed = 1 62 self.playerPosition = 0# move left of obstacle 63 elif self.playerPosition > 0: 64 self.playerPosition -= 1 65 66 self.loadImage() 67 68def moveRight( self ): 69 """Change Player image to face one position to the right""" 70 fig24_07.py

  41. Decrease speed Increase speed Start space ship facing down if player has crashed Change image to crashed space ship on collision with asteroid Return smaller bounding box for collision tests Method inflate resizes Rect object 71 if self.playerPosition == -1: # player has crashed 72 self.speed = 1 73 self.playerPosition = 2# move right of obstacle 74 elif self.playerPosition < ( len( self.movingImages ) - 1 ): 75 self.playerPosition += 1 76 77 self.loadImage() 78 79def decreaseSpeed( self ): 80 81 if self.speed > 0: 82 self.speed -= 1 83 84def increaseSpeed( self ): 85 86 if self.speed < 10: 87 self.speed += 1 88 89 # player has crashed, start player facing down 90if self.playerPosition == -1: 91 self.playerPosition = 1 92 self.loadImage() 93 94def collision( self ): 95 """Change Player image to crashed player""" 96 97 self.speed = 0 98 self.playerPosition = -1 99 self.loadImage() 100 101def collisionBox( self ): 102 """Return smaller bounding box for collision tests""" 103 104return self.rectangle.inflate( -20, -20 ) 105 fig24_07.py

  42. Determine if player is moving by testing speed Increment distance moved Player moves twice as fast when facing straight down Moveable ObstacleSprite Constructor loads Obstacle image and initializes its bounding rectangle 106def isMoving( self ): 107 """Player is not moving if speed is 0""" 108 109 if self.speed == 0: 110 return 0 111 else: 112 return 1 113 114def distanceMoved( self ): 115 """Player moves twice as fast when facing straight down""" 116 117 xIncrement, yIncrement = 0, 0 118 119 if self.isMoving(): 120 121if self.playerPosition == 1: 122 xIncrement = 0 123 yIncrement = 2 * self.speed 124 else: 125 xIncrement = ( self.playerPosition - 1 ) * self.speed 126 yIncrement = self.speed 127 128 return xIncrement, yIncrement 129 130class Obstacle( Sprite ): 131 """A moveable Obstacle Sprite""" 132 133def __init__( self, image, centerX = 0, centerY = 0 ): 134 """Load Obstacle image and initialize rectangle""" 135 136 Sprite.__init__( self, image ) 137 fig24_07.py

  43. Move Obstacle location up by specified increments Returns smaller bounding box for collision tests Moveable ObjectiveSprite 138 # move Obstacle to specified location 139 self.positiveRectangle = self.rectangle 140 self.positiveRectangle.centerx = centerX 141 self.positiveRectangle.centery = centerY 142 143 # display Obstacle in moved position to buffer visible area 144 self.rectangle = self.positiveRectangle.move( -60, -60 ) 145 146def move( self, xIncrement, yIncrement ): 147 """Move Obstacle location up by specified increments""" 148 149 self.positiveRectangle.centerx -= xIncrement 150 self.positiveRectangle.centery -= yIncrement 151 152 # change position for next pass 153 if self.positiveRectangle.centery < 25: 154 self.positiveRectangle[ 0 ] += \ 155 random.randrange( -640, 640 ) 156 157 # keep rectangle values from overflowing 158 self.positiveRectangle[ 0 ] %= 760 159 self.positiveRectangle[ 1 ] %= 600 160 161 # display obstacle in moved position to buffer visible area 162 self.rectangle = self.positiveRectangle.move( -60, -60 ) 163 164def collisionBox( self ): 165 """Return smaller bounding box for collision tests""" 166 167 return self.rectangle.inflate( -20, -20 ) 168 169class Objective( Sprite ): 170 """A moveable Objective Sprite""" 171 fig24_07.py

  44. Load Objective image and initialize rectangle Move Objective to specified location Place message on screen Create Font object using default style and specifying size Method render places specified Font object on the screen Second argument of 1 enables antialiasing (edge smoothing) Third argument specifies text color Obtain Font object’s bounding rectangle Place Font object on screen at specified coordinates Replace old time on screen with updated time 172def __init__( self, image, centerX = 0, centerY = 0 ): 173 """Load Objective image and initialize rectangle""" 174 175 Sprite.__init__( self, image ) 176 177 # move Objective to specified location 178 self.rectangle.centerx = centerX 179 self.rectangle.centery = centerY 180 181 def move( self, xIncrement, yIncrement ): 182 """Move Objective location up by specified increments""" 183 184 self.rectangle.centerx -= xIncrement 185 self.rectangle.centery -= yIncrement 186 187 # place a message on screen 188def displayMessage( message, screen, background ): 189 font = pygame.font.Font( None, 48 ) 190 text = font.render( message, 1, ( 250, 250, 250 ) ) 191 textPosition = text.get_rect() 192 textPosition.centerx = background.get_rect().centerx 193 textPosition.centery = background.get_rect().centery 194 return screen.blit( text, textPosition ) 195 196 # remove old time and place updated time on screen 197def updateClock( time, screen, background, oldPosition ): 198 remove = screen.blit( background, oldPosition, oldPosition ) 199 font = pygame.font.Font( None, 48 ) 200 text = font.render( str( time ), 1, ( 250, 250, 250 ), 201 ( 0, 0, 0 ) ) 202 textPosition = text.get_rect() 203 post = screen.blit( text, textPosition ) 204 return remove, post 205 fig24_07.py

  45. Set game constants Initialize variables Find path to all sounds Find path to all images 206 def main(): 207 208 # constants 209 WAIT_TIME = 20# time to wait between frames 210 COURSE_DEPTH = 50 * 480# 50 screens long 211 NUMBER_ASTEROIDS = 20# controls number of asteroids 212 213 # variables 214 distanceTraveled = 0# vertical distance 215 nextTime = 0# time to generate next frame 216 courseOver = 0# the course has not been completed 217 allAsteroids = [] # randomly generated obstacles 218 dirtyRectangles = [] # screen positions that have changed 219 energyPack = None # current energy pack on screen 220 timeLeft = 60# time left to finish course 221 newClock = ( 0, 0, 0, 0 ) # the location of the clock 222 223 # find path to all sounds 224 collisionFile = os.path.join( "data", "collision.wav" ) 225 chimeFile = os.path.join( "data", "energy.wav" ) 226 startFile = os.path.join( "data", "toneup.wav" ) 227 applauseFile = os.path.join( "data", "applause.wav" ) 228 gameOverFile = os.path.join( "data", "tonedown.wav" ) 229 230 # find path to all images 231 shipFiles = [] 232 shipFiles.append( os.path.join( "data", "shipLeft.gif" ) ) 233 shipFiles.append( os.path.join( "data", "shipDown.gif" ) ) 234 shipFiles.append( os.path.join( "data", "shipRight.gif" ) ) 235 shipCrashFile = os.path.join( "data", "shipCrashed.gif" ) 236 asteroidFile = os.path.join( "data", "Asteroid.gif" ) 237 energyPackFile = os.path.join( "data", "Energy.gif" ) 238 fig24_07.py

  46. Obtain user preference about game size Set display to FULLSCREEN Set title of display Create Surface object Blit background onto screen and update entire display Update entire display Create Sound object Load ship images Get background color of ship image at (0,0) 239 # obtain user preference 240 fullScreen = int( raw_input( 241 "Fullscreen? ( 0 = no, 1 = yes ): " ) ) 242 243 # initialize pygame 244 pygame.init() 245 246 if fullScreen: 247 screen = pygame.display.set_mode( ( 640, 480 ), FULLSCREEN ) 248 else: 249 screen = pygame.display.set_mode( ( 640, 480 ) ) 250 251 pygame.display.set_caption( "Space Cruiser!" ) 252 pygame.mouse.set_visible( 0 ) # make mouse invisible 253 254 # create background and fill with black 255 background = pygame.Surface( screen.get_size() ).convert() 256 257 # blit background onto screen and update entire display 258 screen.blit( background, ( 0, 0 ) ) 259 pygame.display.update() 260 261 collisionSound = pygame.mixer.Sound( collisionFile ) 262 chimeSound = pygame.mixer.Sound( chimeFile ) 263 startSound = pygame.mixer.Sound( startFile ) 264 applauseSound = pygame.mixer.Sound( applauseFile ) 265 gameOverSound = pygame.mixer.Sound( gameOverFile ) 266 267 # load images, convert pixel format and make white transparent 268 loadedImages = [] 269 270 for file in shipFiles: 271 surface = pygame.image.load( file ).convert() 272 surface.set_colorkey( surface.get_at( ( 0, 0 ) ) ) 273 loadedImages.append( surface ) fig24_07.py

  47. Use set_colorkey to make image background color appear transparent Initialize theShip as a Player object Place asteroid as an Obstacle object in randomly selected position Place USEREVENT on event queue every 1000ms Pause if moving too fast for selected frame rate 274 275 # load crash image 276 shipCrashImage = pygame.image.load( shipCrashFile ).convert() 277 shipCrashImage.set_colorkey( shipCrashImage.get_at( ( 0, 0 ) ) ) 278 279 # initialize theShip 280 centerX = screen.get_width() / 2 281 theShip = Player( loadedImages, shipCrashImage, centerX, 25 ) 282 283 # load asteroid image 284 asteroidImage = pygame.image.load( asteroidFile ).convert() 285 asteroidImage.set_colorkey( asteroidImage.get_at( ( 0, 0 ) ) ) 286 287 # place an asteroid in a randomly generated spot 288 for i in range( NUMBER_ASTEROIDS ): 289 allAsteroids.append( Obstacle( asteroidImage, 290 random.randrange( 0, 760 ), random.randrange( 0, 600 ) ) ) 291 292 # load energyPack image 293 energyPackImage = pygame.image.load( energyPackFile ).convert() 294 energyPackImage.set_colorkey( surface.get_at( ( 0, 0 ) ) ) 295 296 startSound.play() 297 pygame.time.set_timer( USEREVENT, 1000 ) 298 299 whilenot courseOver: 300 301 # wait if moving too fast for selected frame rate 302 currentTime = pygame.time.get_ticks() 303 304 if currentTime < nextTime: 305 pygame.time.delay( nextTime - currentTime ) 306 fig24_07.py

  48. Removing each item from the screen returns Rect representing changed area Get next event from event queue Terminate program if player has quit or pressed escape key Slow ship if up arrow key pressed Increase ship’s speed if down arrow key pressed Move ship right if right arrow key pressed 307 nextTime = currentTime + WAIT_TIME 308 309 # remove all objects from the screen 310 dirtyRectangles.append( theShip.remove( screen, 311 background ) ) 312 313 for asteroid in allAsteroids: 314 dirtyRectangles.append( asteroid.remove( screen, 315 background ) ) 316 317 if energyPack isnot None: 318 dirtyRectangles.append( energyPack.remove( screen, 319 background ) ) 320 321 # get next event from event queue 322 event = pygame.event.poll() 323 324 # if player has quit program or pressed escape key 325if event.type == QUITor \ 326 ( event.type == KEYDOWNand event.key == K_ESCAPE ): 327 sys.exit() 328 329 # if up arrow key was pressed, slow ship 330elif event.type == KEYDOWNand event.key == K_UP: 331 theShip.decreaseSpeed() 332 333 # if down arrow key was pressed, speed up ship 334elif event.type == KEYDOWNand event.key == K_DOWN: 335 theShip.increaseSpeed() 336 337 # if right arrow key was pressed, move ship right 338elif event.type == KEYDOWNand event.key == K_RIGHT: 339 theShip.moveRight() 340 fig24_07.py

  49. Move ship left if left arrow key pressed Decrement timer after one second has passed Randomly create new energy pack Update asteroid and energy pack positions Uses smaller bounding boxes to test for collisions to enhance playability 341 # if left arrow key was pressed, move ship left 342elif event.type == KEYDOWNand event.key == K_LEFT: 343 theShip.moveLeft() 344 345 # one second has passed 346elif event.type == USEREVENT: 347 timeLeft -= 1 348 349 # 1 in 100 odds of creating a new energyPack 350if energyPack is None andnot random.randrange( 100 ): 351 energyPack = Objective( energyPackImage, 352 random.randrange( 0, 640 ), 480 ) 353 354 # update obstacle and energyPack positions if ship is moving 355if theShip.isMoving(): 356 xIncrement, yIncrement = theShip.distanceMoved() 357 358 for asteroid in allAsteroids: 359 asteroid.move( xIncrement, yIncrement ) 360 361 if energyPack isnot None: 362 energyPack.move( xIncrement, yIncrement ) 363 364 if energyPack.rectangle.bottom < 0: 365 energyPack = None 366 367 distanceTraveled += yIncrement 368 369 # check for collisions with smaller bounding boxes 370 # for better playability 371 asteroidBoxes = [] 372 373 for asteroid in allAsteroids: 374 asteroidBoxes.append( asteroid.collisionBox() ) 375 fig24_07.py

  50. Method collideList returns first asteroid that intersects with ship Check if player has picked up energy pack Place all objects on screen and add their rectangles to dirtyRectangles Update timer 376 # retrieve list of all obstacles colliding with player 377 collision = theShip.collisionBox().collidelist( 378 asteroidBoxes ) 379 380 # move asteroid one screen down 381 if collision != -1: 382 collisionSound.play() 383 allAsteroids[ collision ].move( 0, -540 ) 384 theShip.collision() 385 timeLeft -= 5 386 387 # check if player has gotten energyPack 388 if energyPack isnot None: 389 390if theShip.collisionBox().colliderect( 391 energyPack.rectangle ): 392 chimeSound.play() 393 energyPack = None 394 timeLeft += 5 395 396 # place all objects on screen 397 dirtyRectangles.append( theShip.place( screen ) ) 398 399 for asteroid in allAsteroids: 400 dirtyRectangles.append( asteroid.place( screen ) ) 401 402 if energyPack isnotNone: 403 dirtyRectangles.append( energyPack.place( screen ) ) 404 405 # update time 406 oldClock, newClock = updateClock( timeLeft, screen, 407 background, newClock ) 408 dirtyRectangles.append( oldClock ) 409 dirtyRectangles.append( newClock ) 410 fig24_07.py

More Related