diff --git a/only-particles-game/main.py b/only-particles-game/main.py new file mode 100644 index 0000000..69baecb --- /dev/null +++ b/only-particles-game/main.py @@ -0,0 +1,218 @@ +import pygame +import math +import random + +# Initialize pygame +pygame.init() + +# Screen dimensions +WIDTH, HEIGHT = 800, 600 +SCREEN = pygame.display.set_mode((WIDTH, HEIGHT)) +pygame.display.set_caption("Neon Breaker with Particles") + +# Colors (RGB) +BLACK = (0, 0, 0) +NEON_BLUE = (50, 255, 255) +NEON_PINK = (255, 50, 255) +NEON_GREEN = (50, 255, 50) + +money = 0 + +# Helper function to draw a neon glow circle using multiple layers +def draw_neon_circle(surface, color, center, radius, glow_layers=10): + for i in range(glow_layers, 0, -1): + # Calculate alpha for the glow (decreases with each layer) + alpha = max(10, int(255 * (i / glow_layers) * 0.5)) + glow_color = (*color, alpha) + glow_radius = radius + i + temp_surface = pygame.Surface((glow_radius * 2, glow_radius * 2), pygame.SRCALPHA) + pygame.draw.circle(temp_surface, glow_color, (glow_radius, glow_radius), glow_radius) + surface.blit(temp_surface, (center[0] - glow_radius, center[1] - glow_radius)) + pygame.draw.circle(surface, color, center, radius) + +# Helper function to draw a neon glow rectangle +def draw_neon_rect(surface, color, rect, glow_layers=8): + for i in range(glow_layers, 0, -1): + alpha = max(10, int(255 * (i / glow_layers) * 0.5)) + glow_color = (*color, alpha) + temp_rect = rect.inflate(i * 2, i * 2) + temp_surface = pygame.Surface((temp_rect.width, temp_rect.height), pygame.SRCALPHA) + pygame.draw.rect(temp_surface, glow_color, (0, 0, temp_rect.width, temp_rect.height), border_radius=4) + surface.blit(temp_surface, temp_rect.topleft) + pygame.draw.rect(surface, color, rect, border_radius=4) + +# Particle class: updated using dt, with fading effect +class Particle: + def __init__(self, x, y, angle, speed, lifetime, color, size): + self.x = x + self.y = y + self.angle = angle # in radians + self.speed = speed # pixels per second + self.lifetime = lifetime # seconds + self.color = color + self.size = size # initial size + + def update(self, dt): + # Move particle using dt + self.x += math.cos(self.angle) * self.speed * dt + self.y += math.sin(self.angle) * self.speed * dt + self.lifetime -= dt + + def draw(self, surface): + if self.lifetime > 0: + # Compute fade effect: size and brightness fade with remaining lifetime + fade = max(0, self.lifetime) + current_size = max(1, int(self.size * (fade))) + # Draw with the neon glow effect. + draw_neon_circle(surface, self.color, (int(self.x), int(self.y)), current_size, glow_layers=4) + +# Particle system to manage all particles +class ParticleSystem: + def __init__(self): + self.particles = [] + + def add_explosion(self, x, y, count, base_speed, lifetime, color, size): + for _ in range(count): + angle = random.uniform(0, 2 * math.pi) + speed = random.uniform(0.5 * base_speed, base_speed) + # lifetime is given in seconds; each particle will have a slightly variable lifetime + part_lifetime = random.uniform(0.5 * lifetime, lifetime) + self.particles.append(Particle(x, y, angle, speed, part_lifetime, color, size)) + + def update(self, dt): + for p in self.particles: + p.update(dt) + # Remove dead particles + self.particles = [p for p in self.particles if p.lifetime > 0] + + def draw(self, surface): + for p in self.particles: + p.draw(surface) + +# Ball class: uses dt in its movement and adds a neon glow. +class Ball: + def __init__(self, x, y, radius=10, color=NEON_BLUE): + self.x = x + self.y = y + self.radius = radius + self.color = color + self.vx = random.choice([-200, 200]) # pixels per second + self.vy = random.choice([-200, 200]) # pixels per second + + def update(self, dt): + self.x += self.vx * dt + self.y += self.vy * dt + + # Bounce off the walls + if self.x - self.radius <= 0 or self.x + self.radius >= WIDTH: + self.vx *= -1 + self.x = max(self.radius, min(WIDTH - self.radius, self.x)) + if self.y - self.radius <= 0 or self.y + self.radius >= HEIGHT: + self.vy *= -1 + self.y = max(self.radius, min(HEIGHT - self.radius, self.y)) + + def draw(self, surface): + draw_neon_circle(surface, self.color, (int(self.x), int(self.y)), self.radius) + + def get_rect(self): + return pygame.Rect(self.x - self.radius, self.y - self.radius, + self.radius * 2, self.radius * 2) + +# Block class with dt-independent health and neon visuals. +class Block: + def __init__(self, x, y, width=80, height=30, health=3, color=NEON_PINK): + self.rect = pygame.Rect(x, y, width, height) + self.max_health = health + self.health = health + self.color = color + + def draw(self, surface): + intensity = self.health / self.max_health + mod_color = (int(self.color[0] * intensity), + int(self.color[1] * intensity), + int(self.color[2] * intensity)) + draw_neon_rect(surface, mod_color, self.rect) + + def hit(self, damage): + self.health -= damage + if self.health < 0: + self.health = 0 + + def is_destroyed(self): + return self.health <= 0 + +def main(): + global money + clock = pygame.time.Clock() + particle_system = ParticleSystem() + running = True + + # Create a neon ball at the center. + ball = Ball(WIDTH // 2, HEIGHT // 2) + + # Create blocks in a grid layout. + blocks = [] + rows, cols = 3, 7 + padding = 10 + block_width = (WIDTH - (cols + 1) * padding) // cols + block_height = 30 + for row in range(rows): + for col in range(cols): + x = padding + col * (block_width + padding) + y = padding + row * (block_height + padding) + blocks.append(Block(x, y, block_width, block_height, health=3, color=NEON_PINK)) + + font = pygame.font.SysFont("Arial", 24) + + while running: + # Calculate delta time in seconds. + dt = clock.tick() / 1000.0 + + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + + # Update game objects using dt. + ball.update(dt) + particle_system.update(dt) + + # Collision check between ball and blocks. + ball_rect = ball.get_rect() + for block in blocks[:]: + if ball_rect.colliderect(block.rect): + # Reflect the ball vertically. + ball.vy *= -1 + + # Add particle explosion at collision point. + collision_x = ball.x + collision_y = ball.y + particle_system.add_explosion(collision_x, collision_y, count=20, + base_speed=150, lifetime=0.5, + color=NEON_GREEN, size=4) + + # Damage the block. + block.hit(1) + # When block is destroyed, add additional particle explosion. + if block.is_destroyed(): + money += 10 + particle_system.add_explosion(block.rect.centerx, block.rect.centery, + count=40, base_speed=200, lifetime=0.7, + color=NEON_PINK, size=6) + blocks.remove(block) + # Stop checking after one collision per frame. + break + + # Draw everything. + SCREEN.fill(BLACK) + ball.draw(SCREEN) + for block in blocks: + block.draw(SCREEN) + particle_system.draw(SCREEN) + money_text = font.render(f"Money: ${money}", True, NEON_GREEN) + SCREEN.blit(money_text, (10, HEIGHT - 40)) + pygame.display.flip() + + pygame.quit() + +if __name__ == "__main__": + main()