Sprite Game Programming

Control Sprites Using Keyboard Events

The program “sprite_display_move_bounce.py” moves the sprite without user action.  However, computer games require interactivity between the user and the program.

To create games, we need to develop techniques such that the user can interact with the program using the keyboard keys or the mouse.

For example, in a collision game between a player sprite and several alien sprites. the alien sprites move independently on their own. On the other hand, the player’s sprite is moved by the user’s action via the keyboard or the mouse.

If the user moves the player sprite to collide with an alien sprite, the alien sprite will disappear from the screen and the program will make a “punch” sound effect or any sound of your choosing.

The sprite game program below uses the user-initiated keypress events to move the sprite image. The code defines a function move(x,y), which moves the sprite by x pixels in the x-direction and y pixels in the y-direction.

The next section’s sprite game program uses user-initiated mouse clicks to control the sprites.

PROGRAM EXAMPLE: KEYBOARD RVENTS AND SPRITES

Program Folder: C:\Users\YourUserName\Python_scripts\sprite_move_keyboard_event.py

Image Name: C:\Users\YourUserName\Python_scripts\sprite_images\ball.png

1  # PROGRAM TO MOVE A SPRITE USING KEYBOARD ARROW KEYS
2  # Program Name: sprite_move_keyboard_event.py
3  # Image Name: ball.png
4  import pygame
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  w = 640 # Width of game window (called 'screen')
11  h = 480 # 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()  # Intialize Pygame.
25  screen = pygame.display.set_mode((w, h))
26  # "screen" is display window of specified width (w) and height (h).
27  pygame.display.set_caption('Sprite Move Using Keyboard') 
28  # Title of Display Window that appears on top of the screen window.
29  clock = pygame.time.Clock() 
30  # Call "Clock" method to create a ‘clock’ object.
31  # The clock object is the MAIN LOOP's clock.
32  # pygame.time.clock()is used in association with clock.tick() in line 143.  
33  
34  ################  OBJECTS  ################
35  ################  class Player(pygame.sprite.Sprite):  ################
36  class MySprite(pygame.sprite.Sprite):
37      def __init__ (self):
38          pygame.sprite.Sprite.__init__(self)
39          self.change_x = 0
40          self.change_y = 0
41          # set up asset folders
42          sprite_program_folder = os.path.dirname(__file__)
43          sprite_img_folder = os.path.join(sprite_program_folder, 'sprite_images')
44          ball_img = pygame.image.load(os.path.join(sprite_img_folder, 'ball.png')).convert()
45          self.image = ball_img
46          self.image.set_colorkey(WHITE)
47          self.rect = self.image.get_rect() 
48  
49  # Define a procedure and name it "step".
50      def step(self,x, y):  # move player by displacement (x,y)
51          self.change_x = self.change_x + x
52          self.change_y = self.change_y + y
53  #
54  # Define a procedure named update(). It is called in the MAIN LOOP
55  # to update the screen in every repeat of the MAIN LOOP.
56      def update(self):
57          self.rect.x = self.rect.x + self.change_x        
58          self.rect.y = self.rect.y + self.change_y 
59  # Screen Boundary Crossing Check.
60  # Test if the sprite has crossed the left or right boundaries
61  # of the screen. If the sprite reaches the left or the right boundary
62  # of the screen, bring it back to the opposite edge of the screen.
63          if self.rect.x > w:
64              self.rect.x = 0
65          if self.rect.x < 0:
66              self.rect.x = w
67  
68  # Test if the sprite reaches the top or the bottom boundary of the screen,
69  # bring it back to the opposite edge of the screen.
70          if self.rect.y > h:
71              self.rect.y = 0
72          if self.rect.y < 0:
73              self.rect.y = h
74  
75  # Create a Group called "all_sprites".
76  all_sprites = pygame.sprite.Group()  
77  # Make an instance of "MySprite" class and call it "ballSprite".
78  ballSprite = MySprite() 
79  # Add the sprite we just created to the "all_sprites" group.
80  all_sprites.add(ballSprite) 
81  # Initialize sprite coordinates on screen.
82  ballSprite.rect.x = w // 2 
83  ballSprite.rect.y = h // 2
84  stepsPerKeypress = 5 # Number of pixels the sprite moves per keypress.
85  
86  ################  MAIN LOOP  ################
87  running  = True
88  while running:
89      # Check the Events Queue for events initiated by the user.
90      for event in pygame.event.get(): 
91      # Check if the user clicked the "X" on the window to exit the program.
92      # if "X" is clicked on the screen window, set "running" = False and end the MAIN LOOP.  
93          if event.type == pygame.QUIT: 
94              running = False
95          # Monitor Events Queue to check if the user presses the "q" key
96          # on the keyboard to quit the game.
97          # If "q" key is pressed, set "running" to False and end the MAIN LOOP.        
98          elif event.type == pygame.KEYDOWN: 
99              if event.key == ord('q'):
100                  running = False
101  #                       
102              # Now check if any of the arrow keys are pressed by the user.
103              if event.key == pygame.K_LEFT:
104                  ballSprite.step(-stepsPerKeypress, 0)
105                  # Reduce x-coordinate by "stepsPerKeypress" pixels.
106              elif event.key == pygame.K_RIGHT:
107                  ballSprite.step(stepsPerKeypress, 0)
108                  # Increase x-coordinate by "stepsPerKeypress" pixels.
109                  
110              elif event.key == pygame.K_UP:
111                  ballSprite.step(0, -stepsPerKeypress)
112                  # Reduce y-coordinate by "stepsPerKeypress" pixels.
113              elif event.key == pygame.K_DOWN:
114                  ballSprite.step(0, stepsPerKeypress)
115                  # Increase y-coordinate by "stepsPerKeypress" pixels.
116          
117          # Now check if the user has released the pressed key.
118          # if the key is released, do not move the sprite.
119          # The sprite stays in the current location.
120          if event.type == pygame.KEYUP:
121              if event.key == pygame.K_LEFT:
122                  ballSprite.step(stepsPerKeypress,0)
123  
124              if event.key == pygame.K_RIGHT:
125                  ballSprite.step(-stepsPerKeypress,0)
126  
127              if event.key == pygame.K_UP:
128                  ballSprite.step(0, stepsPerKeypress)
129  
130              if event.key == pygame.K_DOWN:
131                  ballSprite.step(0, -stepsPerKeypress)
132               
133      # Call procedure update() to update the screen.
134      all_sprites.update() 
135      # Render the screen.
136      screen.fill(BLUE)
137      all_sprites.draw(screen) 
138  
139      # After drawing the screen Surface, call the pygame.display.flip() method.
140      # flip() method makes everything we have drawn on the screen Surface become visible. 
141      pygame.display.flip() 
142  
143      clock.tick(FPS)  
144      # tick() method runs the loop at "stepsPerKeypress" code in statement 12, FPS = 60.  
145  pygame.quit() 
146  # When the MAIN LOOP ends, pygame.quit() statement closes the window.    

