import pygame import random import math # Initialize pygame pygame.init() # Screen dimensions and panel sizes WIDTH, HEIGHT = 800, 600 PANEL_HEIGHT = 150 # Bottom panel for sliders SIM_HEIGHT = HEIGHT - PANEL_HEIGHT # Simulation area height screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("Particle Simulation with Adjustable Variables") clock = pygame.time.Clock() # Define a simple Slider class class Slider: def __init__(self, x, y, w, h, min_val, max_val, init_val, label): self.x = x self.y = y self.w = w self.h = h self.min_val = min_val self.max_val = max_val self.value = init_val self.label = label self.dragging = False def handle_event(self, event): if event.type == pygame.MOUSEBUTTONDOWN: if event.button == 1: if self.get_knob_rect().collidepoint(event.pos): self.dragging = True elif event.type == pygame.MOUSEBUTTONUP: if event.button == 1: self.dragging = False elif event.type == pygame.MOUSEMOTION: if self.dragging: mx = event.pos[0] # Clamp mx inside slider range relative = (mx - self.x) / self.w relative = max(0, min(1, relative)) self.value = self.min_val + relative * (self.max_val - self.min_val) def get_knob_rect(self): # Determine knob position along slider track relative = (self.value - self.min_val) / (self.max_val - self.min_val) knob_x = self.x + relative * self.w knob_width = 10 knob_height = self.h return pygame.Rect(knob_x - knob_width // 2, self.y, knob_width, knob_height) def draw(self, surface, font): # Draw slider track (a thin rectangle) track_rect = pygame.Rect(self.x, self.y + self.h // 2 - 2, self.w, 4) pygame.draw.rect(surface, (200, 200, 200), track_rect) # Draw knob knob_rect = self.get_knob_rect() pygame.draw.rect(surface, (100, 100, 100), knob_rect) # Draw label and current value (as plain text) label_surface = font.render(f"{self.label}: {self.value:.2f}", True, (0, 0, 0)) surface.blit(label_surface, (self.x, self.y - 20)) # Particle class class Particle: def __init__(self, pos, velocity, lifetime, size, color=(255, 255, 255)): self.pos = pygame.math.Vector2(pos) self.vel = pygame.math.Vector2(velocity) self.lifetime = lifetime self.size = size self.initial_lifetime = lifetime self.color = color def update(self, gravity): self.vel.y += gravity self.pos += self.vel self.lifetime -= 1 def is_dead(self): return self.lifetime <= 0 def draw(self, surface, glow_intensity): # Draw glow effect if glow_intensity is greater than zero if glow_intensity > 0: # Create a temporary surface for glow with per-pixel alpha glow_surface = pygame.Surface((self.size*6, self.size*6), pygame.SRCALPHA) glow_center = self.size * 3 # Draw several concentric circles for the glow effect for i in range(1, 6): # Alpha decreases as the circle radius increases alpha = max(0, int(255 * (glow_intensity / 10) * (1 - i/6))) radius = int(self.size + i * 2) pygame.draw.circle(glow_surface, (self.color[0], self.color[1], self.color[2], alpha), (glow_center, glow_center), radius) # Blit the glow surface with additive blending surface.blit(glow_surface, (self.pos.x - self.size*3, self.pos.y - self.size*3), special_flags=pygame.BLEND_RGBA_ADD) # Draw the particle itself pygame.draw.circle(surface, self.color, (int(self.pos.x), int(self.pos.y)), int(self.size)) # Create sliders for each variable, arranged in two rows within the bottom panel. font = pygame.font.SysFont("Arial", 16) sliders = [] # Row 1: Emission Rate, Speed, Lifetime sliders.append(Slider(x=20, y=SIM_HEIGHT + 10, w=200, h=20, min_val=0, max_val=50, init_val=5, label="Emission Rate")) sliders.append(Slider(x=240, y=SIM_HEIGHT + 10, w=200, h=20, min_val=0, max_val=10, init_val=5, label="Speed")) sliders.append(Slider(x=460, y=SIM_HEIGHT + 10, w=200, h=20, min_val=10, max_val=300, init_val=100, label="Lifetime")) # Row 2: Size, Gravity, Glow sliders.append(Slider(x=20, y=SIM_HEIGHT + 50, w=200, h=20, min_val=1, max_val=20, init_val=5, label="Size")) sliders.append(Slider(x=240, y=SIM_HEIGHT + 50, w=200, h=20, min_val=0, max_val=2, init_val=0.1, label="Gravity")) sliders.append(Slider(x=460, y=SIM_HEIGHT + 50, w=200, h=20, min_val=0, max_val=10, init_val=3, label="Glow")) # List to hold all particles particles = [] # Emitter position (center of simulation area) emitter = pygame.math.Vector2(WIDTH // 2, SIM_HEIGHT // 2) # Main loop running = True while running: # Process events (for quitting and slider events) for event in pygame.event.get(): if event.type == pygame.QUIT: running = False for slider in sliders: slider.handle_event(event) # Get simulation variables from slider values emission_rate = sliders[0].value # particles per frame speed = sliders[1].value # initial speed magnitude lifetime = sliders[2].value # lifetime in frames size = sliders[3].value # particle size (radius) gravity = sliders[4].value # gravity acceleration glow = sliders[5].value # glow intensity # Spawn new particles (round emission_rate to an integer count) for _ in range(int(emission_rate)): # Spawn at the emitter with a random direction angle = random.uniform(0, 2 * math.pi) velocity = pygame.math.Vector2(math.cos(angle), math.sin(angle)) * speed particles.append(Particle(emitter, velocity, lifetime, size)) # Update particles and remove dead ones for particle in particles[:]: particle.update(gravity) if particle.is_dead(): particles.remove(particle) # Clear simulation area (fill with black) screen.fill((0, 0, 0), rect=pygame.Rect(0, 0, WIDTH, SIM_HEIGHT)) # Optionally fill the control area with a light color (or leave it as is) screen.fill((220, 220, 220), rect=pygame.Rect(0, SIM_HEIGHT, WIDTH, PANEL_HEIGHT)) # Draw all particles for particle in particles: particle.draw(screen, glow_intensity=glow) # Draw slider controls in the bottom panel for slider in sliders: slider.draw(screen, font) # Draw debug text (plain text, no background) at the top-left corner of the simulation area debug_text = (f"Particles: {len(particles)} | Emission Rate: {emission_rate:.2f} | Speed: {speed:.2f} | " f"Lifetime: {lifetime:.2f} | Size: {size:.2f} | Gravity: {gravity:.2f} | Glow: {glow:.2f}") debug_surface = font.render(debug_text, True, (255, 255, 255)) screen.blit(debug_surface, (10, 10)) pygame.display.flip() clock.tick(60) pygame.quit()