Draw Moving Sprites Stress Test

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