Below is the program’s output. The motion of the ball is the user playing the game using keypresses. Notice how the ball bounces off the display screen boundaries.

Sprite Game Move a Sprite Using Keyborad Events.
sprite_move_keyboard_event.py program output

Detailed Line-by-line Explanation of the Sprite Game Program (Keyboard Events):

The explanation of all lines is the same as the program “sprite_display_move_bounce.py” except for the following lines of code.

Lines 36 – 40:  

36  class MySprite(pygame.sprite.Sprite):
37      def __init__ (self):
38          pygame.sprite.Sprite.__init__(self)
39          self.change_x = 0
40          self.change_y = 0

The code in lines 36 – 40 is similar to lines in the program “sprite_display_move_bounce.py”.

The function __init__ creates the class MySprite and attributes “change_x” and “change_y”.

“change_x” specifies the number of pixels the sprite moves in the x-direction each time the left arrow key is pressed.

Similarly, “change_y” specifies the number of pixels the sprite moves in the y-direction each time the right arrow key is pressed.

Function Definition “step(self, x, y)”

Lines 50 – 52:

50      def step(self,x, y):  # move player by displacement (x,y)
51          self.change_x = self.change_x + x
52          self.change_y = self.change_y + y

Lines 50 – 52 define a procedure named “step“. The procedure is called by the Event Loop when a keypress event is detected. The “step” function moves the sprite by the displacement (x,y) every time the “step” function is called.

This procedure takes the current position of the pixels and adds the displacement (x,y)  to calculate the new sprite position.

Function Definition “update()”

Lines 56 – 58:

