Pygame Draw Moving Sprites Source Code

draw_moving_sprites.py
  1"""
  2Moving Sprite Stress Test
  3
  4Simple program to test how fast we can draw sprites that are moving
  5
  6Artwork from http://kenney.nl
  7"""
  8
  9# noinspection PyPackageRequirements
 10import pygame
 11import random
 12import os
 13from performance_timing import PerformanceTiming
 14
 15# Define some colors
 16BLACK = (0, 0, 0)
 17WHITE = (255, 255, 255)
 18RED = (255, 0, 0)
 19
 20# --- Constants ---
 21SPRITE_SCALING_COIN = 0.25
 22SPRITE_NATIVE_SIZE = 128
 23SPRITE_SIZE = int(SPRITE_NATIVE_SIZE * SPRITE_SCALING_COIN)
 24
 25RESULTS_FILE = "../../result_data/pygame/draw_moving_sprites.csv"
 26RESULTS_IMAGE = "../../result_data/pygame/draw_moving_sprites.png"
 27SCREEN_WIDTH = 1800
 28SCREEN_HEIGHT = 1000
 29SCREEN_TITLE = "Pygame - Moving Sprite Stress Test"
 30
 31
 32class Coin(pygame.sprite.Sprite):
 33    """
 34    This class represents the ball
 35    It derives from the "Sprite" class in Pygame
 36    """
 37
 38    # Static coin image
 39    coin_image = None
 40
 41    def __init__(self):
 42        """ Constructor. Pass in the color of the block,
 43        and its x and y position. """
 44        # Call the parent class (Sprite) constructor
 45        super().__init__()
 46
 47        # In Pygame, if we load and scale a coin image every time we create a sprite,
 48        # this will result in a noticeable performance hit. Therefore we do it once,
 49        # and re-use that image over-and-over.
 50        if Coin.coin_image is None:
 51            # Create an image of the block, and fill it with a color.
 52            # This could also be an image loaded from the disk.
 53            Coin.coin_image = pygame.image.load("../resources/coinGold.png")
 54            rect = Coin.coin_image.get_rect()
 55            Coin.coin_image = pygame.transform.scale(
 56                Coin.coin_image,
 57                (int(rect.width * SPRITE_SCALING_COIN), int(rect.height * SPRITE_SCALING_COIN)))
 58            Coin.coin_image.convert()
 59            Coin.coin_image.set_colorkey(BLACK)
 60
 61        self.image = Coin.coin_image
 62
 63        # Fetch the rectangle object that has the dimensions of the image
 64        # image.
 65        # Update the position of this object by setting the values
 66        # of rect.x and rect.y
 67        self.rect = self.image.get_rect()
 68
 69        # Instance variables for our current speed and direction
 70        self.change_x = 0
 71        self.change_y = 0
 72
 73    def update(self):
 74        """ Called each frame. """
 75        self.rect.x += self.change_x
 76        self.rect.y += self.change_y
 77
 78
 79class MyGame:
 80    """ Our custom Window Class"""
 81
 82    def __init__(self):
 83        """ Initializer """
 84
 85        # Set the working directory (where we expect to find files) to the same
 86        # directory this .py file is in. You can leave this out of your own
 87        # code, but it is needed to easily run the examples using "python -m"
 88        # as mentioned at the top of this program.
 89        file_path = os.path.dirname(os.path.abspath(__file__))
 90        os.chdir(file_path)
 91
 92        # Variables that will hold sprite lists
 93        self.coin_list = None
 94
 95        self.performance_timing = PerformanceTiming(results_file=RESULTS_FILE,
 96                                                    start_n=0,
 97                                                    increment_n=250,
 98                                                    end_time=60)
 99
100        # Initialize Pygame
101        pygame.init()
102        pygame.display.set_caption(SCREEN_TITLE)
103
104        # Set the height and width of the screen
105        self.screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
106
107        # This is a list of every sprite. All blocks and the player block as well.
108        self.coin_list = pygame.sprite.Group()
109
110        self.font = pygame.font.SysFont('Calibri', 25, True, False)
111
112    def add_coins(self, coin_amount):
113
114        # Create the coins
115        for i in range(coin_amount):
116            # Create the coin instance
117            # Coin image from kenney.nl
118            coin = Coin()
119
120            # Position the coin
121            coin.rect.x = random.randrange(SPRITE_SIZE, SCREEN_WIDTH - SPRITE_SIZE)
122            coin.rect.y = random.randrange(SPRITE_SIZE, SCREEN_HEIGHT - SPRITE_SIZE)
123
124            coin.change_x = random.randrange(-3, 4)
125            coin.change_y = random.randrange(-3, 4)
126
127            # Add the coin to the lists
128            self.coin_list.add(coin)
129
130    def on_draw(self):
131        """ Draw everything """
132
133        # Start timing how long this takes
134        self.performance_timing.start_timer('draw')
135
136        # Clear the screen
137        self.screen.fill((59, 122, 87))
138
139        # Draw all the spites
140        self.coin_list.draw(self.screen)
141
142        pygame.display.flip()
143
144        # Stop timing how long this takes
145        self.performance_timing.stop_timer('draw')
146
147    def update(self, _delta_time):
148        # Start update timer
149        self.performance_timing.start_timer('update')
150
151        self.coin_list.update()
152
153        for sprite in self.coin_list:
154
155            if sprite.rect.x < 0:
156                sprite.change_x *= -1
157            elif sprite.rect.x > SCREEN_WIDTH:
158                sprite.change_x *= -1
159            if sprite.rect.y < 0:
160                sprite.change_y *= -1
161            elif sprite.rect.y > SCREEN_HEIGHT:
162                sprite.change_y *= -1
163
164        # Stop timing the update
165        self.performance_timing.stop_timer('update')
166
167        # Figure out if we need more coins
168        if self.performance_timing.target_n > len(self.coin_list):
169            new_coin_amount = self.performance_timing.target_n - len(self.coin_list)
170            self.add_coins(new_coin_amount)
171
172
173def main():
174    """ Main method """
175    window = MyGame()
176
177    # Loop until the user clicks the close button.
178    done = False
179
180    # Used to manage how fast the screen updates
181    clock = pygame.time.Clock()
182
183    # -------- Main Program Loop -----------
184    while not window.performance_timing.end_run() and not done:
185        for event in pygame.event.get():
186            if event.type == pygame.QUIT:
187                done = True
188        window.update(0)
189        window.on_draw()
190        clock.tick(60)
191
192    # Save screenshot
193    pygame.image.save(window.screen, RESULTS_IMAGE)
194
195    pygame.quit()
196
197
198if __name__ == "__main__":
199    main()