Guest User

Particles

a guest
Feb 14th, 2025
21
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.22 KB | None | 0 0
  1. import random
  2. from dataclasses import dataclass
  3.  
  4. import pygame
  5.  
  6. PARTICLE_COLORS = [tuple(color[:3]) for color in list(pygame.color.THECOLORS.values())]
  7. GLOW_SHRINK_RATE = 0.15
  8. GLOW_STARTING_RADIUS = 30.0
  9. BLUR_RADIUS = 5
  10. GRAVITY = 0.015
  11.  
  12.  
  13. @dataclass(slots=True)
  14. class Particle:
  15.     position: pygame.Vector2
  16.     direction: pygame.Vector2
  17.     color: tuple
  18.     radius: float = 5.0
  19.     glow_radius: float = GLOW_STARTING_RADIUS
  20.     float_duration: float = 0.1
  21.     speed: int = 100
  22.     alive: bool = True
  23.  
  24.  
  25. def create_background(surface):
  26.     rectangle_colors = [
  27.         ["red", "black", "skyblue"],
  28.         ["black", "green", "white"],
  29.         ["grey", "black", "blue"]
  30.     ]
  31.     margin = 50
  32.     background_surface = surface.copy()
  33.     rectangle_width = (background_surface.get_width() - (margin * 2)) // len(rectangle_colors[0])
  34.     rectangle_height = (background_surface.get_height() - (margin * 2)) // len(rectangle_colors)
  35.  
  36.     for y, colors in enumerate(rectangle_colors):
  37.         for x, color in enumerate(colors):
  38.             rect = pygame.Rect(
  39.                 (x * rectangle_width + margin, y * rectangle_height + margin),
  40.                 (rectangle_width, rectangle_height)
  41.             )
  42.             pygame.draw.rect(background_surface, pygame.Color(color).lerp("black", 0.7), rect, 0)
  43.  
  44.     return background_surface
  45.  
  46.  
  47. class ImageCache:
  48.     def __init__(self):
  49.         self.cache = {}
  50.         self.blurred_cache = {}
  51.  
  52.         self._render_glow_surface()
  53.  
  54.     def _render_glow_surface(self):
  55.         steps = int(GLOW_STARTING_RADIUS / GLOW_SHRINK_RATE)
  56.         glow_radii = [GLOW_STARTING_RADIUS - i * GLOW_SHRINK_RATE for i in range(steps)]
  57.         alpha_value = 150
  58.         color = (*[255] * 3, alpha_value)
  59.  
  60.         for radius in glow_radii:
  61.             size = [radius * 5] * 2
  62.             base_surface = pygame.Surface(size, flags=pygame.SRCALPHA)
  63.             glow_surface = base_surface.copy()
  64.             glow_surface.set_colorkey("black")
  65.  
  66.             center = base_surface.get_rect().center
  67.             pygame.draw.circle(glow_surface, color, center, radius)
  68.             pygame.transform.gaussian_blur(
  69.                 glow_surface,
  70.                 BLUR_RADIUS,
  71.                 repeat_edge_pixels=False,
  72.                 dest_surface=base_surface
  73.             )
  74.             self.store_blurred(radius, base_surface)
  75.  
  76.     def store_blurred(self, glow_radius, surface):
  77.         key = round(glow_radius, 2)
  78.         self.blurred_cache[key] = surface
  79.  
  80.     def get_surface(self, glow_radius, color):
  81.         key = round(glow_radius, 2), color
  82.         if key not in self.cache:
  83.             blurred_cache = round(glow_radius, 2)
  84.             glow_surface = self.blurred_cache[blurred_cache]
  85.             colored_surface = glow_surface.copy()
  86.             colored_surface.fill(color)
  87.             colored_surface.blit(glow_surface, (0, 0), special_flags=pygame.BLEND_RGB_MULT)
  88.  
  89.             # return colored_surface  # Less caching
  90.             self.cache[key] = colored_surface
  91.  
  92.         return self.cache[key]
  93.  
  94.     def __len__(self):
  95.         return len(self.cache.keys())
  96.  
  97.  
  98. class ParticleManager:
  99.     def __init__(self):
  100.         self.particles = []
  101.  
  102.     def update_particles(self, delta_time):
  103.         for particle in self.particles[:]:
  104.             particle.float_duration -= delta_time
  105.             if particle.float_duration <= 0:
  106.                 particle.direction.y += GRAVITY
  107.  
  108.             particle.radius -= 0.03
  109.             particle.glow_radius -= 0.15
  110.  
  111.             particle.position += particle.direction * particle.speed * delta_time
  112.  
  113.             if particle.glow_radius <= 1.0:
  114.                 particle.alive = False
  115.                 self.particles.remove(particle)
  116.  
  117.     def emit_particles(self, particle_count=1):
  118.         position = pygame.mouse.get_pos()
  119.  
  120.         for count in range(particle_count):
  121.             color = random.choice(PARTICLE_COLORS)
  122.             particle = Particle(
  123.                 pygame.Vector2(position), pygame.Vector2(random.uniform(-1, 1), -1), color=color
  124.             )
  125.             self.particles.append(particle)
  126.  
  127.     def draw_particle(self, surface, image_cache):
  128.         for particle in self.particles:
  129.             glow_surface = image_cache.get_surface(particle.glow_radius, particle.color)
  130.             center = glow_surface.get_rect(center=particle.position)
  131.             pygame.draw.circle(surface, particle.color, particle.position, particle.radius)
  132.             surface.blit(glow_surface, center, special_flags=pygame.BLEND_RGB_ADD)
  133.  
  134.  
  135. def main():
  136.     pygame.init()
  137.     display = pygame.display.set_mode((1500, 900))
  138.     clock = pygame.Clock()
  139.     background_surface = create_background(display)
  140.     debug_font = pygame.font.SysFont("Consolas", 12, bold=True)
  141.  
  142.     image_cache = ImageCache()
  143.     particle_manager = ParticleManager()
  144.  
  145.     elapsed_time = 0
  146.     fixed_delta_time = 1 / 60
  147.     delta_time = 0
  148.  
  149.     running = True
  150.     while running:
  151.         for event in pygame.event.get():
  152.             if event.type == pygame.QUIT:
  153.                 running = False
  154.  
  155.         particle_manager.emit_particles(particle_count=1)
  156.  
  157.         elapsed_time += delta_time
  158.         if elapsed_time >= fixed_delta_time:
  159.             elapsed_time = 0
  160.             particle_manager.update_particles(fixed_delta_time)
  161.  
  162.         debug_string = f"""\
  163.                Cache size: {len(image_cache)}
  164.                Glow cache size: {len(image_cache.blurred_cache)}
  165.                Colors: {len(PARTICLE_COLORS)}
  166.                Total particles: {len(particle_manager.particles)}
  167.                FPS: {clock.get_fps():.2f}
  168.                """
  169.         debug_surface = debug_font.render(debug_string, True, "white")
  170.         debug_shadow = debug_font.render(debug_string, True, "black")
  171.         mouse_position = pygame.mouse.get_pos()
  172.  
  173.         display.fill("black")
  174.         display.blit(background_surface, (0, 0))
  175.         particle_manager.draw_particle(display, image_cache)
  176.         display.blit(debug_shadow, (mouse_position[0] + 1, mouse_position[1]))
  177.         display.blit(debug_surface, mouse_position)
  178.         pygame.display.flip()
  179.         delta_time = clock.tick() / 1000
  180.  
  181.         pygame.display.set_caption(debug_string)
  182.  
  183.     pygame.quit()
  184.  
  185.  
  186. if __name__ == '__main__':
  187.     main()
  188.  
Add Comment
Please, Sign In to add comment