Collision Stress Test

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()