Sprite Game: Move a Sprite and Bounce From Screen Boundary
The previous program “sprite_Space_Shuttle_Display.py” showed you how to display a sprite.
Let’s now write a sprite game program that makes the sprite move by itself. The program makes the sprite bounce off the display screen boundaries when it reaches the screen boundaries. After the bounce, the image continues to move in the opposite direction.
In the program below, we use the image of a color bird as a sprite.
PROGRAM EXAMPLE: Move a Sprite and Bounce from the Screen Boundary
Program Folder: C:\Users\YourUserName\Python_scripts\sprite_display_move_bounce.py
Image Name: C:\Users\YourUserName\Python_scripts\sprite_images\colorBird
1 ################ PROGRAM TO DISPLAY AND MOVE A SPRITE ################
2 # Program Name: sprite_display_move_bounce.py
3 # Image Name: colorbird.png
4 import pygame # Import Pygame and os modules.
5 from pygame.locals import *
6 import os
7 # os Module provides a portable way of using operating system dependent functionality.
8
9 ################ VARIABLES ################
10 WIDTH = 480 # Width of game window (called 'screen')
11 HEIGHT = 320 # Height of the game window.
12 FPS = 60
13 # Set number of times per second the MAIN LOOP repeats.
14
15 # Define colors
16 WHITE = (255, 255, 255)
17 BLACK = (0, 0, 0)
18 RED = (255, 0, 0)
19 GREEN = (0, 255, 0)
20 BLUE = (0, 0, 255)
21
22 ################ SETUP ################
23 # initialize pygame and create game window and name it "screen".
24 pygame.init() # Start pygame and initialize it.
25 screen = pygame.display.set_mode((WIDTH, HEIGHT))
26 # "screen" is the game window of size defined in VARIABLES section.
27 pygame.display.set_caption("Bird Sprite Boundary Bounce") # Step 6a)
28 # Title that appears at the top of the game window.
29 clock = pygame.time.Clock()
30 # Call "Clock" method to create new ‘clock’ object.
31 # The clock object is the MAIN LOOP's clock.
32 # pygame.time.clock()is used in association with clock.tick() in step 15).
33
34 ################ OBJECTS ################
35 ################ class MySprite(pygame.sprite.Sprite): ################
36 class MySprite(pygame.sprite.Sprite):
37 def __init__(self, step):
38 # "step" argument specifies how many pixels to move in each frame.
39 pygame.sprite.Sprite.__init__(self)
40 # set up asset folders
41 sprite_program_folder = os.path.dirname(__file__)
42 sprite_img_folder = os.path.join(sprite_program_folder, 'sprite_images')
43 bird_img1 = pygame.image.load(os.path.join(sprite_img_folder, 'colorBird.png')) # Step 8b)
44 bird_img = bird_img1.convert()
45 self.image = bird_img
46 self.image.set_colorkey(BLACK)
47 self.rect = self.image.get_rect()
48 self.step = [step, step]
49
50 def update(self):
51 self.rect = self.rect.move(self.step)
52 #
53 if self.rect.right > WIDTH or self.rect.left < 0:
54 self.step[0] = -self.step[0]
55
56 if self.rect.bottom > HEIGHT or self.rect.top < 0:
57 self.step[1] = -self.step[1]
58
59 step = 2 # step = 2 means birdSprite moves 2 pixels each frame.
60
61 # Create a Group called all_sprites
62 all_sprites = pygame.sprite.Group()
63
64 # Create (spawn) an instance of "MySprite" clsss.
65 # and name this instance "birdSprite".
66 birdSprite = MySprite(step)
67 # Add this instance of sprite to the "all_sprites" group.
68 all_sprites.add(birdSprite)
69
70 ################ MAIN LOOP ################
71 running = True
72 while running:
73 # This section of code checks the events queue for events initiated by the user.
74 for event in pygame.event.get():
75 # Check if the user clicked the "X" on the window to exit the program.
76 # if "X" is clicked, set "running" = False and end the MAIN LOOP.
77 if event.type == pygame.QUIT:
78 running = False
79 # Monitor events queue to check if the user presses the "q" key on the keyboard.
80 # If "q" key is pressed, set "running" to False and end the MAIN LOOP.
81 elif event.type == pygame.KEYDOWN:
82 if event.key == ord('q'):
83 running = False
84
85 # Call procedure update() to update the screen.
86 all_sprites.update()
87
88 # Draw and render
89 screen.fill(WHITE)
90 all_sprites.draw(screen)
91
92 # After drawing the screen Surface, call the pygame.display.flip() method.
93 # flip() method makes everything we have drawn on the screen Surface become visible.
94 pygame.display.flip()
95
96 clock.tick(FPS)
97 # tick() method runs the loop at "step" defined in step 3) by statement FPS = 30.
98
99 pygame.quit()
100 # When the MAIN LOOP ends, pygame.quit() statement closes the window.
Detailed Line-by-line Explanation of the Sprite Game Program to Move a Sprite and Bounce of the Screen Boundary:
Line number explanations of this program are the same as the program “Sprite_Space_Shuttle_Display.py”, except for the following lines of code.
Lines 37 – 48:
37 def __init__(self, step):
39 pygame.sprite.Sprite.__init__(self)
41 sprite_program_folder = os.path.dirname(__file__)
42 sprite_img_folder = os.path.join(sprite_program_folder, 'sprite_images')
43 bird_img1 = pygame.image.load(os.path.join(sprite_img_folder, 'colorBird.png'))
44 bird_img = bird_img1.convert() # Step 8c)
45 self.image = bird_img
46 self.image.set_colorkey(BLACK) # Step 8d)
47 self.rect = self.image.get_rect() # Step 8e)
48 self.step = [step, step]
Line 37:
def __init__(self, step):
In this line, we define a new parameter named “step”. This variable defines how many pixels the sprite moves in each frame (each loop of the Event Loop). The parameter “step” is initialized to “2” in line 59 so that the sprite will move 2 pixels in each frame.
Lines 38 through 47 are similar to the lines in program “Sprite_Space_Shuttle_Display.py”.
Line 48: self.step = [step, step]
The first argument within the square brackets in the statement self.step = [step, step]
is the number of pixels the sprite moves in the x-direction in each frame.
The second argument within the square bracket is the number of pixels the sprite moves in the y-direction in each frame (that is, each iteration of the Event Loop).
In this example, the program moves the sprite by the same amount in the x-direction and y-direction in each frame as per the argument “step” defined in code line 59. All other lines of code are the same as inthe program “Sprite_Space_Shuttle_Display.py”.
Lines 50 – 57:
50 def update(self):
51 self.rect = self.rect.move(self.step) # Step 9)
53 if self.rect.right > WIDTH or self.rect.left < 0:
54 self.step[0] = -self.step[0] # Step 9a)
55
56 if self.rect.bottom > HEIGHT or self.rect.top < 0:
57 self.step[1] = -self.step[1]
Define the Function update()
Lines 50 – 57 define a procedure named update(self)
. This procedure is called by the Event Loop in each repeat of the loop to update the position of the sprite.
This procedure uses pygame’s rect.move
(x,y) method. This method returns a new rectangle moved by a displacement (x,y) in each frame of the Event Loop. For example, if (x,y) = (2,3), the sprite will move by 2 pixels in the x-direction and 3 pixels in the y-direction in each successive frame.
Line 50 – 51:
50 def update(self):
51 self.rect = self.rect.move(self.step)
This code defines the procedure update().
Check for LEFT and RIGHT Boundaries
Line 53 – 54:
53 if self.rect.right > WIDTH or self.rect.left < 0:
54 self.step[0] = -self.step[0]
The code in lines 53 – 54 tests if the sprite has reached the left or right boundaries of the screen using the logical OR of the following two conditions:
If the left edge of the rectangle containing the sprite has reached the left boundary of the screen (meaning, x-coordinate of the left edge of the sprite < 0),
OR
The right edge of the rectangle containing the sprite has reached the right boundary of the screen (meaning, x-coordinate of the right edge of the sprite > WIDTH).
If either of these two tests is True, this code reverses the direction of movement of the sprite by changing the polarity of the argument “step”. This means that if “step” was the number 2 when the sprite reached the boundaries of the screen, these lines of code will set “step” = -2.
Note the minus sign on the right side of the equal “=” sign in the line 54 statement. This will make the sprite bounce off the edge of the screen boundary and will begin to move in the opposite direction in the next frame.
Note “0” in step[0]
in in line 54 refers to x-direction.
Check for TOP and BOTTOM Boundaries
Line 56 – 57:
56 if self.rect.bottom > HEIGHT or self.rect.top < 0:
57 self.step[1] = -self.step[1]
This code does the same logic as code in lines 53 – 54, except it does it when the sprite reaches the top OR the bottom boundary of the screen (y-direction). Note “1” in step[1]
in line 57 refers to the y-direction.
For details on the Rect object’s many attributes (rect.left, rect.right, rect.top, and rect.bottom), refer to Pygame pages. Some of the Rect object’s attributes are reproduced here for easy reference.
Rect Object’s Attributes:
“Left”, “right”, “top”, and “bottom” are called Rect
object’s attributes. The Rect
object has many attributes associated with it. In the Table below, newRect is a Rect
object. Below are a few of the attributes of the Rect object.
ATTRIBUTE | MEANING |
newRect.centerx | Integer value of the x-coordinate of the center of the rectangle |
newRect.centery | Integer value of the y-coordinate of the center of the rectangle |
newRect.width | Value of the width of the rectangle |
newRect.left | Integer value of the x-coordinate of the left side of rectangle |
newRect.right | Integer value of the x-coordinate of the right side of rectangle |
Line 59: step = 2
step = 2 means “birdSprite” moves 2 pixels each frame in the x-direction and the y-direction.
Put Sprites in the Sprite Group
Line 62: all_sprites = pygame.sprite.Group()
In this step, we create a sprite Group called “all_sprites” by calling Pygame.sprite.Group()
method. In this example program, we have only one sprite, but most games have many sprites on the display screen. Since our next programs will have many sprites on the screen, let us define a Group called “all_sprites” to hold all the sprites for games we will develop in the next section.
Line 66: birdSprite = MySprite(step)
Line 66 statement creates (spawns) an instance of “MySprite” class. This object instance is named “birdSprite”.
Line 68: all_sprites.add(birdSprite)
In line 68, we add the object instance “birdSprite” we created in line 66 to the “all_sprites” group that was created in line 62.
Lines 71 – 83: This code is part of the Event Loop.
71 running = True
72 while running:
73 # This section of code checks the events queue for events initiated by the user.
74 for event in pygame.event.get():
75 # Check if the user clicked the "X" on the window to exit the program.
76 # if "X" is clicked, set "running" = False and end the MAIN LOOP.
77 if event.type == pygame.QUIT:
78 running = False
79 # Monitor events queue to check if the user presses the "q" key on the keyboard.
80 # If "q" key is pressed, set "running" to False and end the MAIN LOOP.
81 elif event.type == pygame.KEYDOWN:
82 if event.key == ord('q'):
83 running = False
The Event Loop
The code in these lines is the program’s Event Loop and is the same as in program “sprite_space_shuttle_display.py” program in the earlier section. The code in lines 71- 83 continuously monitors the Event Queue for the events initiated by the user, like clicking the “X” on the window or hitting “q” key on the keyboard. If either of these events happen, the program sets the variable “running” = False. This ends the Event Loop and the game ends.
Line 86: all_sprites.update()
Line 86 is a Call to procedure “update(self)” defined in code lines 50 – 57. This procedure updates the screen.
The following steps draw and render the screen.
Line 89: screen.fill(WHITE)
This step is the same as in “sprite_space_shuttle_display.py” program and fills the screen with WHITE color in each turn of the while
loop.
Line 90: all_sprites.draw(screen)
Code in line 90 draws the sprites contained in “all_sprites” Group on the screen object.
Make All Images Visible on the Screen
Line 94: pygame.display.flip()
When we are finished drawing the screen Surface, we call the pygame.display.flip()
method. This method makes everything we have drawn on the screen Surface become visible on the display screen.
Line 96: clock.tick(FPS)
Call to tick()
method makes the Event Loop run at speed defined earlier in the program in the VARIABLES definition section by statement FPS = 60 in line 12. tick()
method tells Pygame to run the loop and after one loop is finished, pause to make sure 1/60th second are finished before starting the next repeat of the loop. This ensures that each loop finishes in 1/60th of a second. This is necessary, else the game will run too fast and images may not be visible to the user.
Quit the Program
Line 99: pygame.quit()
This step is the same as in the “Sprite_Space_Shuttle_Display.py” program.
The pygame.quit()
statement un-initializes all pygame modules that have previously been initialized. When the Event Loop ends, pygame.quit()
statement closes the game window. pygame.quit()
is the event that happens, when the ‘X’ is clicked on the screen window. When “X” is clicked, the program sets running to False and the Event Loop will end.