Performance Statistics

../_images/performance_statistics1.png

Arcade includes performance monitoring tools to help you optimize your game. This example demonstrates the following performance api features:

If you do not want to display graphs in your game window, you can use arcade.print_timings() to print out the count and average time for all dispatched events with the function. The output looks like this:

Event          Count Average Time
-------------- ----- ------------
on_activate        1       0.0000
on_resize          1       0.0000
on_show            1       0.0000
on_update         59       0.0000
on_expose          1       0.0000
on_draw           59       0.0021
on_mouse_enter     1       0.0000
on_mouse_motion  100       0.0000

See Performance Information for more information about the performance api.

performance_statistics.py
  1"""
  2Performance Statistic Display Example
  3
  4This example demonstrates how to use a few performance profiling tools
  5built into Arcade:
  6
  7* arcade.enable_timings
  8* arcade.PerfGraph
  9* arcade.get_fps
 10* arcade.print_timings
 11* arcade.clear_timings
 12
 13A large number of sprites bounce around the screen to produce load. You
 14can adjust the number of sprites by changing the COIN_COUNT constant.
 15
 16Artwork from https://kenney.nl
 17
 18If Python and Arcade are installed, this example can be run from the
 19command line with:
 20python -m arcade.examples.performance_statistics
 21"""
 22import random
 23
 24import arcade
 25
 26# --- Constants ---
 27SPRITE_SCALING_COIN = 0.25
 28SPRITE_NATIVE_SIZE = 128
 29SPRITE_SIZE = int(SPRITE_NATIVE_SIZE * SPRITE_SCALING_COIN)
 30
 31WINDOW_WIDTH = 1280
 32WINDOW_HEIGHT = 720
 33WINDOW_TITLE = "Performance Statistics Display Example"
 34
 35# Size of performance graphs and distance between them
 36GRAPH_WIDTH = 200
 37GRAPH_HEIGHT = 120
 38GRAPH_MARGIN = 5
 39
 40COIN_COUNT = 1500
 41
 42# Turn on tracking for the number of event handler
 43# calls and the average execution time of each type.
 44arcade.enable_timings()
 45
 46
 47class Coin(arcade.BasicSprite):
 48    """ Our coin sprite class """
 49    def __init__(self, texture: arcade.Texture, scale: float):
 50        super().__init__(texture, scale=scale)
 51        # Add a velocity to the coin
 52        self.change_x = 0
 53        self.change_y = 0
 54
 55    def update(self, delta_time: float = 1/60):
 56        """ Update the sprite. """
 57        # Setting the position is faster than setting x & y individually
 58        self.position = (
 59            self.position[0] + self.change_x,
 60            self.position[1] + self.change_y
 61        )
 62
 63        # Bounce the coin on the edge of the window
 64        if self.position[0] < 0:
 65            self.change_x *= -1
 66        elif self.position[0] > WINDOW_WIDTH:
 67            self.change_x *= -1
 68        if self.position[1] < 0:
 69            self.change_y *= -1
 70        elif self.position[1] > WINDOW_HEIGHT:
 71            self.change_y *= -1
 72
 73
 74class GameView(arcade.View):
 75    """ Our custom Window Class"""
 76
 77    def __init__(self):
 78        """ Initializer """
 79        # Call the parent class initializer
 80        super().__init__()
 81
 82        # Variables to hold game objects and performance info
 83        self.coin_list: arcade.SpriteList | None = None
 84        self.perf_graph_list: arcade.SpriteList | None = None
 85        self.fps_text: arcade.Text | None = None
 86        self.frame_count: int = 0  # for tracking the reset interval
 87
 88        self.coin_texture = arcade.load_texture(":resources:images/items/coinGold.png")
 89        self.background_color = arcade.color.AMAZON
 90
 91    def add_coins(self, amount):
 92
 93        # Create the coins
 94        for i in range(amount):
 95            # Create the coin instance
 96            # Coin image from kenney.nl
 97            coin = Coin(self.coin_texture, scale=SPRITE_SCALING_COIN)
 98
 99            # Position the coin
100            coin.position = (
101                random.randrange(SPRITE_SIZE, WINDOW_WIDTH - SPRITE_SIZE),
102                random.randrange(SPRITE_SIZE, WINDOW_HEIGHT - SPRITE_SIZE)
103            )
104
105            coin.change_x = random.randrange(-3, 4)
106            coin.change_y = random.randrange(-3, 4)
107
108            # Add the coin to the lists
109            self.coin_list.append(coin)
110
111    def setup(self):
112        """ Set up the game and initialize the variables. """
113
114        # Sprite lists
115        self.coin_list = arcade.SpriteList(use_spatial_hash=False)
116
117        # Create some coins
118        self.add_coins(COIN_COUNT)
119
120        # Create a sprite list to put the performance graphs into
121        self.perf_graph_list = arcade.SpriteList()
122
123        # Calculate position helpers for the row of 3 performance graphs
124        row_y = self.height - GRAPH_HEIGHT / 2
125        starting_x = GRAPH_WIDTH / 2
126        step_x = GRAPH_WIDTH + GRAPH_MARGIN
127
128        # Create the FPS performance graph
129        graph = arcade.PerfGraph(GRAPH_WIDTH, GRAPH_HEIGHT, graph_data="FPS")
130        graph.position = starting_x, row_y
131        self.perf_graph_list.append(graph)
132
133        # Create the on_update graph
134        graph = arcade.PerfGraph(GRAPH_WIDTH, GRAPH_HEIGHT, graph_data="on_update")
135        graph.position = starting_x + step_x, row_y
136        self.perf_graph_list.append(graph)
137
138        # Create the on_draw graph
139        graph = arcade.PerfGraph(GRAPH_WIDTH, GRAPH_HEIGHT, graph_data="on_draw")
140        graph.position = starting_x + step_x * 2, row_y
141        self.perf_graph_list.append(graph)
142
143        # Create a Text object to show the current FPS
144        self.fps_text = arcade.Text(
145            f"FPS: {arcade.get_fps(60):5.1f}",
146            10, 10, arcade.color.BLACK, 22
147        )
148
149    def on_draw(self):
150        """ Draw everything """
151
152        # Clear the screen
153        self.clear()
154
155        # Draw all the coin sprites
156        self.coin_list.draw()
157
158        # Draw the graphs
159        self.perf_graph_list.draw()
160
161        # Get & draw the FPS for the last 60 frames
162        if arcade.timings_enabled():
163            self.fps_text.value = f"FPS: {arcade.get_fps(60):5.1f}"
164            self.fps_text.draw()
165
166    def on_update(self, delta_time):
167        """ Update method """
168        self.frame_count += 1
169
170        # Print and clear timings every 60 frames
171        if self.frame_count % 60 == 0:
172            arcade.print_timings()
173            arcade.clear_timings()
174
175        # Move the coins
176        self.coin_list.update()
177
178    def on_key_press(self, symbol: int, modifiers: int):
179        if symbol == arcade.key.SPACE:
180            if arcade.timings_enabled():
181                arcade.disable_timings()
182            else:
183                arcade.enable_timings()
184
185
186def main():
187    """ Main function """
188    # Create a window class. This is what actually shows up on screen
189    window = arcade.Window(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
190
191    # Create and setup the GameView
192    game = GameView()
193    game.setup()
194
195    # Show GameView on screen
196    window.show_view(game)
197
198    # Start the arcade game loop
199    arcade.run()
200
201if __name__ == "__main__":
202    main()