56      def update(self):
57          self.rect.x = self.rect.x + self.change_x # Step 9)       
58          self.rect.y = self.rect.y + self.change_y

The code in lines 56 – 58 defines the update() procedure.

The update() procedure moves the sprite to its new position, before blitting it onto the screen in the new position. It adds the change_x defined in the function step to the current x-coordinates (rect_x) of the sprite. 

Similarly, it adds change_y defined in the function step to the current y-coordinate (rect_y) of the ball.  This happens in each loop iteration of the Main Loop.

Boundary Check in the LEFT and RIGHT Direction

Lines 63 – 66:

63          if self.rect.x > w:
64              self.rect.x = 0
65          if self.rect.x < 0:
66              self.rect.x = w

The code in lines 63 – 66 is part of the update(self) procedure and checks if the ball has crossed the left OR the right boundaries of the screen. If the sprite reaches the left ( x < 0) OR the right (x > w) boundaries of the screen, this code brings it back to the opposite edge of the screen.

Boundary Check in the TOP and BOTTOM Direction

Lines 70 – 73:

70          if self.rect.y > h:
71              self.rect.y = 0
72          if self.rect.y < 0:
73              self.rect.y = h

Lines 70 -73 are also part of the update(self) procedure and test if the sprite reaches the top (y < 0) or the bottom (y > h) boundary of the screen. In either of these two cases, the above code brings the sprite back to the opposite edge of the screen.

Initialize the Position of The Sprite

Lines 82 – 84:

82  ballSprite.rect.x = w // 2 
83  ballSprite.rect.y = h // 2
84  stepsPerKeypress = 5

This code initializes the position of the sprite to the center of the screen and defines the number of pixels the sprite moves per key press. Line 84 sets the number of pixels to move for each keypress to 5 pixels.

The Event Loop

Line 87 – 100: The Event Loop

This code is the same as in the program sprite_display_move_bounce.py” and checks if the user clicked “X” on the game window or pressed the “q” key.

Lines 103 – 107:

103              if event.key == pygame.K_LEFT:
104                  ballSprite.step(-stepsPerKeypress, 0)
105                  # Reduce x-coordinate by "stepsPerKeypress" pixels.
106              elif event.key == pygame.K_RIGHT:
107                  ballSprite.step(stepsPerKeypress, 0)

Event Loop Checks For Key Presses LEFT ARROW and RIGHT ARROW

The Event Loop code in lines 103 – 108 checks for keypress events.

If the left arrow key event (pygame.K_LEFT) is detected, the function “step” is called, which moves the ball to the left by “stepPerKeypress” pixels. “stepPerKeypress” variable was set to be 5 in code line #84.  If the right arrow keypress event is detected, the “step” function moves the ball to the right by “stepPerKeypress” pixels.

Event Loop Checks for Key Presses UP ARROW And DOWN ARROW

Lines 110 – 114:

110              elif event.key == pygame.K_UP:
111                  ballSprite.step(0, -stepsPerKeypress)
112                  # Reduce y-coordinate by "stepsPerKeypress" pixels.
113              elif event.key == pygame.K_DOWN:
114                  ballSprite.step(0, stepsPerKeypress)

The above code does the same logic as code lines 103 – 107, but it does it for the y-direction (UP/DOWN direction).

Lines 120 -131:

120          if event.type == pygame.KEYUP:
121              if event.key == pygame.K_LEFT:
122                  ballSprite.step(stepsPerKeypress,0)
123  
124              if event.key == pygame.K_RIGHT:
125                  ballSprite.step(-stepsPerKeypress,0)
126  
127              if event.key == pygame.K_UP:
128                  ballSprite.step(0, stepsPerKeypress)
129  
130              if event.key == pygame.K_DOWN:
131                  ballSprite.step(0, -stepsPerKeypress)

Event Loop Checks For Release of The Keys

The code in lines #120 – 131 checks if the user has released the pressed key. This code makes sure that if the key is released, the sprite is not allowed to move.  The sprite stays in its current location.  If we did not have this code, the sprite will keep on moving even after the key has been released.

The rest of the program does the same functionality as the “sprite_display_move_bounce.py“ program.

Control Sprite Using Mouse Events

In this section, the sprite game program does the same event processing as in the “sprite_move_keyboard_event.py” program, except instead of the keyboard events, it uses mouse motion events.

