gpu_particle_burst_07.py Full Listing#
gpu_particle_burst_07.py#
1"""
2Example showing how to create particle explosions via the GPU.
3"""
4import random
5import time
6import math
7from array import array
8from dataclasses import dataclass
9import arcade
10import arcade.gl
11
12SCREEN_WIDTH = 1024
13SCREEN_HEIGHT = 768
14SCREEN_TITLE = "GPU Particle Explosion"
15
16PARTICLE_COUNT = 300
17
18MIN_FADE_TIME = 0.25
19MAX_FADE_TIME = 1.5
20
21
22@dataclass
23class Burst:
24 """ Track for each burst. """
25 buffer: arcade.gl.Buffer
26 vao: arcade.gl.Geometry
27 start_time: float
28
29
30class MyWindow(arcade.Window):
31 """ Main window"""
32 def __init__(self):
33 super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
34 self.burst_list = []
35
36 # Program to visualize the points
37 self.program = self.ctx.load_program(
38 vertex_shader="vertex_shader_v4.glsl",
39 fragment_shader="fragment_shader.glsl",
40 )
41
42 self.ctx.enable_only(self.ctx.BLEND)
43
44 def on_draw(self):
45 """ Draw everything """
46 self.clear()
47
48 # Set the particle size
49 self.ctx.point_size = 2 * self.get_pixel_ratio()
50
51 # Loop through each burst
52 for burst in self.burst_list:
53
54 # Set the uniform data
55 self.program['time'] = time.time() - burst.start_time
56
57 # Render the burst
58 burst.vao.render(self.program, mode=self.ctx.POINTS)
59
60 def on_update(self, dt):
61 """ Update game """
62
63 # Create a copy of our list, as we can't modify a list while iterating
64 # it. Then see if any of the items have completely faded out and need
65 # to be removed.
66 temp_list = self.burst_list.copy()
67 for burst in temp_list:
68 if time.time() - burst.start_time > MAX_FADE_TIME:
69 self.burst_list.remove(burst)
70
71
72 def on_mouse_press(self, x: float, y: float, button: int, modifiers: int):
73 """ User clicks mouse """
74
75 def _gen_initial_data(initial_x, initial_y):
76 """ Generate data for each particle """
77 for i in range(PARTICLE_COUNT):
78 angle = random.uniform(0, 2 * math.pi)
79 speed = abs(random.gauss(0, 1)) * .5
80 dx = math.sin(angle) * speed
81 dy = math.cos(angle) * speed
82 red = random.uniform(0.5, 1.0)
83 green = random.uniform(0, red)
84 blue = 0
85 fade_rate = random.uniform(1 / MAX_FADE_TIME, 1 / MIN_FADE_TIME)
86
87 yield initial_x
88 yield initial_y
89 yield dx
90 yield dy
91 yield red
92 yield green
93 yield blue
94 yield fade_rate
95
96 # Recalculate the coordinates from pixels to the OpenGL system with
97 # 0, 0 at the center.
98 x2 = x / self.width * 2. - 1.
99 y2 = y / self.height * 2. - 1.
100
101 # Get initial particle data
102 initial_data = _gen_initial_data(x2, y2)
103
104 # Create a buffer with that data
105 buffer = self.ctx.buffer(data=array('f', initial_data))
106
107 # Create a buffer description that says how the buffer data is formatted.
108 buffer_description = arcade.gl.BufferDescription(buffer,
109 '2f 2f 3f f',
110 ['in_pos',
111 'in_vel',
112 'in_color',
113 'in_fade_rate'])
114 # Create our Vertex Attribute Object
115 vao = self.ctx.geometry([buffer_description])
116
117 # Create the Burst object and add it to the list of bursts
118 burst = Burst(buffer=buffer, vao=vao, start_time=time.time())
119 self.burst_list.append(burst)
120
121
122if __name__ == "__main__":
123 window = MyWindow()
124 window.center_window()
125 arcade.run()