How To Animate A Shape On Pygame
18
ANIMATING GRAPHICS
At present that yous've learned some pygame skills, we'll write a program to animate boxes that bounce around a window. The boxes are dissimilar colors and sizes and move only in diagonal directions. To animate the boxes, nosotros'll move them a few pixels on each iteration through the game loop. This will make it look like the boxes are moving around the screen.
Sample Run of the Animation Program
When yous run the Blitheness plan, it will look something like Effigy 18-1. The blocks will exist billowy off the edges of the window.
Figure 18-1: A screenshot of the Blitheness programme
Source Code for the Animation Program
Enter the post-obit plan into the file editor and save it as blitheness.py. If you get errors after typing in this code, compare the code you lot typed to the book's code with the online unequal tool at https://world wide web.nostarch.com/inventwithpython#diff.
animation.py
1. import pygame, sys, fourth dimension
two. from pygame.locals import *
three.
four. # Ready up pygame.
v. pygame.init()
6.
7. # Set the window.
8. WINDOWWIDTH = 400
9. WINDOWHEIGHT = 400
10. windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT),
0, 32)
11. pygame.display.set_caption('Animation')
12.
xiii. # Ready direction variables.
14. DOWNLEFT = 'downleft'
xv. DOWNRIGHT = 'downright'
sixteen. UPLEFT = 'upleft'
17. UPRIGHT = 'upright'
xviii.
19. MOVESPEED = four
20.
21. # Fix the colors.
22. WHITE = (255, 255, 255)
23. Ruby-red = (255, 0, 0)
24. Greenish = (0, 255, 0)
25. BLUE = (0, 0, 255)
26.
27. # Set up the box data structure.
28. b1 = {'rect':pygame.Rect(300, 80, 50, 100), 'colour':Reddish, 'dir':UPRIGHT}
29. b2 = {'rect':pygame.Rect(200, 200, 20, 20), 'color':GREEN, 'dir':UPLEFT}
30. b3 = {'rect':pygame.Rect(100, 150, 60, 60), 'color':BLUE, 'dir':DOWNLEFT}
31. boxes = [b1, b2, b3]
32.
33. # Run the game loop.
34. while Truthful:
35. # Bank check for the QUIT event.
36. for upshot in pygame.issue.get():
37. if consequence.type == QUIT:
38. pygame.quit()
39. sys.go out()
40.
41. # Draw the white background onto the surface.
42. windowSurface.fill up(WHITE)
43.
44. for b in boxes:
45. # Motion the box data structure.
46. if b['dir'] == DOWNLEFT:
47. b['rect'].left -= MOVESPEED
48. b['rect'].superlative += MOVESPEED
49. if b['dir'] == DOWNRIGHT:
50. b['rect'].left += MOVESPEED
51. b['rect'].meridian += MOVESPEED
52. if b['dir'] == UPLEFT:
53. b['rect'].left -= MOVESPEED
54. b['rect'].top -= MOVESPEED
55. if b['dir'] == UPRIGHT:
56. b['rect'].left += MOVESPEED
57. b['rect'].meridian -= MOVESPEED
58.
59. # Bank check whether the box has moved out of the window.
60. if b['rect'].peak < 0:
61. # The box has moved past the tiptop.
62. if b['dir'] == UPLEFT:
63. b['dir'] = DOWNLEFT
64. if b['dir'] == UPRIGHT:
65. b['dir'] = DOWNRIGHT
66. if b['rect'].lesser > WINDOWHEIGHT:
67. # The box has moved by the bottom.
68. if b['dir'] == DOWNLEFT:
69. b['dir'] = UPLEFT
seventy. if b['dir'] == DOWNRIGHT:
71. b['dir'] = UPRIGHT
72. if b['rect'].left < 0:
73. # The box has moved past the left side.
74. if b['dir'] == DOWNLEFT:
75. b['dir'] = DOWNRIGHT
76. if b['dir'] == UPLEFT:
77. b['dir'] = UPRIGHT
78. if b['rect'].correct > WINDOWWIDTH:
79. # The box has moved past the right side.
lxxx. if b['dir'] == DOWNRIGHT:
81. b['dir'] = DOWNLEFT
82. if b['dir'] == UPRIGHT:
83. b['dir'] = UPLEFT
84.
85. # Draw the box onto the surface.
86. pygame.depict.rect(windowSurface, b['colour'], b['rect'])
87.
88. # Draw the window onto the screen.
89. pygame.display.update()
90. fourth dimension.sleep(0.02)
Moving and Bouncing the Boxes
In this programme, we'll take three boxes of dissimilar colors moving around and bouncing off the walls of a window. In the adjacent chapters, we'll apply this programme every bit a base of operations to make a game in which we control ane of the boxes. To do this, first we need to consider how nosotros desire the boxes to move.
Each box will move in i of four diagonal directions. When a box hits the side of the window, it should bounce off and move in a new diagonal direction. The boxes volition bounce as shown in Effigy xviii-2.
Figure xviii-2: How boxes will bounce
The new direction that a box moves after it bounces depends on two things: which direction it was moving earlier the bounce and which wall information technology bounced off. At that place are 8 possible means a box can bounciness: ii different ways for each of the 4 walls. For example, if a box is moving downward and right then bounces off the bottom edge of the window, we desire the box's new management to be upwards and right.
We can employ a Rect object to represent the position and size of the box, a tuple of three integers to represent the color of the box, and an integer to represent which of the four diagonal directions the box is currently moving in.
The game loop volition adjust the 10- and y-position of the box in the Rect object and draw all the boxes on the screen at their current position on each iteration. Equally the program execution iterates over the loop, the boxes volition gradually movement across the screen and so that it looks like they're smoothly moving and billowy around.
Setting Upwardly the Constant Variables
Lines 1 to v are just setting up our modules and initializing pygame as nosotros did in Chapter 17:
1. import pygame, sys, fourth dimension
2. from pygame.locals import *
3.
4. # Ready pygame.
v. pygame.init()
half dozen.
7. # Set the window.
viii. WINDOWWIDTH = 400
9. WINDOWHEIGHT = 400
10. windowSurface = pygame.brandish.set_mode((WINDOWWIDTH, WINDOWHEIGHT),
0, 32)
eleven. pygame.display.set_caption('Animation')
At lines 8 and 9, we define the two constants for the window width and height, and so in line x, we use those constants to set up windowSurface, which will represent our pygame window. Line xi uses set_caption() to prepare the window's caption to 'Animation'.
In this program, you lot'll come across that the size of the window'southward width and elevation is used for more than just the call to set_mode(). Nosotros'll use constant variables so that if you ever want to modify the size of the window, you lot only take to change lines viii and 9. Since the window width and peak never change during the program's execution, constant variables are a good idea.
Constant Variables for Direction
We'll use constant variables for each of the iv directions the boxes can move in:
thirteen. # Set up direction variables.
fourteen. DOWNLEFT = 'downleft'
15. DOWNRIGHT = 'downright'
16. UPLEFT = 'upleft'
17. UPRIGHT = 'upright'
Yous could have used any value you wanted for these directions instead of using a constant variable. For example, you could use the string 'downleft' directly to represent the down and left diagonal direction and retype the string every time you demand to specify that direction. However, if you e'er mistyped the 'downleft' string, you lot'd stop up with a problems that would crusade your plan to behave strangely, even though the program wouldn't crash.
If you use abiding variables instead and accidentally mistype the variable name, Python will notice that in that location'due south no variable with that name and crash the program with an mistake. This would still be a pretty bad bug, only at to the lowest degree you would know near it immediately and could fix information technology.
We also create a abiding variable to determine how fast the boxes should move:
xix. MOVESPEED = 4
The value iv in the constant variable MOVESPEED tells the programme how many pixels each box should move on each iteration through the game loop.
Constant Variables for Colour
Lines 22 to 25 set up constant variables for the colors. Remember, pygame uses a tuple of three integer values for the amounts of red, greenish, and bluish, called an RGB value. The integers range from 0 to 255.
21. # Ready the colors.
22. WHITE = (255, 255, 255)
23. Red = (255, 0, 0)
24. Greenish = (0, 255, 0)
25. BLUE = (0, 0, 255)
Constant variables are used for readability, just every bit in the pygame How-do-you-do Globe programme.
Setting Up the Box Data Structures
Next we'll define the boxes. To make things elementary, nosotros'll ready up a dictionary as a information structure (see "The Lexicon Data Type" on page 112) to represent each moving box. The lexicon volition accept the keys 'rect' (with a Rect object for a value), 'color' (with a tuple of three integers for a value), and 'dir' (with ane of the management constant variables for a value). We'll set up just three boxes for now, but y'all can gear up up more boxes past defining more data structures. The animation lawmaking we'll use subsequently tin can exist used to animate every bit many boxes as you define when you set your data structures.
The variable b1 volition store one of these box information structures:
27. # Set up upward the box data structure.
28. b1 = {'rect':pygame.Rect(300, eighty, 50, 100), 'color':Red, 'dir':UPRIGHT}
This box's superlative-left corner is located at an ten-coordinate of 300 and a y-coordinate of 80. Information technology has a width of 50 pixels and a height of 100 pixels. Its color is RED, and its initial direction is UPRIGHT.
Lines 29 and 30 create two more like data structures for boxes that are different sizes, positions, colors, and directions:
29. b2 = {'rect':pygame.Rect(200, 200, 20, xx), 'color':Dark-green, 'dir':UPLEFT}
xxx. b3 = {'rect':pygame.Rect(100, 150, lx, 60), 'color':Blue, 'dir':DOWNLEFT}
31. boxes = [b1, b2, b3]
If you needed to retrieve a box or value from the list, yous could do then using indexes and keys. Entering boxes[0] would access the dictionary information structure in b1. If we entered boxes[0]['color'], that would access the 'color' key in b1, and so the expression boxes[0]['color'] would evaluate to (255, 0, 0). You can refer to any of the values in any of the box data structures by starting with boxes. The three dictionaries, b1, b2, and b3, are then stored in a list in the boxes variable.
The Game Loop
The game loop handles animative the moving boxes. Animations piece of work by cartoon a serial of pictures with slight differences that are shown ane correct after some other. In our animation, the pictures will be of the moving boxes and the slight differences will be in each box's position. Each box will move by iv pixels in each motion picture. The pictures are shown and then fast that the boxes volition await similar they are moving smoothly beyond the screen. If a box hits the side of the window, and then the game loop will make the box bounce by changing its direction.
At present that we know a little flake most how the game loop will work, let's code it!
Treatment When the Player Quits
When the player quits by closing the window, nosotros demand to stop the program in the same mode we did the pygame How-do-you-do World program. We demand to do this in the game loop and then that our programme is constantly checking whether there has been a QUIT event. Line 34 starts the loop, and lines 36 to 39 handle quitting:
33. # Run the game loop.
34. while True:
35. # Check for the QUIT issue.
36. for event in pygame.event.get():
37. if result.type == QUIT:
38. pygame.quit()
39. sys.exit()
Later on that, we desire to make sure that windowSurface is set to exist drawn on. Later, nosotros'll depict each box on windowSurface with the rect() method. On each iteration through the game loop, the lawmaking redraws the unabridged window with new boxes that are located a few pixels over each fourth dimension. When nosotros practise that, nosotros're not redrawing the whole Surface object; instead, we're only adding a cartoon of the Rect object to windowSurface. Merely when the game loop iterates to describe all the Rect objects again, it redraws every Rect and doesn't erase the sometime Rect drawing. If nosotros just let the game loop continue cartoon Rect objects on the screen, we'll end up with a trail of Rect objects instead of a smooth blitheness. To avert that, we need to clear the window for every iteration of the game loop.
In society to practice that, line 42 fills the entire Surface with white and so that annihilation previously drawn on it is erased:
41. # Draw the white background onto the surface.
42. windowSurface.make full(WHITE)
Without calling windowSurface.fill(WHITE) to white out the unabridged window before cartoon the rectangles in their new position, you would take a trail of Rect objects. If you want to try information technology out and come across what happens, yous can comment out line 42 by putting a # at the get-go of the line.
One time windowSurface is filled, nosotros can start drawing all of our Rect objects.
Moving Each Box
In order to update the position of each box, we need to iterate over the boxes list inside the game loop:
44. for b in boxes:
Inside the for loop, you lot'll refer to the electric current box equally b to brand the code easier to type. We need to change each box depending on the management it is already moving, then we'll use if statements to figure out the box'south management by checking the dir key within the box data structure. And so we'll change the box'south position depending on the direction the box is moving.
45. # Move the box data structure.
46. if b['dir'] == DOWNLEFT:
47. b['rect'].left -= MOVESPEED
48. b['rect'].top += MOVESPEED
49. if b['dir'] == DOWNRIGHT:
50. b['rect'].left += MOVESPEED
51. b['rect'].top += MOVESPEED
52. if b['dir'] == UPLEFT:
53. b['rect'].left -= MOVESPEED
54. b['rect'].top -= MOVESPEED
55. if b['dir'] == UPRIGHT:
56. b['rect'].left += MOVESPEED
57. b['rect'].summit -= MOVESPEED
The new value to set up the left and top attributes of each box to depends on the box's direction. If the direction is either DOWNLEFT or DOWNRIGHT, y'all desire to increase the top attribute. If the direction is UPLEFT or UPRIGHT, you want to decrease the top attribute.
If the box's direction is DOWNRIGHT or UPRIGHT, you want to increment the left attribute. If the management is DOWNLEFT or UPLEFT, you desire to decrease the left attribute.
The value of these attributes will increase or decrease by the amount of the integer stored in MOVESPEED, which stores how many pixels the boxes motility on each iteration through the game loop. We set up MOVESPEED on line 19.
For example, if b['dir'] is ready to 'downleft', b['rect'].left to forty, and b['rect'].peak to 100, then the status on line 46 will be True. If MOVESPEED is set to 4, and so lines 47 and 48 will modify the Rect object so that b['rect'].left is 36 and b['rect'].meridian is 104. Irresolute the Rect value then causes the drawing code on line 86 to draw the rectangle slightly down and to the left of its previous position.
Bouncing a Box
After lines 44 to 57 have moved the box, nosotros need to cheque whether the box has gone past the edge of the window. If it has, y'all want to bounce the box. In the lawmaking, this means the for loop volition set a new value for the box'due south 'dir' key. The box will move in the new direction on the next iteration of the game loop. This makes it look like the box has bounced off the side of the window.
In the if statement on line threescore, we determine that the box has moved past the top edge of the window if the top attribute of the box's Rect object is less than 0:
59. # Check whether the box has moved out of the window.
60. if b['rect'].summit < 0:
61. # The box has moved past the acme.
62. if b['dir'] == UPLEFT:
63. b['dir'] = DOWNLEFT
64. if b['dir'] == UPRIGHT:
65. b['dir'] = DOWNRIGHT
In that case, the direction will be inverse based on which management the box was moving. If the box was moving UPLEFT, and then it volition at present move DOWNLEFT; if it was moving UPRIGHT, it will now move DOWNRIGHT.
Lines 66 to 71 handle the situation in which the box has moved by the bottom edge of the window:
66. if b['rect'].bottom > WINDOWHEIGHT:
67. # The box has moved by the bottom.
68. if b['dir'] == DOWNLEFT:
69. b['dir'] = UPLEFT
70. if b['dir'] == DOWNRIGHT:
71. b['dir'] = UPRIGHT
These lines check whether the bottom attribute (not the top attribute) is greater than the value in WINDOWHEIGHT. Recollect that the y-coordinates commencement at 0 at the tiptop of the window and increment to WINDOWHEIGHT at the lesser.
Lines 72 to 83 handle the behavior of the boxes when they bounce off the sides:
72. if b['rect'].left < 0:
73. # The box has moved past the left side.
74. if b['dir'] == DOWNLEFT:
75. b['dir'] = DOWNRIGHT
76. if b['dir'] == UPLEFT:
77. b['dir'] = UPRIGHT
78. if b['rect'].correct > WINDOWWIDTH:
79. # The box has moved by the correct side.
80. if b['dir'] == DOWNRIGHT:
81. b['dir'] = DOWNLEFT
82. if b['dir'] == UPRIGHT:
83. b['dir'] = UPLEFT
Lines 78 to 83 are like to lines 72 to 77 but check whether the right side of the box has moved past the window's correct edge. Remember, the x-coordinates start at 0 on the window'due south left edge and increase to WINDOWWIDTH on the window's correct edge.
Drawing the Boxes on the Window in Their New Positions
Every time the boxes move, we need to depict them in their new positions on windowSurface past calling the pygame.draw.rect() function:
85. # Draw the box onto the surface.
86. pygame.draw.rect(windowSurface, b['colour'], b['rect'])
Yous demand to pass windowSurface to the function considering information technology is the Surface object to depict the rectangle on. Pass b['color'] to the function because it is the rectangle'southward colour. Finally, pass b['rect'] because it is the Rect object with the position and size of the rectangle to draw.
Line 86 is the last line of the for loop.
Drawing the Window on the Screen
Afterwards the for loop, each box in the boxes list volition be drawn, and so yous need to call pygame.display.update() to draw windowSurface on the screen:
88. # Draw the window onto the screen.
89. pygame.display.update()
90. time.slumber(0.02)
The computer can move, bounce, and draw the boxes and so fast that if the program ran at full speed, all the boxes would look like a blur. In guild to make the program run slowly enough that nosotros can see the boxes, we need to add together time.sleep(0.02). Yous can endeavour commenting out the time.sleep(0.02) line and running the program to run into what it looks similar. The call to time.sleep() will pause the programme for 0.02 seconds, or 20 milliseconds, between each motility of the boxes.
Subsequently this line, execution returns to the starting time of the game loop and begins the process all over once more. This mode, the boxes are constantly moving a little, bouncing off the walls, and being drawn on the screen in their new positions.
Summary
This chapter has presented a whole new style of creating estimator programs. The previous chapters' programs would stop and wait for the thespian to enter text. Even so, in our Animation plan, the program constantly updates the data structures without waiting for input from the player.
Remember that we had data structures that would represent the country of the lath in our Hangman and Tic-Tac-Toe games. These data structures were passed to a drawBoard() function to be displayed on the screen. Our Animation program is similar. The boxes variable holds a list of data structures representing boxes to be drawn to the screen, and these are fatigued inside the game loop.
But without calls to input(), how practise we get input from the histrion? In Affiliate xix, we'll cover how programs know when the role player presses keys on the keyboard. Nosotros'll likewise learn almost a new concept called collision detection.
Source: https://inventwithpython.com/invent4thed/chapter18.html
Posted by: richmondsheming.blogspot.com
0 Response to "How To Animate A Shape On Pygame"
Post a Comment