For details of the mouse events, refer to the page “Events in Pygame”.

PROGRAM EXAMPLE: MOUSE EVENTS AND SPRITES

Program Folder: C:\Users\YourUserName\Python_scripts\sprite_move_mouse_event.py

Image Name: C:\Users\YourUserName\Python_scripts\sprite_images\ball.png

1  # PROGRAM TO MOVE A SPRITE USING MOUSE
2  # Program Name: sprite_move_mouse_event.py
3  # Image Name: ball.png
4  import pygame
5  from pygame.locals import *
6  import os 
7  # os Module provides a way of using operating system dependent functionality.
8  
9  ################  VARIABLES  ################
10  w = 640 # Width of game window (called 'screen')
11  h = 480 # 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()  # Intialize Pygame.
25  screen = pygame.display.set_mode((w, h))
26  # "screen" is display window of specified width (w) and height (h).
27  pygame.display.set_caption('Sprite Move Using Keyboard') 
28  # Title of Display Window that appears on top of the screen window.
29  clock = pygame.time.Clock() 
30  # Call "Clock" method to create a ‘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 Player(pygame.sprite.Sprite):  ################
36  class MySprite(pygame.sprite.Sprite):
37      def __init__ (self):
38          pygame.sprite.Sprite.__init__(self)
39          self.change_x = 0
40          self.change_y = 0
41          # set up asset folders
42          sprite_program_folder = os.path.dirname(__file__) 
43          sprite_img_folder = os.path.join(sprite_program_folder, 'sprite_images')
44          ball_img = pygame.image.load(os.path.join(sprite_img_folder, 'ball.png')).convert() 
45          self.image = ball_img 
46          self.image.set_colorkey(WHITE)  
47          self.rect = self.image.get_rect() 
48  
49  # Define a procedure and name it "move".
50      def move(self,x, y):  # move player movement
51          x, y = pygame.mouse.get_pos() 
52          self.change_x = x
53          self.change_y = y   
54  # Define a procedure update(), which is called in the MAIN LOOP
55  # to update the screen in every repeat of the MAIN LOOP.
56      def update(self):
57          self.rect.x = self.change_x        
58          self.rect.y = self.change_y 
59  # Screen Boundary Crossing Check.    
60  # Test if the sprite has crossed the left or right boundaries
61  # of the screen. If the sprite reaches the left or the right boundary
62  # of the screen, bring it back to the opposite edge of the screen.
63          if self.rect.x > w -20:
64              self.rect.x = 20
65          if self.rect.x < 20:
66              self.rect.x = w - 100
67  #
68  # Test if the sprite reaches the top or the bottom boundary of the screen.
69  # If it does, bring it back to the opposite edge of the screen.
70          if self.rect.y > h - 20:
71              self.rect.y = 20
72          if self.rect.y < 20:
73              self.rect.y = h - 100
74  
75  # Create a Group called "all_sprites".
76  all_sprites = pygame.sprite.Group() 
77  # Make an instance of "MySprite" class and call it "ballSprite".
78  ballSprite = MySprite() 
79  # Add the sprite we just created to the "all_sprites" group.
80  all_sprites.add(ballSprite) 
81  # Initialize sprite coordinates on screen.
82  ballSprite.rect.x = w // 2 
83  ballSprite.rect.y = h // 2
84  
85  #    
86  ################  MAIN LOOP  ################
87  running  = True
88  while running:
89      # Check the Events Queue for events initiated by the user.
90      for event in pygame.event.get(): 
91      # Check if the user clicked the "X" on the window to exit the program.
92      # if "X" is clicked, set "running" = False and end the MAIN LOOP.  
93          if event.type == pygame.QUIT:
94              running = False
95          # Monitor events queue to check if the user presses the "q" key
96          # on the keyboard to quit the game.
97          # If "q" key is pressed, set "running" to False and end the MAIN LOOP.        
98          elif event.type == pygame.KEYDOWN: 
99              if event.key == ord('q'):
100                  running = False
101  
102      # Now check if the user moved the mouse.                
103      if event.type == pygame.MOUSEMOTION:
104          x, y = pygame.mouse.get_pos() # Get mouse coordinates.
105          print('Mouse motion detected', event.pos)
106          ballSprite.move(x, y) # Call function move(x,y).
107  #                                  
108      # Call procedure update() to update the screen.
109      all_sprites.update() 
110      # Render the screen.
111      screen.fill(BLUE)
112      all_sprites.draw(screen) 
113  
114      # After drawing the screen Surface, call the pygame.display.flip() method.
115      # flip() method makes everything we have drawn on the screen Surface become visible. 
116      pygame.display.flip() 
117  
118      clock.tick(FPS)  
119      # tick() method runs the loop 60 times per second as defined
120      # in code line #12 by statement FPS = 60.  
121  pygame.quit() 
122  # When the MAIN LOOP ends, pygame.quit() statement closes the window.    

