Particle Systems

particle_systems.py
1"""
2Particle Systems
3
4Demonstrate how to use the Emitter and Particle classes to create particle systems.
5
6Demonstrate the different effects possible with Emitter's and Particle's by showing
7a number of different emitters in sequence, with each example often varying just one
8setting from the previous example.
9
10If Python and Arcade are installed, this example can be run from the command line with:
11python -m arcade.examples.particle_systems
12"""
13import arcade
14import pyglet
15import random
16import math
17from arcade.math import (
18 rand_in_circle,
19 rand_on_circle,
20 rand_in_rect,
21 rand_on_line,
22 rand_vec_magnitude,
23 rand_vec_spread_deg,
24)
25from arcade import particles, LBWH
26
27WINDOW_WIDTH = 800
28WINDOW_HEIGHT = 600
29WINDOW_TITLE = "Particle System Examples"
30QUIET_BETWEEN_SPAWNS = 0.25 # time between spawning another particle system
31EMITTER_TIMEOUT = 10 * 60
32CENTER_POS = (WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2)
33BURST_PARTICLE_COUNT = 500
34TEXTURE = ":resources:images/pinball/pool_cue_ball.png"
35TEXTURE2 = ":resources:images/space_shooter/playerShip3_orange.png"
36TEXTURE3 = ":resources:images/pinball/bumper.png"
37TEXTURE4 = ":resources:images/enemies/wormGreen.png"
38TEXTURE5 = ":resources:images/space_shooter/meteorGrey_med1.png"
39TEXTURE6 = ":resources:images/animated_characters/female_person/femalePerson_idle.png"
40TEXTURE7 = ":resources:images/tiles/boxCrate_double.png"
41DEFAULT_SCALE = 0.3
42DEFAULT_ALPHA = 32
43DEFAULT_PARTICLE_LIFETIME = 3.0
44PARTICLE_SPEED_FAST = 1.0
45PARTICLE_SPEED_SLOW = 0.3
46DEFAULT_EMIT_INTERVAL = 0.003
47DEFAULT_EMIT_DURATION = 1.5
48
49
50# Utils
51def sine_wave(t, min_x, max_x, wavelength):
52 spread = max_x - min_x
53 mid = (max_x + min_x) / 2
54 return (spread / 2) * math.sin(2 * math.pi * t / wavelength) + mid
55
56
57# Example emitters
58def emitter_0():
59 """Burst, emit from center, particle with lifetime"""
60 e = particles.Emitter(
61 center_xy=CENTER_POS,
62 emit_controller=particles.EmitBurst(BURST_PARTICLE_COUNT),
63 particle_factory=lambda emitter: particles.LifetimeParticle(
64 filename_or_texture=TEXTURE,
65 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
66 lifetime=DEFAULT_PARTICLE_LIFETIME,
67 scale=DEFAULT_SCALE,
68 alpha=DEFAULT_ALPHA
69 )
70 )
71 return emitter_0.__doc__, e
72
73
74def emitter_1():
75 """Burst, emit from center, particle lifetime 1.0 seconds"""
76 e = particles.Emitter(
77 center_xy=CENTER_POS,
78 emit_controller=particles.EmitBurst(BURST_PARTICLE_COUNT),
79 particle_factory=lambda emitter: particles.LifetimeParticle(
80 filename_or_texture=TEXTURE,
81 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
82 lifetime=1.0,
83 scale=DEFAULT_SCALE,
84 alpha=DEFAULT_ALPHA
85 )
86 )
87 return emitter_1.__doc__, e
88
89
90def emitter_2():
91 """Burst, emit from center, particle lifetime random in range"""
92 e = particles.Emitter(
93 center_xy=CENTER_POS,
94 emit_controller=particles.EmitBurst(BURST_PARTICLE_COUNT),
95 particle_factory=lambda emitter: particles.LifetimeParticle(
96 filename_or_texture=TEXTURE,
97 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
98 lifetime=random.uniform(DEFAULT_PARTICLE_LIFETIME - 1.0, DEFAULT_PARTICLE_LIFETIME),
99 scale=DEFAULT_SCALE,
100 alpha=DEFAULT_ALPHA
101 )
102 )
103 return emitter_2.__doc__, e
104
105
106def emitter_3():
107 """Burst, emit in circle"""
108 e = particles.Emitter(
109 center_xy=CENTER_POS,
110 emit_controller=particles.EmitBurst(BURST_PARTICLE_COUNT),
111 particle_factory=lambda emitter: particles.LifetimeParticle(
112 filename_or_texture=TEXTURE,
113 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_SLOW),
114 lifetime=DEFAULT_PARTICLE_LIFETIME,
115 center_xy=rand_in_circle((0.0, 0.0), 100),
116 scale=DEFAULT_SCALE,
117 alpha=DEFAULT_ALPHA
118 )
119 )
120 return emitter_3.__doc__, e
121
122
123def emitter_4():
124 """Burst, emit on circle"""
125 e = particles.Emitter(
126 center_xy=CENTER_POS,
127 emit_controller=particles.EmitBurst(BURST_PARTICLE_COUNT),
128 particle_factory=lambda emitter: particles.LifetimeParticle(
129 filename_or_texture=TEXTURE,
130 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_SLOW),
131 lifetime=DEFAULT_PARTICLE_LIFETIME,
132 center_xy=rand_on_circle((0.0, 0.0), 100),
133 scale=DEFAULT_SCALE,
134 alpha=DEFAULT_ALPHA
135 )
136 )
137 return emitter_4.__doc__, e
138
139
140def emitter_5():
141 """Burst, emit in rectangle"""
142 width, height = 200, 100
143 centering_offset = (-width / 2, -height / 2)
144 e = particles.Emitter(
145 center_xy=CENTER_POS,
146 emit_controller=particles.EmitBurst(BURST_PARTICLE_COUNT),
147 particle_factory=lambda emitter: particles.LifetimeParticle(
148 filename_or_texture=TEXTURE,
149 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_SLOW),
150 lifetime=DEFAULT_PARTICLE_LIFETIME,
151 center_xy=rand_in_rect(LBWH(*centering_offset, width, height)),
152 scale=DEFAULT_SCALE,
153 alpha=DEFAULT_ALPHA
154 )
155 )
156 return emitter_5.__doc__, e
157
158
159def emitter_6():
160 """Burst, emit on line"""
161 e = particles.Emitter(
162 center_xy=CENTER_POS,
163 emit_controller=particles.EmitBurst(BURST_PARTICLE_COUNT),
164 particle_factory=lambda emitter: particles.LifetimeParticle(
165 filename_or_texture=TEXTURE,
166 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_SLOW),
167 lifetime=DEFAULT_PARTICLE_LIFETIME,
168 center_xy=rand_on_line((0.0, 0.0), (WINDOW_WIDTH, WINDOW_HEIGHT)),
169 scale=DEFAULT_SCALE,
170 alpha=DEFAULT_ALPHA
171 )
172 )
173 return emitter_6.__doc__, e
174
175
176def emitter_7():
177 """Burst, emit from center, velocity fixed speed around 360 degrees"""
178 e = particles.Emitter(
179 center_xy=CENTER_POS,
180 emit_controller=particles.EmitBurst(BURST_PARTICLE_COUNT // 4),
181 particle_factory=lambda emitter: particles.LifetimeParticle(
182 filename_or_texture=TEXTURE,
183 change_xy=rand_on_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
184 lifetime=DEFAULT_PARTICLE_LIFETIME,
185 scale=DEFAULT_SCALE,
186 alpha=DEFAULT_ALPHA
187 )
188 )
189 return emitter_7.__doc__, e
190
191
192def emitter_8():
193 """Burst, emit from center, velocity in rectangle"""
194 e = particles.Emitter(
195 center_xy=CENTER_POS,
196 emit_controller=particles.EmitBurst(BURST_PARTICLE_COUNT),
197 particle_factory=lambda emitter: particles.LifetimeParticle(
198 filename_or_texture=TEXTURE,
199 change_xy=rand_in_rect(LBWH(-2.0, -2.0, 4.0, 4.0)),
200 lifetime=DEFAULT_PARTICLE_LIFETIME,
201 scale=DEFAULT_SCALE,
202 alpha=DEFAULT_ALPHA
203 )
204 )
205 return emitter_8.__doc__, e
206
207
208def emitter_9():
209 """Burst, emit from center, velocity in fixed angle and random speed"""
210 e = particles.Emitter(
211 center_xy=CENTER_POS,
212 emit_controller=particles.EmitBurst(BURST_PARTICLE_COUNT // 4),
213 particle_factory=lambda emitter: particles.LifetimeParticle(
214 filename_or_texture=TEXTURE,
215 change_xy=rand_vec_magnitude(45, 1.0, 4.0),
216 lifetime=DEFAULT_PARTICLE_LIFETIME,
217 scale=DEFAULT_SCALE,
218 alpha=DEFAULT_ALPHA
219 )
220 )
221 return emitter_9.__doc__, e
222
223
224def emitter_10():
225 """Burst, emit from center, velocity from angle with spread"""
226 e = particles.Emitter(
227 center_xy=CENTER_POS,
228 emit_controller=particles.EmitBurst(BURST_PARTICLE_COUNT // 4),
229 particle_factory=lambda emitter: particles.LifetimeParticle(
230 filename_or_texture=TEXTURE,
231 change_xy=rand_vec_spread_deg(90, 45, 2.0),
232 lifetime=DEFAULT_PARTICLE_LIFETIME,
233 scale=DEFAULT_SCALE,
234 alpha=DEFAULT_ALPHA
235 )
236 )
237 return emitter_10.__doc__, e
238
239
240def emitter_11():
241 """Burst, emit from center, velocity along a line"""
242 e = particles.Emitter(
243 center_xy=CENTER_POS,
244 emit_controller=particles.EmitBurst(BURST_PARTICLE_COUNT // 4),
245 particle_factory=lambda emitter: particles.LifetimeParticle(
246 filename_or_texture=TEXTURE,
247 change_xy=rand_on_line((-2, 1), (2, 1)),
248 lifetime=DEFAULT_PARTICLE_LIFETIME,
249 scale=DEFAULT_SCALE,
250 alpha=DEFAULT_ALPHA
251 )
252 )
253 return emitter_11.__doc__, e
254
255
256def emitter_12():
257 """Infinite emitting w/ eternal particle"""
258 e = particles.Emitter(
259 center_xy=CENTER_POS,
260 emit_controller=particles.EmitInterval(0.02),
261 particle_factory=lambda emitter: particles.EternalParticle(
262 filename_or_texture=TEXTURE,
263 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
264 scale=DEFAULT_SCALE,
265 alpha=DEFAULT_ALPHA
266 )
267 )
268 return emitter_12.__doc__, e
269
270
271def emitter_13():
272 """Interval, emit particle every 0.01 seconds for one second"""
273 e = particles.Emitter(
274 center_xy=CENTER_POS,
275 emit_controller=particles.EmitterIntervalWithTime(
276 DEFAULT_EMIT_INTERVAL,
277 DEFAULT_EMIT_DURATION,
278 ),
279 particle_factory=lambda emitter: particles.LifetimeParticle(
280 filename_or_texture=TEXTURE,
281 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
282 lifetime=DEFAULT_PARTICLE_LIFETIME,
283 scale=DEFAULT_SCALE,
284 alpha=DEFAULT_ALPHA
285 )
286 )
287 return emitter_13.__doc__, e
288
289
290def emitter_14():
291 """Interval, emit from center, particle lifetime 1.0 seconds"""
292 e = particles.Emitter(
293 center_xy=CENTER_POS,
294 emit_controller=particles.EmitterIntervalWithTime(
295 DEFAULT_EMIT_INTERVAL,
296 DEFAULT_EMIT_DURATION,
297 ),
298 particle_factory=lambda emitter: particles.LifetimeParticle(
299 filename_or_texture=TEXTURE,
300 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
301 lifetime=1.0,
302 scale=DEFAULT_SCALE,
303 alpha=DEFAULT_ALPHA
304 )
305 )
306 return emitter_14.__doc__, e
307
308
309def emitter_15():
310 """Interval, emit from center, particle lifetime random in range"""
311 e = particles.Emitter(
312 center_xy=CENTER_POS,
313 emit_controller=particles.EmitterIntervalWithTime(
314 DEFAULT_EMIT_INTERVAL,
315 DEFAULT_EMIT_DURATION,
316 ),
317 particle_factory=lambda emitter: particles.LifetimeParticle(
318 filename_or_texture=TEXTURE,
319 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
320 lifetime=random.uniform(DEFAULT_PARTICLE_LIFETIME - 1.0, DEFAULT_PARTICLE_LIFETIME),
321 scale=DEFAULT_SCALE,
322 alpha=DEFAULT_ALPHA
323 )
324 )
325 return emitter_15.__doc__, e
326
327
328def emitter_16():
329 """Interval, emit in circle"""
330 e = particles.Emitter(
331 center_xy=CENTER_POS,
332 emit_controller=particles.EmitterIntervalWithTime(
333 DEFAULT_EMIT_INTERVAL,
334 DEFAULT_EMIT_DURATION
335 ),
336 particle_factory=lambda emitter: particles.LifetimeParticle(
337 filename_or_texture=TEXTURE,
338 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_SLOW),
339 lifetime=DEFAULT_PARTICLE_LIFETIME,
340 center_xy=rand_in_circle((0.0, 0.0), 100),
341 scale=DEFAULT_SCALE,
342 alpha=DEFAULT_ALPHA
343 )
344 )
345 return emitter_16.__doc__, e
346
347
348def emitter_17():
349 """Interval, emit on circle"""
350 e = particles.Emitter(
351 center_xy=CENTER_POS,
352 emit_controller=particles.EmitterIntervalWithTime(
353 DEFAULT_EMIT_INTERVAL,
354 DEFAULT_EMIT_DURATION,
355 ),
356 particle_factory=lambda emitter: particles.LifetimeParticle(
357 filename_or_texture=TEXTURE,
358 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_SLOW),
359 lifetime=DEFAULT_PARTICLE_LIFETIME,
360 center_xy=rand_on_circle((0.0, 0.0), 100),
361 scale=DEFAULT_SCALE,
362 alpha=DEFAULT_ALPHA
363 )
364 )
365 return emitter_17.__doc__, e
366
367
368def emitter_18():
369 """Interval, emit in rectangle"""
370 width, height = 200, 100
371 centering_offset = (-width / 2, -height / 2)
372 e = particles.Emitter(
373 center_xy=CENTER_POS,
374 emit_controller=particles.EmitterIntervalWithTime(
375 DEFAULT_EMIT_INTERVAL,
376 DEFAULT_EMIT_DURATION,
377 ),
378 particle_factory=lambda emitter: particles.LifetimeParticle(
379 filename_or_texture=TEXTURE,
380 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_SLOW),
381 lifetime=DEFAULT_PARTICLE_LIFETIME,
382 center_xy=rand_in_rect(LBWH(*centering_offset, width, height)),
383 scale=DEFAULT_SCALE,
384 alpha=DEFAULT_ALPHA
385 )
386 )
387 return emitter_18.__doc__, e
388
389
390def emitter_19():
391 """Interval, emit on line"""
392 e = particles.Emitter(
393 center_xy=(0.0, 0.0),
394 emit_controller=particles.EmitterIntervalWithTime(
395 DEFAULT_EMIT_INTERVAL,
396 DEFAULT_EMIT_DURATION
397 ),
398 particle_factory=lambda emitter: particles.LifetimeParticle(
399 filename_or_texture=TEXTURE,
400 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_SLOW),
401 lifetime=DEFAULT_PARTICLE_LIFETIME,
402 center_xy=rand_on_line((0.0, 0.0), (WINDOW_WIDTH, WINDOW_HEIGHT)),
403 scale=DEFAULT_SCALE,
404 alpha=DEFAULT_ALPHA,
405 )
406 )
407 return emitter_19.__doc__, e
408
409
410def emitter_20():
411 """Interval, emit from center, velocity fixed speed around 360 degrees"""
412 e = particles.Emitter(
413 center_xy=CENTER_POS,
414 emit_controller=particles.EmitterIntervalWithTime(
415 DEFAULT_EMIT_INTERVAL,
416 DEFAULT_EMIT_DURATION
417 ),
418 particle_factory=lambda emitter: particles.LifetimeParticle(
419 filename_or_texture=TEXTURE,
420 change_xy=rand_on_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
421 lifetime=DEFAULT_PARTICLE_LIFETIME,
422 scale=DEFAULT_SCALE,
423 alpha=DEFAULT_ALPHA,
424 )
425 )
426 return emitter_20.__doc__, e
427
428
429def emitter_21():
430 """Interval, emit from center, velocity in rectangle"""
431 e = particles.Emitter(
432 center_xy=CENTER_POS,
433 emit_controller=particles.EmitterIntervalWithTime(
434 DEFAULT_EMIT_INTERVAL,
435 DEFAULT_EMIT_DURATION,
436 ),
437 particle_factory=lambda emitter: particles.LifetimeParticle(
438 filename_or_texture=TEXTURE,
439 change_xy=rand_in_rect(LBWH(-2.0, -2.0, 4.0, 4.0)),
440 lifetime=DEFAULT_PARTICLE_LIFETIME,
441 scale=DEFAULT_SCALE,
442 alpha=DEFAULT_ALPHA
443 )
444 )
445 return emitter_21.__doc__, e
446
447
448def emitter_22():
449 """Interval, emit from center, velocity in fixed angle and speed"""
450 e = particles.Emitter(
451 center_xy=CENTER_POS,
452 emit_controller=particles.EmitterIntervalWithTime(0.2, DEFAULT_EMIT_DURATION),
453 particle_factory=lambda emitter: particles.LifetimeParticle(
454 filename_or_texture=TEXTURE,
455 change_xy=(1.0, 1.0),
456 lifetime=DEFAULT_PARTICLE_LIFETIME,
457 scale=DEFAULT_SCALE,
458 alpha=128
459 )
460 )
461 return emitter_22.__doc__, e
462
463
464def emitter_23():
465 """Interval, emit from center, velocity in fixed angle and random speed"""
466 e = particles.Emitter(
467 center_xy=CENTER_POS,
468 emit_controller=particles.EmitterIntervalWithTime(
469 DEFAULT_EMIT_INTERVAL * 8,
470 DEFAULT_EMIT_DURATION,
471 ),
472 particle_factory=lambda emitter: particles.LifetimeParticle(
473 filename_or_texture=TEXTURE,
474 change_xy=rand_vec_magnitude(45, 1.0, 4.0),
475 lifetime=DEFAULT_PARTICLE_LIFETIME,
476 scale=DEFAULT_SCALE,
477 alpha=DEFAULT_ALPHA
478 )
479 )
480 return emitter_23.__doc__, e
481
482
483def emitter_24():
484 """Interval, emit from center, velocity from angle with spread"""
485 e = particles.Emitter(
486 center_xy=CENTER_POS,
487 emit_controller=particles.EmitterIntervalWithTime(
488 DEFAULT_EMIT_INTERVAL,
489 DEFAULT_EMIT_DURATION,
490 ),
491 particle_factory=lambda emitter: particles.LifetimeParticle(
492 filename_or_texture=TEXTURE,
493 change_xy=rand_vec_spread_deg(90, 45, 2.0),
494 lifetime=DEFAULT_PARTICLE_LIFETIME,
495 scale=DEFAULT_SCALE,
496 alpha=DEFAULT_ALPHA
497 )
498 )
499 return emitter_24.__doc__, e
500
501
502def emitter_25():
503 """Interval, emit from center, velocity along a line"""
504 e = particles.Emitter(
505 center_xy=CENTER_POS,
506 emit_controller=particles.EmitterIntervalWithTime(
507 DEFAULT_EMIT_INTERVAL,
508 DEFAULT_EMIT_DURATION,
509 ),
510 particle_factory=lambda emitter: particles.LifetimeParticle(
511 filename_or_texture=TEXTURE,
512 change_xy=rand_on_line((-2, 1), (2, 1)),
513 lifetime=DEFAULT_PARTICLE_LIFETIME,
514 scale=DEFAULT_SCALE,
515 alpha=DEFAULT_ALPHA
516 )
517 )
518 return emitter_25.__doc__, e
519
520
521def emitter_26():
522 """Interval, emit particles every 0.4 seconds and stop after emitting 5"""
523 e = particles.Emitter(
524 center_xy=CENTER_POS,
525 emit_controller=particles.EmitterIntervalWithCount(0.4, 5),
526 particle_factory=lambda emitter: particles.LifetimeParticle(
527 filename_or_texture=TEXTURE,
528 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
529 lifetime=DEFAULT_PARTICLE_LIFETIME,
530 scale=0.6,
531 alpha=128
532 )
533 )
534 return emitter_26.__doc__, e
535
536
537def emitter_27():
538 """Maintain a steady count of particles"""
539 e = particles.Emitter(
540 center_xy=CENTER_POS,
541 emit_controller=particles.EmitMaintainCount(3),
542 particle_factory=lambda emitter: particles.LifetimeParticle(
543 filename_or_texture=TEXTURE,
544 change_xy=rand_on_circle((0.0, 0.0), 2.0),
545 lifetime=random.uniform(1.0, 3.0),
546 )
547 )
548 return emitter_27.__doc__, e
549
550
551def emitter_28():
552 """random particle textures"""
553 e = particles.Emitter(
554 center_xy=CENTER_POS,
555 emit_controller=particles.EmitterIntervalWithTime(
556 DEFAULT_EMIT_INTERVAL * 5,
557 DEFAULT_EMIT_DURATION,
558 ),
559 particle_factory=lambda emitter: particles.LifetimeParticle(
560 filename_or_texture=random.choice((TEXTURE, TEXTURE2, TEXTURE3)),
561 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
562 lifetime=DEFAULT_PARTICLE_LIFETIME,
563 scale=DEFAULT_SCALE
564 )
565 )
566 return emitter_28.__doc__, e
567
568
569def emitter_29():
570 """random particle scale"""
571 e = particles.Emitter(
572 center_xy=CENTER_POS,
573 emit_controller=particles.EmitterIntervalWithTime(
574 DEFAULT_EMIT_INTERVAL * 5,
575 DEFAULT_EMIT_DURATION,
576 ),
577 particle_factory=lambda emitter: particles.LifetimeParticle(
578 filename_or_texture=TEXTURE,
579 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
580 lifetime=DEFAULT_PARTICLE_LIFETIME,
581 scale=random.uniform(0.1, 0.8),
582 alpha=DEFAULT_ALPHA
583 )
584 )
585 return emitter_29.__doc__, e
586
587
588def emitter_30():
589 """random particle alpha"""
590 e = particles.Emitter(
591 center_xy=CENTER_POS,
592 emit_controller=particles.EmitterIntervalWithTime(
593 DEFAULT_EMIT_INTERVAL * 5,
594 DEFAULT_EMIT_DURATION,
595 ),
596 particle_factory=lambda emitter: particles.LifetimeParticle(
597 filename_or_texture=TEXTURE,
598 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
599 lifetime=DEFAULT_PARTICLE_LIFETIME,
600 scale=DEFAULT_SCALE,
601 alpha=int(random.uniform(32, 128))
602 )
603 )
604 return emitter_30.__doc__, e
605
606
607def emitter_31():
608 """Constant particle angle"""
609 e = particles.Emitter(
610 center_xy=CENTER_POS,
611 emit_controller=particles.EmitterIntervalWithTime(
612 DEFAULT_EMIT_INTERVAL * 5,
613 DEFAULT_EMIT_DURATION,
614 ),
615 particle_factory=lambda emitter: particles.LifetimeParticle(
616 filename_or_texture=TEXTURE2,
617 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
618 lifetime=DEFAULT_PARTICLE_LIFETIME,
619 angle=45,
620 scale=DEFAULT_SCALE
621 )
622 )
623 return emitter_31.__doc__, e
624
625
626def emitter_32():
627 """animate particle angle"""
628 e = particles.Emitter(
629 center_xy=CENTER_POS,
630 emit_controller=particles.EmitterIntervalWithTime(
631 DEFAULT_EMIT_INTERVAL * 5,
632 DEFAULT_EMIT_DURATION,
633 ),
634 particle_factory=lambda emitter: particles.LifetimeParticle(
635 filename_or_texture=TEXTURE2,
636 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
637 lifetime=DEFAULT_PARTICLE_LIFETIME,
638 change_angle=2,
639 scale=DEFAULT_SCALE
640 )
641 )
642 return emitter_32.__doc__, e
643
644
645def emitter_33():
646 """Particles that fade over time"""
647 e = particles.Emitter(
648 center_xy=CENTER_POS,
649 emit_controller=particles.EmitterIntervalWithTime(
650 DEFAULT_EMIT_INTERVAL,
651 DEFAULT_EMIT_DURATION,
652 ),
653 particle_factory=lambda emitter: particles.FadeParticle(
654 filename_or_texture=TEXTURE,
655 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
656 lifetime=DEFAULT_PARTICLE_LIFETIME,
657 scale=DEFAULT_SCALE
658 )
659 )
660 return emitter_33.__doc__, e
661
662
663def emitter_34():
664 """Dynamically generated textures, burst emitting, fading particles"""
665 textures = [
666 arcade.make_soft_circle_texture(48, p)
667 for p in (arcade.color.GREEN, arcade.color.BLUE_GREEN)
668 ]
669 e = particles.Emitter(
670 center_xy=CENTER_POS,
671 emit_controller=particles.EmitBurst(BURST_PARTICLE_COUNT),
672 particle_factory=lambda emitter: particles.FadeParticle(
673 filename_or_texture=random.choice(textures),
674 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST),
675 lifetime=DEFAULT_PARTICLE_LIFETIME,
676 scale=DEFAULT_SCALE
677 )
678 )
679 return emitter_34.__doc__, e
680
681
682def emitter_35():
683 """Use most features"""
684 soft_circle = arcade.make_soft_circle_texture(80, (255, 64, 64))
685 textures = (
686 TEXTURE,
687 TEXTURE2,
688 TEXTURE3,
689 TEXTURE4,
690 TEXTURE5,
691 TEXTURE6,
692 TEXTURE7,
693 soft_circle,
694 )
695 e = particles.Emitter(
696 center_xy=CENTER_POS,
697 emit_controller=particles.EmitterIntervalWithTime(0.01, 1.0),
698 particle_factory=lambda emitter: particles.FadeParticle(
699 filename_or_texture=random.choice(textures),
700 change_xy=rand_in_circle((0.0, 0.0), PARTICLE_SPEED_FAST * 2),
701 lifetime=random.uniform(1.0, 3.5),
702 angle=random.uniform(0, 360),
703 change_angle=random.uniform(-3, 3),
704 scale=random.uniform(0.1, 0.8)
705 )
706 )
707 return emitter_35.__doc__, e
708
709
710def emitter_36():
711 """Moving emitter. Particles spawn relative to emitter."""
712
713 class MovingEmitter(particles.Emitter):
714 def __init__(self, *args, **kwargs):
715 super().__init__(*args, **kwargs)
716 self.elapsed = 0.0
717
718 def update(self, delta_time: float = 1 / 60):
719 super().update(delta_time)
720 self.elapsed += delta_time
721 self.center_x = sine_wave(self.elapsed, 0, WINDOW_WIDTH, WINDOW_WIDTH / 100)
722 self.center_y = sine_wave(self.elapsed, 0, WINDOW_HEIGHT, WINDOW_HEIGHT / 100)
723
724 e = MovingEmitter(
725 center_xy=CENTER_POS,
726 emit_controller=particles.EmitInterval(0.005),
727 particle_factory=lambda emitter: particles.FadeParticle(
728 filename_or_texture=TEXTURE,
729 change_xy=rand_in_circle((0.0, 0.0), 0.1),
730 lifetime=random.uniform(1.5, 5.5),
731 scale=random.uniform(0.05, 0.2)
732 )
733 )
734 return emitter_36.__doc__, e
735
736
737def emitter_37():
738 """Rotating emitter. Particles initial velocity is relative to emitter's angle."""
739 e = particles.Emitter(
740 center_xy=CENTER_POS,
741 emit_controller=particles.EmitterIntervalWithTime(
742 DEFAULT_EMIT_INTERVAL,
743 DEFAULT_EMIT_DURATION,
744 ),
745 particle_factory=lambda emitter: particles.LifetimeParticle(
746 filename_or_texture=TEXTURE,
747 change_xy=(0.0, 2.0),
748 lifetime=2.0,
749 scale=DEFAULT_SCALE
750 )
751 )
752 e.change_angle = 10.0
753 return emitter_37.__doc__, e
754
755
756def emitter_38():
757 """Use simple emitter interface to create a burst emitter"""
758 e = particles.make_burst_emitter(
759 center_xy=CENTER_POS,
760 filenames_and_textures=(TEXTURE, TEXTURE3, TEXTURE4),
761 particle_count=50,
762 particle_speed=2.5,
763 particle_lifetime_min=1.0,
764 particle_lifetime_max=2.5,
765 particle_scale=0.3,
766 fade_particles=True
767 )
768 return emitter_38.__doc__, e
769
770
771def emitter_39():
772 """Use simple emitter interface to create an interval emitter"""
773 e = particles.make_interval_emitter(
774 center_xy=CENTER_POS,
775 filenames_and_textures=(TEXTURE, TEXTURE3, TEXTURE4),
776 emit_interval=0.01,
777 emit_duration=2.0,
778 particle_speed=1.5,
779 particle_lifetime_min=1.0,
780 particle_lifetime_max=3.0,
781 particle_scale=0.2,
782 fade_particles=True
783 )
784 return emitter_39.__doc__, e
785
786
787class GameView(arcade.View):
788 def __init__(self):
789 super().__init__()
790
791 self.background_color = arcade.color.BLACK
792
793 # collect particle factory functions
794 self.factories = [v for k, v in globals().items() if k.startswith("emitter_")]
795
796 self.emitter_factory_id = -1
797 self.label = None
798 self.emitter = None
799 self.emitter_timeout = 0
800 self.obj = arcade.Sprite(
801 ":resources:images/pinball/bumper.png",
802 scale=0.2,
803 center_x=0,
804 center_y=15,
805 )
806 self.obj.change_x = 3
807 pyglet.clock.schedule_once(self.next_emitter, QUIET_BETWEEN_SPAWNS)
808
809 def next_emitter(self, _time_delta):
810 self.emitter_factory_id = (self.emitter_factory_id + 1) % len(self.factories)
811 print("Changing emitter to {}".format(self.emitter_factory_id))
812 self.emitter_timeout = 0
813 self.label, self.emitter = self.factories[self.emitter_factory_id]()
814
815 def on_update(self, delta_time):
816 if self.emitter:
817 self.emitter_timeout += 1
818 self.emitter.update(delta_time)
819 if self.emitter.can_reap() or self.emitter_timeout > EMITTER_TIMEOUT:
820 pyglet.clock.schedule_once(self.next_emitter, QUIET_BETWEEN_SPAWNS)
821 self.emitter = None
822 self.obj.update(delta_time)
823 if self.obj.center_x > WINDOW_WIDTH:
824 self.obj.center_x = 0
825
826 def on_draw(self):
827 self.clear()
828 arcade.draw_sprite(self.obj)
829 if self.label:
830 arcade.draw_text("#{} {}".format(self.emitter_factory_id, self.label),
831 WINDOW_WIDTH / 2, WINDOW_HEIGHT - 25,
832 arcade.color.PALE_GOLD, 20, width=WINDOW_WIDTH,
833 anchor_x="center")
834 if self.emitter:
835 self.emitter.draw()
836 arcade.draw_text(
837 "Particles: " + str(self.emitter.get_count()),
838 x=10,
839 y=30,
840 color=arcade.color.PALE_GOLD,
841 font_size=12,
842 )
843
844 def on_key_press(self, key, modifiers):
845 if key == arcade.key.ESCAPE:
846 arcade.close_window()
847
848
849def main():
850 """ Main function """
851 # Create a window class. This is what actually shows up on screen
852 window = arcade.Window(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
853
854 # Create the GameView
855 game = GameView()
856
857 # Show GameView on screen
858 window.show_view(game)
859
860 # Start the arcade game loop
861 arcade.run()
862
863
864if __name__ == "__main__":
865 main()