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