Below is the sprite game program’s output. The sprite image is moving on the screen as the user is moving the mouse reacting to event type pygame.MOUSEMOTION

Sprite Game Move a Sprite Using Mouse Motion Events.
sprite_move_mouse_event.py Program Output

Detailed Line-by-line Explanation of the Sprite Game Program Using Mouse Events:

The explanation of this program is the same as the “sprite_move_keyboard_event.py” program, except for the following code line numbers.

Function Definition “move(self, x, y)”

Lines 50 – 53:

50      def move(self,x, y):  # move player movement
51          x, y = pygame.mouse.get_pos() 
52          self.change_x = x
53          self.change_y = y

The code above defines a procedure called “move”.  The procedure calls the mouse.get_pos() method and stores the current position coordinates in variables ”x” and “y”.

The pygame.mouse.get_pos(x,y) function gets the mouse curser position. This function returns the mouse x and y cursor position relative to the left-top corner of the display. Refer to the Pygame page for details about this function.

Function Definition “update()”

Lines 63 – 73: The update() procedure

63          if self.rect.x > w -20:
64              self.rect.x = 20
65          if self.rect.x < 20:
66              self.rect.x = w - 100
67  #
68  # Test if the sprite reaches the top or the bottom boundary of the screen.
69  # If it does, bring it back to the opposite edge of the screen.
70          if self.rect.y > h - 20:
71              self.rect.y = 20
72          if self.rect.y < 20:
73              self.rect.y = h - 100

Lines 63 – 73 define the procedure update(). It is very similar to the code in the “sprite.move_keyboard_event.py” program, except for the boundary check code. The above code tests if the sprite has crossed the left OR the right boundaries of the screen.

If the sprite reaches the left OR the right boundary of the screen, this code brings the sprite back to the opposite edge of the screen.

Lines 63 – 66 do the test for the left and right boundaries of the display screen.

Lines 70 – 73 do the same test as the code in lines 60 – 63, except it checks for sprite boundary crossover for the screen’s top and bottom boundaries.

The Event Loop

Line 88 – 100: Part of the Event Loop

88  while running:
89      # Check the Events Queue for events initiated by the user.
90      for event in pygame.event.get(): 
91      # Check if the user clicked the "X" on the window to exit the program.
92      # if "X" is clicked, set "running" = False and end the MAIN LOOP.  
93          if event.type == pygame.QUIT: 
94              running = False
95          # Monitor events queue to check if the user presses the "q" key
96          # on the keyboard to quit the game.
97          # If "q" key is pressed, set "running" to False and end the MAIN LOOP.        
98          elif event.type == pygame.KEYDOWN: 
99              if event.key == ord('q'):
100                  running = False

This code is the same as in the program “sprite_move_keyboard_event.py’ and checks if the user clicked “X” on the game window or pressed the “q” key.

Check for Mouse Motion Events

Lines 103 – 106: This is also part of the Event Loop.

103      if event.type == pygame.MOUSEMOTION:
104          x, y = pygame.mouse.get_pos() # Get mouse coordinates.
105          print('Mouse motion detected', event.pos)
106          ballSprite.move(x, y)

In the Event Loop, lines 103 – 106 test if the user moved the mouse.  The test is done by checking if the event type is Pygame.MOUSEMOTION.  

If the event type is MOUSEMOTION, the code calls the method mouse.get_pos() and stores the coordinates of the mouse position in variables “x” and “y”. 

The code then prints the text “Mouse motion detected”. It also prints the coordinates of the mouse position when the event was detected.

Refer to the Pygame Events page for details of pygame.MOUSEMOTION  event type and for mouse.get_pos() method.

Verified by MonsterInsights