Advertisement
cookertron

Python Pygame Bouncing Balls with Particles

Oct 22nd, 2021
988
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.33 KB | None | 0 0
  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.  
  15.         # particle radius
  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
  35.         s.radius -= 0.1
  36.  
  37.     def glow(s):
  38.         global PDS
  39.         # get rectangular size of the particle. radius * 2
  40.         r = Vector2(s.radius) * 2 # r = (radius * 2, 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):
  58.         global OBSTICLES, BALL_RADIUS, BALL_RADIUS_V, BALL_RADIUS2_V
  59.  
  60.         r = Rect(s.xy - BALL_RADIUS_V, BALL_RADIUS2_V)
  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)
  83.         pygame.draw.circle(PDS, WHITE, s.xy, BALL_RADIUS)
  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.  
  124. BALL_RADIUS = 10
  125. BALL_RADIUS_V = Vector2(BALL_RADIUS)
  126. BALL_RADIUS2_V = BALL_RADIUS_V * 2
  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
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement