# Python Pygame Bouncing Balls with Particles

Oct 22nd, 2021
731
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
1. import pygame
2. from pygame import Rect
3. from pygame import Vector2
4. from random import randint, uniform
5.
6. # particle
7. class particle:
8.     def __init__(s, xy, vel): # xy = tuple(x, y)
9.         # position of the particle
10.         s.xy = Vector2(xy)
11.
12.         # particle velocity
13.         s.vel = vel #Vector2(uniform(-1, 1), uniform(-4.5, -5)) # x vel is betweem -1 & 1 and y vel is between -4.5 and -5
14.
16.         s.radius = randint(4, 8) # random integer between 5 & 15
17.
18.     # draw particle and update position/size
19.     def update(s):
20.         global PDS, WHITE # PDS = primary display surface
21.
22.         # draw particle
23.         pygame.draw.circle(PDS, (128, 128, 128), s.xy, s.radius)
24.
25.         # draw glow
26.         s.glow()
27.
28.         # add velocity to particle
29.         s.xy += s.vel
30.
31.         # add gravity to velocity. negative velocity will slowly become positive
32.         s.vel.y += GRAVITY
33.
34.         # decrease radius to give a fizzling out effect
36.
37.     def glow(s):
38.         global PDS
39.         # get rectangular size of the particle. radius * 2
41.
42.         # create a surface twice the size of the particle
43.         gs = pygame.Surface(r * 2)
44.
45.         # draw a circle with a radius twice the size of the particle in the center of the new surface
46.         pygame.draw.circle(gs, (60, 20, 60), r, r.x)
47.
48.         # blit the new larger particle on the primary display with the center of the smaller particle
49.         # use BLEND_RGB_ADD to increase luminosity if particles overlap
50.         PDS.blit(gs, s.xy - r, special_flags=pygame.BLEND_RGB_ADD)
51.
52. class ball:
53.     def __init__(s, xy, v):
54.         s.xy = xy
55.         s.v = v
56.
57.     def update(s):
59.
61.         nr = Rect(s.xy + s.v - (10, 10), (20, 20))
62.
63.         for o in OBSTICLES:
64.             if not o.colliderect(nr): continue
65.
66.             if nr.right >= o.left and r.right <= o.left:
67.                 r.right = o.left
68.                 s.v.x = -s.v.x
69.                 burst(r.midright, 1, 0)
70.             if nr.left <= o.right and r.left >= o.right:
71.                 r.left = o.right
72.                 s.v.x = -s.v.x
73.                 burst(r.midleft, 1, 1)
74.             if nr.bottom >= o.top and r.bottom <= o.top:
75.                 r.bottom = o.top
76.                 s.v.y = -s.v.y
77.                 burst(r.midbottom, 0, 0)
78.             if nr.top <= o.bottom and r.top >= o.bottom:
79.                 r.top = o.bottom
80.                 s.v.y = -s.v.y
81.                 burst(r.midbottom, 0, 1)
82.             s.xy = Vector2(r.center)
84.         s.xy += s.v
85.
86. def burst(xy, verticies, ricochet_direction):
87.     global PARTICLES
88.
89.     for i in range(20):
90.         if verticies == 0: # horizontal particle burst
91.             v = Vector2(uniform(-4, -2) if i // 10 else uniform(2, 4), uniform(1, 2) if ricochet_direction else uniform(-2, -1))
92.         else:
93.             v = Vector2(uniform(1, 2) if ricochet_direction else uniform(-2, -1), uniform(-4, -2) if i // 10 else uniform(2, 4))
94.         PARTICLES += [particle(xy, v)]
95.
96.
97. # initialise pygame and create primary display surface PDS
98. pygame.init()
99. PDR = Rect(0, 0, 1280, 720)
100. PDS = pygame.display.set_mode(PDR.size)
101.
102. # define some colors
103. BLACK = (0, 0, 0)
104. WHITE = (255, 255, 255)
105.
106. # strength of gravity
107. GRAVITY = 0.1
108.
109. # particle container
110. PARTICLES = []
111.
112. # obsticles
113. OBSTICLES = [
114.     Rect(0, 0, PDR.w, 20),
115.     Rect(0, 20, 20, PDR.h),
116.     Rect(20, PDR.h - 20, PDR.w - 20, 20),
117.     Rect(PDR.w - 20, 20, 20, PDR.h - 40),
118.     Rect(PDR.w / 3 - 10, 140, 20, PDR.h - 280),
119.     Rect(-10 + PDR.w - PDR.w / 3, 140, 20, PDR.h - 280),
120.     Rect(140, PDR.centery - 10, PDR.w / 3 - 270, 20),
121.     Rect(PDR.w - 300, PDR.centery - 10, PDR.w / 3 - 270, 20)
122. ]
123.
127. BALLS = [ball(Vector2(PDR.center), Vector2(5).rotate(d)) for d in range(0, 360, 20)]
128.
129. exitDemo = False
130. pause = False # press p to pause
131. while not exitDemo:
132.
133.     # handle the events
134.     events = pygame.event.get()
135.     for event in events:
136.         if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
137.             exitDemo = True
138.         if event.type == pygame.KEYDOWN and event.key == pygame.K_p:
139.             pause = 1 - pause
140.
141.     if pause: continue
142.
143.     # clear the PDS to black
144.     PDS.fill(BLACK)
145.
146.     for o in OBSTICLES:
147.         pygame.draw.rect(PDS, (60, 20, 60), o, 2)
148.
149.     for b in BALLS:
150.         b.update()
151.
152.     # create a container to hold particles that need deleting
153.     killParticles = []
154.     for p in PARTICLES:
155.         p.update() # draw and update postion/size of the particle
156.
157.         # if the particle is outside of the PDS or the radius is less than zero ie no longer visible
158.         # then add it the killparticles pile
159.         if p.xy.y >= PDR.bottom or p.radius <= 0:
160.             killParticles += [p]
161.
162.     # delete particles from particle container
163.     for p in killParticles:
164.         PARTICLES.remove(p)
165.
166.     # update the PDS
167.     pygame.display.update()
168.     pygame.time.Clock().tick(120) # limit FPS to 120
RAW Paste Data