Sprite Depth Controlled by a 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
17from __future__ import annotations
18
19import math
20
21from pyglet.graphics import Batch
22
23import arcade
24
25# All constants are in pixels
26WINDOW_WIDTH, WINDOW_HEIGHT = 1280, 720
27
28WINDOW_TITLE = "Sprite Depth Testing Example w/ a Cosine Wave"
29NUM_SPRITES = 10
30
31SPRITE_X_START = 150
32SPRITE_X_STEP = 50
33SPRITE_Y = WINDOW_HEIGHT // 2
34
35DOT_SIZE = 10
36
37
38class GameView(arcade.View):
39
40 def __init__(self):
41 super().__init__()
42
43 texture = arcade.load_texture(":resources:images/test_textures/xy_square.png")
44 self.text_batch = Batch()
45
46 self.use_depth: bool = True
47 self.text_use_depth = arcade.Text(
48 "SPACE: Toggle depth testing (True)",
49 x=10,
50 y=30,
51 font_size=15,
52 color=arcade.color.WHITE,
53 batch=self.text_batch,
54 )
55
56 self.sprite_list = arcade.SpriteList()
57
58 for i in range(NUM_SPRITES):
59 sprite = arcade.Sprite(
60 texture, center_x=SPRITE_X_START + SPRITE_X_STEP * i, center_y=SPRITE_Y
61 )
62 self.sprite_list.append(sprite)
63
64 def on_draw(self):
65 self.clear()
66
67 ctx = self.window.ctx
68 if self.use_depth:
69 # This with block temporarily enables depth testing
70 with ctx.enabled(ctx.DEPTH_TEST):
71 self.sprite_list.draw()
72 else:
73 self.sprite_list.draw()
74
75 # Draw wave visualization markers over each sprite
76 for i, sprite in enumerate(self.sprite_list):
77 arcade.draw_point(
78 SPRITE_X_START + SPRITE_X_STEP * i,
79 SPRITE_Y + sprite.depth,
80 arcade.color.WHITE,
81 DOT_SIZE,
82 )
83
84 self.text_batch.draw()
85
86 def on_key_press(self, symbol: int, modifiers: int):
87 if symbol == arcade.key.SPACE:
88 self.use_depth = not self.use_depth
89 self.text_use_depth.text = f"SPACE: Toggle depth testing ({self.use_depth})"
90
91 def on_update(self, delta_time):
92 # Using time from the window's clock simplifies the math below
93 time = self.window.time
94 for i, sprite in enumerate(self.sprite_list):
95 sprite.depth = math.cos(time + i) * SPRITE_X_STEP
96
97
98def main():
99 """ Main function """
100 # Create a window class. This is what actually shows up on screen
101 window = arcade.Window(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
102
103 # Create the GameView
104 game = GameView()
105
106 # Show GameView on screen
107 window.show_view(game)
108
109 # Start the arcade game loop
110 arcade.run()
111
112
113if __name__ == "__main__":
114 main()