Sprite Depth Controlled by a Cosine Wave

Screenshot of sprites whose depth value is controlled by time-dependent cosine wave.
sprite_depth_cosine.py
  1"""
  2Depth-sort sprites using a depth buffer in the GL context.
  3
  4Press the space bar to toggle depth testing during drawing.
  5
  6During each update, the depth of each sprite is updated to follow a
  7cosine wave. Afterward, the following is drawn:
  8
  9* All sprites in depth-sorted order
 10* A white square centered over each sprite along the x-axis, and moving
 11  with the wave along the y-axis
 12
 13If Python and Arcade are installed, this example can be run from the command line with:
 14python -m arcade.examples.sprite_depth_cosine
 15"""
 16
 17import math
 18
 19from pyglet.graphics import Batch
 20
 21import arcade
 22
 23# All constants are in pixels
 24WINDOW_WIDTH, WINDOW_HEIGHT = 1280, 720
 25
 26WINDOW_TITLE = "Sprite Depth Testing Example w/ a Cosine Wave"
 27NUM_SPRITES = 10
 28
 29SPRITE_X_START = 150
 30SPRITE_X_STEP = 50
 31SPRITE_Y = WINDOW_HEIGHT // 2
 32
 33DOT_SIZE = 10
 34
 35
 36class GameView(arcade.View):
 37
 38    def __init__(self):
 39        super().__init__()
 40
 41        texture = arcade.load_texture(":resources:images/test_textures/xy_square.png")
 42        self.text_batch = Batch()
 43
 44        self.use_depth: bool = True
 45        self.text_use_depth = arcade.Text(
 46            "SPACE: Toggle depth testing (True)",
 47            x=10,
 48            y=30,
 49            font_size=15,
 50            color=arcade.color.WHITE,
 51            batch=self.text_batch,
 52        )
 53
 54        self.sprite_list = arcade.SpriteList()
 55
 56        for i in range(NUM_SPRITES):
 57            sprite = arcade.Sprite(
 58                texture, center_x=SPRITE_X_START + SPRITE_X_STEP * i, center_y=SPRITE_Y
 59            )
 60            self.sprite_list.append(sprite)
 61
 62    def on_draw(self):
 63        self.clear()
 64
 65        ctx = self.window.ctx
 66        if self.use_depth:
 67            # This with block temporarily enables depth testing
 68            with ctx.enabled(ctx.DEPTH_TEST):
 69                self.sprite_list.draw()
 70        else:
 71            self.sprite_list.draw()
 72
 73        # Draw wave visualization markers over each sprite
 74        for i, sprite in enumerate(self.sprite_list):
 75            arcade.draw_point(
 76                SPRITE_X_START + SPRITE_X_STEP * i,
 77                SPRITE_Y + sprite.depth,
 78                arcade.color.WHITE,
 79                DOT_SIZE,
 80            )
 81
 82        self.text_batch.draw()
 83
 84    def on_key_press(self, symbol: int, modifiers: int):
 85        if symbol == arcade.key.SPACE:
 86            self.use_depth = not self.use_depth
 87            self.text_use_depth.text = f"SPACE: Toggle depth testing ({self.use_depth})"
 88
 89    def on_update(self, delta_time):
 90        # Using time from the window's clock simplifies the math below
 91        time = self.window.time
 92        for i, sprite in enumerate(self.sprite_list):
 93            sprite.depth = math.cos(time + i) * SPRITE_X_STEP
 94
 95
 96def main():
 97    """ Main function """
 98    # Create a window class. This is what actually shows up on screen
 99    window = arcade.Window(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
100
101    # Create the GameView
102    game = GameView()
103
104    # Show GameView on screen
105    window.show_view(game)
106
107    # Start the arcade game loop
108    arcade.run()
109
110
111if __name__ == "__main__":
112    main()