Collision Stress Test

Screenshot of stress test example
stress_test_collision_arcade.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
  8If Python and Arcade are installed, this example can be run from the command line with:
  9python -m arcade.examples.stress_test_draw_moving
 10"""
 11
 12import arcade
 13import random
 14import os
 15import timeit
 16import time
 17import collections
 18import pyglet
 19
 20# --- Constants ---
 21SPRITE_SCALING_COIN = 0.09
 22SPRITE_SCALING_PLAYER = 0.5
 23SPRITE_NATIVE_SIZE = 128
 24SPRITE_SIZE = int(SPRITE_NATIVE_SIZE * SPRITE_SCALING_COIN)
 25COIN_COUNT_INCREMENT = 500
 26
 27STOP_COUNT = 12000
 28
 29SCREEN_WIDTH = 1800
 30SCREEN_HEIGHT = 1000
 31SCREEN_TITLE = "Moving Sprite Stress Test"
 32
 33USE_SPATIAL_HASHING = True
 34if USE_SPATIAL_HASHING:
 35    RESULTS_FILE = "stress_test_collision_arcade_spatial.csv"
 36else:
 37    RESULTS_FILE = "stress_test_collision_arcade.csv"
 38
 39
 40class FPSCounter:
 41    def __init__(self):
 42        self.time = time.perf_counter()
 43        self.frame_times = collections.deque(maxlen=60)
 44
 45    def tick(self):
 46        t1 = time.perf_counter()
 47        dt = t1 - self.time
 48        self.time = t1
 49        self.frame_times.append(dt)
 50
 51    def get_fps(self):
 52        total_time = sum(self.frame_times)
 53        if total_time == 0:
 54            return 0
 55        else:
 56            return len(self.frame_times) / sum(self.frame_times)
 57
 58
 59class MyGame(arcade.Window):
 60    """ Our custom Window Class"""
 61
 62    def __init__(self):
 63        """ Initializer """
 64        # Call the parent class initializer
 65        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
 66
 67        # Set the working directory (where we expect to find files) to the same
 68        # directory this .py file is in. You can leave this out of your own
 69        # code, but it is needed to easily run the examples using "python -m"
 70        # as mentioned at the top of this program.
 71        file_path = os.path.dirname(os.path.abspath(__file__))
 72        os.chdir(file_path)
 73
 74        # Variables that will hold sprite lists
 75        self.coin_list = None
 76        self.player_list = None
 77        self.player = None
 78
 79        self.processing_time = 0
 80        self.draw_time = 0
 81        self.program_start_time = timeit.default_timer()
 82        self.sprite_count_list = []
 83        self.fps_list = []
 84        self.processing_time_list = []
 85        self.drawing_time_list = []
 86        self.last_fps_reading = 0
 87        self.fps = FPSCounter()
 88
 89        arcade.set_background_color(arcade.color.AMAZON)
 90
 91        # Open file to save timings
 92        self.results_file = open(RESULTS_FILE, "w")
 93
 94    def add_coins(self):
 95
 96        # Create the coins
 97        for i in range(COIN_COUNT_INCREMENT):
 98            # Create the coin instance
 99            # Coin image from kenney.nl
100            coin = arcade.Sprite(":resources:images/items/coinGold.png", SPRITE_SCALING_COIN)
101
102            # Position the coin
103            coin.center_x = random.randrange(SPRITE_SIZE, SCREEN_WIDTH - SPRITE_SIZE)
104            coin.center_y = random.randrange(SPRITE_SIZE, SCREEN_HEIGHT - SPRITE_SIZE)
105
106            # Add the coin to the lists
107            self.coin_list.append(coin)
108
109    def setup(self):
110        """ Set up the game and initialize the variables. """
111
112        # Sprite lists
113        self.coin_list = arcade.SpriteList(use_spatial_hash=USE_SPATIAL_HASHING)
114        self.player_list = arcade.SpriteList()
115        self.player = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png", SPRITE_SCALING_PLAYER)
116        self.player.center_x = random.randrange(SCREEN_WIDTH)
117        self.player.center_y = random.randrange(SCREEN_HEIGHT)
118        self.player.change_x = 3
119        self.player.change_y = 5
120        self.player_list.append(self.player)
121
122    def on_draw(self):
123        """ Draw everything """
124
125        # Start timing how long this takes
126        draw_start_time = timeit.default_timer()
127
128        arcade.start_render()
129        self.coin_list.draw()
130        self.player_list.draw()
131
132        # Display info on sprites
133        output = f"Sprite count: {len(self.coin_list):,}"
134        arcade.draw_text(output, 20, SCREEN_HEIGHT - 20, arcade.color.BLACK, 16)
135
136        # Display timings
137        output = f"Processing time: {self.processing_time:.3f}"
138        arcade.draw_text(output, 20, SCREEN_HEIGHT - 40, arcade.color.BLACK, 16)
139
140        output = f"Drawing time: {self.draw_time:.3f}"
141        arcade.draw_text(output, 20, SCREEN_HEIGHT - 60, arcade.color.BLACK, 16)
142
143        fps = self.fps.get_fps()
144        output = f"FPS: {fps:3.0f}"
145        arcade.draw_text(output, 20, SCREEN_HEIGHT - 80, arcade.color.BLACK, 16)
146
147        self.draw_time = timeit.default_timer() - draw_start_time
148        self.fps.tick()
149
150    def update(self, delta_time):
151        # Start update timer
152
153        start_time = timeit.default_timer()
154
155        self.player_list.update()
156        if self.player.center_x < 0 and self.player.change_x < 0:
157            self.player.change_x *= -1
158        if self.player.center_y < 0 and self.player.change_y < 0:
159            self.player.change_y *= -1
160
161        if self.player.center_x > SCREEN_WIDTH and self.player.change_x > 0:
162            self.player.change_x *= -1
163        if self.player.center_y > SCREEN_HEIGHT and self.player.change_y > 0:
164            self.player.change_y *= -1
165
166        coin_hit_list = arcade.check_for_collision_with_list(self.player, self.coin_list)
167        for coin in coin_hit_list:
168            coin.center_x = random.randrange(SCREEN_WIDTH)
169            coin.center_y = random.randrange(SCREEN_HEIGHT)
170
171        # Save the time it took to do this.
172        self.processing_time = timeit.default_timer() - start_time
173
174        # Total time program has been running
175        total_program_time = int(timeit.default_timer() - self.program_start_time)
176
177        # Print out stats, or add more sprites
178        if total_program_time > self.last_fps_reading:
179            self.last_fps_reading = total_program_time
180
181            # It takes the program a while to "warm up", so the first
182            # few seconds our readings will be off. So wait some time
183            # before taking readings
184            if total_program_time > 5:
185
186                # We want the program to run for a while before taking
187                # timing measurements. We don't want the time it takes
188                # to add new sprites to be part of that measurement. So
189                # make sure we have a clear second of nothing but
190                # running the sprites, and not adding the sprites.
191                if total_program_time % 2 == 1:
192
193                    output = f"{total_program_time}, {len(self.coin_list)}, {self.fps.get_fps():.1f}, " \
194                            f"{self.processing_time:.4f}, {self.draw_time:.4f}\n"
195                    print(output, end="")
196                    self.results_file.write(output)
197
198                    if len(self.coin_list) >= STOP_COUNT:
199                        self.results_file.close()
200                        pyglet.app.exit()
201                        return
202
203                    # Take timings
204                    print(f"{total_program_time}, {len(self.coin_list)}, {self.fps.get_fps():.1f}, "
205                          f"{self.processing_time:.4f}, {self.draw_time:.4f}")
206                    self.sprite_count_list.append(len(self.coin_list))
207                    self.fps_list.append(round(self.fps.get_fps(), 1))
208                    self.processing_time_list.append(self.processing_time)
209                    self.drawing_time_list.append(self.draw_time)
210
211                    # Now add the coins
212                    self.add_coins()
213
214
215def main():
216    """ Main method """
217    window = MyGame()
218    window.setup()
219    arcade.run()
220
221
222if __name__ == "__main__":
223    main()