From b422cd4621bf288aec6b778c127511eb9f1dc1c1 Mon Sep 17 00:00:00 2001 From: OusmBlueNinja <89956790+OusmBlueNinja@users.noreply.github.com> Date: Fri, 21 Feb 2025 13:38:59 -0600 Subject: [PATCH] fireeeee --- __pycache__/particle.cpython-311.pyc | Bin 0 -> 8674 bytes main.py | 95 ++++++++++++++++----------- particle.py | 92 +++++++++++++++----------- 3 files changed, 109 insertions(+), 78 deletions(-) create mode 100644 __pycache__/particle.cpython-311.pyc diff --git a/__pycache__/particle.cpython-311.pyc b/__pycache__/particle.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd7a2be09a39d0da589f72e843346b12ebae9d4b GIT binary patch literal 8674 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 literal 0 HcmV?d00001 diff --git a/main.py b/main.py index 6a755c0..ccd4ff0 100644 --- a/main.py +++ b/main.py @@ -3,59 +3,74 @@ import random from particle import Particle pygame.init() - -# Set up display and clock. screen = pygame.display.set_mode((800, 600)) -pygame.display.set_caption("Particle Test") +pygame.display.set_caption("Fireplace Simulation") clock = pygame.time.Clock() particles = [] +# Define the fireplace area (a simple rectangle to simulate a brick fireplace) +fireplace_rect = pygame.Rect(300, 400, 200, 200) # x, y, width, height + running = True while running: - dt = clock.tick(60) / 1000.0 # Delta time in seconds. + dt = clock.tick() / 1000.0 # Delta time in seconds - # Event loop: quit on window close or spawn new particles on mouse click. for event in pygame.event.get(): if event.type == pygame.QUIT: running = False - elif event.type == pygame.MOUSEBUTTONDOWN: - # Create several particles at the mouse position. - for _ in range(10): - pos = pygame.mouse.get_pos() - vel = (random.uniform(-100, 100), random.uniform(-100, 100)) - p = Particle( - pos=pos, - vel=vel, - acceleration=(0, 0), - lifetime=2.0, - decay_rate=1, - color=( - random.randint(100, 255), - random.randint(100, 255), - random.randint(100, 255) - ), - size=5, - size_decay=2, - glow=True, - glow_intensity=1.0, - friction=0.1, - gravity=50, - bounce=True, - bounce_damping=0.7, - random_spread=10, - spin=0, - spin_rate=random.uniform(-180, 180), - spin_decay=0.5, - trail=True, - trail_length=15, - fade=True, - shape='circle' - ) - particles.append(p) # Clear the screen. screen.fill((0, 0, 0)) + + # Draw the fireplace background: + # Fill with a dark brick color and draw a border to simulate the fireplace frame. + # pygame.draw.rect(screen, (70, 20, 20), fireplace_rect) # Fireplace interior + # pygame.draw.rect(screen, (150, 50, 50), fireplace_rect, 5) # Fireplace border + + # Determine a random fire origin along the bottom edge inside the fireplace. + + + # Spawn fire particles from the fire origin. + particles_to_spawn = (16000 - len(particles)) + + + + for _ in range(particles_to_spawn): + fire_origin = ( + random.uniform(0, 800), + 600 + ) + fire_particle = Particle( + pos=(fire_origin[0] + random.uniform(-5, 5), fire_origin[1] + random.uniform(-2, 2)), + vel=(random.uniform(-20, 20), random.uniform(-80, -120)), # Upward motion + lifetime=1.5, + decay_rate=1, + size=random.uniform(5, 8), + size_decay=5, + glow=True, + glow_intensity=1.0, + friction=0.05, + gravity=-30, # Negative gravity makes the particle rise + fade=True, + particle_type="fire" + ) + particles.append(fire_particle) + + # smoke_particle = Particle( + # pos=(fire_origin[0] + random.uniform(-10, 10), fire_origin[1] + random.uniform(-2, 2)), + # vel=(random.uniform(-10, 10), random.uniform(-40, -60)), # Slower upward motion + # lifetime=2.5, + # decay_rate=0.8, + # size=random.uniform(8, 12), + # size_decay=1, + # glow=False, + # friction=0.02, + # gravity=-10, + # fade=True, + # particle_type="smoke" + # ) + # particles.append(smoke_particle) # Update and draw each particle. for particle in particles[:]: @@ -63,7 +78,7 @@ while running: particle.draw(screen) if particle.is_dead(): particles.remove(particle) - + pygame.display.flip() pygame.quit() diff --git a/particle.py b/particle.py index 711123a..3bde614 100644 --- a/particle.py +++ b/particle.py @@ -1,6 +1,5 @@ import pygame import random -import math class Particle: def __init__( @@ -8,15 +7,15 @@ class Particle: pos, vel=(0, 0), acceleration=(0, 0), - lifetime=2.0, # seconds the particle lives - decay_rate=1, # how fast the lifetime decreases + lifetime=1.0, # seconds the particle lives + decay_rate=1.0, # how fast the lifetime decreases color=(255, 255, 255), size=5, - size_decay=0, # rate at which the size decreases + size_decay=5, # rate at which the size decreases glow=False, glow_intensity=0, # multiplier for glow radius - friction=0, # slows down velocity over time - gravity=0, # constant acceleration downward + friction=0.05, # slows down velocity over time + gravity=0, # constant acceleration (negative makes it rise) bounce=False, bounce_damping=0.5, # energy loss when bouncing off boundaries random_spread=0, # randomness added to velocity each update @@ -25,20 +24,19 @@ class Particle: spin_decay=0, # how spin_rate slows down trail=False, trail_length=10, # how many previous positions to store - fade=False, # if True, the particle will fade (alpha decreases) - shape='circle' # could be 'circle' or 'square' + fade=True, # if True, the particle will fade (alpha decreases) + shape='circle', # could be 'circle' or 'square' + particle_type="generic" # "fire" or "smoke" ): - # Position, velocity, and acceleration are stored as vectors. + # Position, velocity, and acceleration as vectors. self.pos = pygame.math.Vector2(pos) self.vel = pygame.math.Vector2(vel) self.acceleration = pygame.math.Vector2(acceleration) - # Lifetime and decay self.lifetime = lifetime self.initial_lifetime = lifetime self.decay_rate = decay_rate - # Appearance settings self.color = color self.size = size self.initial_size = size @@ -46,7 +44,6 @@ class Particle: self.fade = fade self.alpha = 255 - # Effects options self.glow = glow self.glow_intensity = glow_intensity self.friction = friction @@ -55,44 +52,61 @@ class Particle: self.bounce_damping = bounce_damping self.random_spread = random_spread - # Spin (if using rotated images or shapes) self.spin = spin self.spin_rate = spin_rate self.spin_decay = spin_decay - # Trail settings: stores previous positions to create a trailing effect self.trail = trail self.trail_length = trail_length self.positions = [self.pos.copy()] if trail else [] - # Shape of the particle ('circle' or 'square') self.shape = shape + # Particle type for specialized behavior. + self.particle_type = particle_type + def update(self, dt, screen_rect): - """ - dt: Delta time in seconds. - screen_rect: The rectangle representing screen boundaries (for bounce). - """ - # Decrease lifetime + # Decrease lifetime. self.lifetime -= self.decay_rate * dt if self.lifetime < 0: self.lifetime = 0 - # Add random variation to velocity if enabled. + # Compute life ratio (1 at birth, 0 at death). + life_ratio = self.lifetime / self.initial_lifetime if self.initial_lifetime else 0 + + # Update color based on particle type. + if self.particle_type == "fire": + # Realistic fire uses a multi-stage color gradient: + # At birth: bright white-yellow, mid-life: vivid orange, end: dark red. + if life_ratio > 0.5: + factor = (life_ratio - 0.5) / 0.5 # factor from 1 to 0 as life_ratio goes from 1 -> 0.5 + r = 255 + g = int(255 * factor + 180 * (1 - factor)) + b = int(240 * factor + 50 * (1 - factor)) + else: + factor = life_ratio / 0.5 # factor from 1 to 0 as life_ratio goes from 0.5 -> 0 + r = int(255 * factor + 150 * (1 - factor)) + g = int(180 * factor) + b = int(50 * factor) + self.color = (r, g, b) + elif self.particle_type == "smoke": + # Smoke transitions from a semi-transparent dark gray to a light gray. + start_shade = 100 + end_shade = 230 + shade = int(start_shade * life_ratio + end_shade * (1 - life_ratio)) + self.color = (shade, shade, shade) + + # Optionally add random spread. if self.random_spread: self.vel.x += random.uniform(-self.random_spread, self.random_spread) * dt self.vel.y += random.uniform(-self.random_spread, self.random_spread) * dt - # Apply gravity (as an extra acceleration on the y-axis) + # Apply gravity (negative gravity makes particles rise). self.acceleration.y += self.gravity - # Update velocity using acceleration. + # Update velocity and position. self.vel += self.acceleration * dt - - # Apply friction to slow the particle over time. self.vel *= (1 - self.friction * dt) - - # Update the position based on velocity. self.pos += self.vel * dt # Bounce off screen edges if enabled. @@ -110,55 +124,57 @@ class Particle: elif self.pos.y + self.size > screen_rect.bottom: self.pos.y = screen_rect.bottom - self.size - # Update spin + # Update spin. self.spin += self.spin_rate * dt self.spin_rate *= (1 - self.spin_decay * dt) - # Decrease size if size_decay is set. + # Decrease size. if self.size_decay: self.size = max(0, self.size - self.size_decay * dt) - # Fade out by decreasing alpha based on lifetime. + # Fade out by adjusting alpha. if self.fade: - self.alpha = int(255 * (self.lifetime / self.initial_lifetime)) + self.alpha = int(255 * life_ratio) if self.alpha < 0: self.alpha = 0 - # Update trail history. + # Update trail positions if enabled. if self.trail: self.positions.append(self.pos.copy()) if len(self.positions) > self.trail_length: self.positions.pop(0) + # Reset acceleration for next update. + self.acceleration = pygame.math.Vector2(0, 0) + def draw(self, surface): - # Set drawing color with alpha if fading. + # Apply alpha to color if fading. if self.fade: draw_color = (*self.color, self.alpha) else: draw_color = self.color - # Draw the particle's trail if enabled. + # Optionally draw a trail. if self.trail and len(self.positions) > 1: for i in range(1, len(self.positions)): start = self.positions[i - 1] end = self.positions[i] pygame.draw.line(surface, draw_color, start, end, int(self.size)) - # Draw glow effect if enabled. + # Optionally draw glow. if self.glow: glow_radius = int(self.size * (1 + self.glow_intensity)) - glow_color = (*self.color, self.alpha) if self.fade else self.color + glow_color = (*self.color, self.alpha) glow_surface = pygame.Surface((glow_radius * 2, glow_radius * 2), pygame.SRCALPHA) pygame.draw.circle(glow_surface, glow_color, (glow_radius, glow_radius), glow_radius) surface.blit(glow_surface, (self.pos.x - glow_radius, self.pos.y - glow_radius), special_flags=pygame.BLEND_ADD) - # Draw the particle shape. + # Draw the particle (default is circle). if self.shape == 'circle': pygame.draw.circle(surface, draw_color, (int(self.pos.x), int(self.pos.y)), int(self.size)) elif self.shape == 'square': rect = pygame.Rect(self.pos.x - self.size, self.pos.y - self.size, self.size * 2, self.size * 2) pygame.draw.rect(surface, draw_color, rect) - # Additional shapes (e.g., triangles, rotated images) can be added here. def is_dead(self): """Return True if the particle should be removed."""