import pygame import sys import math import random # Initialize pygame.init() WIDTH, HEIGHT = 1000, 700 screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("🌌 Realistic Black Hole Simulation") clock = pygame.time.Clock() FPS = 60 # Colors BLACK = (0, 0, 0) DEEP_SPACE = (5, 5, 20) PURPLE = (200, 0, 255) STAR_COLOR = (200, 200, 255) TRAIL_COLOR = (150, 0, 255) EVENT_HORIZON_COLOR = (255, 50, 200) GLOW_COLOR = (255, 100, 255) NEBULA_COLORS = [(40, 0, 70), (70, 0, 120), (110, 0, 160)] # Sound (optional) try: absorb_sound = pygame.mixer.Sound("absorb.wav") except: absorb_sound = None # Black hole settings blackhole_radius = 35 event_horizon_offset = 25 gravity_strength = 0.75 growth_rate = 0.05 # Stars background stars = [( random.randint(0, WIDTH), random.randint(0, HEIGHT), random.randint(1, 3), random.uniform(0.01, 0.03) ) for _ in range(150)] # Particle class class Particle: def __init__(self): angle = random.uniform(0, 2 * math.pi) distance = random.uniform(250, 500) self.pos = pygame.Vector2( WIDTH // 2 + math.cos(angle) * distance, HEIGHT // 2 + math.sin(angle) * distance ) self.vel = pygame.Vector2(-math.sin(angle), math.cos(angle)) * 2.2 self.color = PURPLE self.radius = 2 self.alive = True self.trail = [] self.fading = False self.opacity = 255 def update(self, bh_pos): global blackhole_radius, absorbed_particles to_bh = bh_pos - self.pos distance = to_bh.length() if distance < blackhole_radius + event_horizon_offset and not self.fading: self.fading = True if absorb_sound: absorb_sound.play() if self.fading: self.opacity -= 10 if self.opacity <= 0: self.alive = False blackhole_radius += growth_rate absorbed_particles += 1 return if distance != 0: to_bh.normalize_ip() self.vel += to_bh * (gravity_strength / (distance / 50)) self.pos += self.vel self.trail.append(self.pos.copy()) if len(self.trail) > 10: self.trail.pop(0) def draw(self, surface, draw_trail=True): if self.alive: if draw_trail: for i, pos in enumerate(self.trail): alpha = max(0, self.opacity - i * 25) trail_surf = pygame.Surface((4, 4), pygame.SRCALPHA) pygame.draw.circle(trail_surf, (*TRAIL_COLOR, alpha), (2, 2), 2) surface.blit(trail_surf, (int(pos.x) - 2, int(pos.y) - 2)) glow = pygame.Surface((10, 10), pygame.SRCALPHA) pygame.draw.circle(glow, (*GLOW_COLOR, min(100, self.opacity)), (5, 5), 5) surface.blit(glow, (int(self.pos.x) - 5, int(self.pos.y) - 5)) color = (*self.color[:3], self.opacity) pygame.draw.circle(surface, color, (int(self.pos.x), int(self.pos.y)), self.radius) # Draw background stars def draw_stars(surface, frame): for x, y, size, speed in stars: flicker = int(127 + 128 * math.sin(frame * speed)) pygame.draw.circle(surface, (flicker, flicker, flicker), (x, y), size) # Draw event horizon ring def draw_event_horizon(surface, center, radius): r = int(radius + event_horizon_offset) ring = pygame.Surface((r * 2, r * 2), pygame.SRCALPHA) pygame.draw.circle(ring, (*EVENT_HORIZON_COLOR, 100), (r, r), r, width=4) surface.blit(ring, (center.x - r, center.y - r), special_flags=pygame.BLEND_RGBA_ADD) # Draw improved nebula def draw_nebula(surface, blackhole_pos, radius, frame): nebula_intensity = min(1.0, absorbed_particles / 600) for i, color in enumerate(NEBULA_COLORS): scale_factor = 2 + i * 0.4 nebula_radius = int(radius * scale_factor * nebula_intensity) if nebula_radius < 10: continue nebula_surface = pygame.Surface((nebula_radius * 2, nebula_radius * 2), pygame.SRCALPHA) alpha = int(60 + 40 * math.sin(frame * 0.02 + i)) pygame.draw.circle(nebula_surface, (*color, alpha), (nebula_radius, nebula_radius), nebula_radius) surface.blit(nebula_surface, (blackhole_pos.x - nebula_radius, blackhole_pos.y - nebula_radius), special_flags=pygame.BLEND_RGBA_ADD) # Draw flickering atom effect def draw_flickering_atoms(surface, center, radius, frame): if radius < 500: return flicker_scale = int((radius - 500) / 50) flickers_per_burst = (frame // (3 * FPS)) * 10 + flicker_scale * 5 flickers_per_burst = min(flickers_per_burst, 100) for _ in range(flickers_per_burst): if random.random() < 0.4: # Reduced flicker density angle = random.uniform(0, 2 * math.pi) dist = random.uniform(0, radius * 0.9) flicker_pos = pygame.Vector2( center.x + math.cos(angle) * dist, center.y + math.sin(angle) * dist ) size = random.randint(1, 3) flicker = pygame.Surface((size, size), pygame.SRCALPHA) alpha = random.randint(180, 255) pygame.draw.circle(flicker, (255, 255, 255, alpha), (size // 2, size // 2), size // 2) surface.blit(flicker, (flicker_pos.x - size // 2, flicker_pos.y - size // 2)) # Camera shake shake_intensity = 0 def apply_camera_shake(pos): if shake_intensity > 0: offset = pygame.Vector2(random.uniform(-shake_intensity, shake_intensity), random.uniform(-shake_intensity, shake_intensity)) return pos + offset return pos particles = [Particle() for _ in range(300)] absorbed_particles = 0 frame = 0 show_trail = True background_color = DEEP_SPACE # Main loop while True: screen.fill(background_color) frame += 1 blackhole_pos = pygame.Vector2(pygame.mouse.get_pos()) if blackhole_radius > 100: shake_intensity = min(15, (blackhole_radius - 100) * 0.5) else: shake_intensity = 0 for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == pygame.KEYDOWN: if event.key == pygame.K_c: background_color = (0, 0, 50) if background_color == DEEP_SPACE else DEEP_SPACE if event.key == pygame.K_t: show_trail = not show_trail draw_stars(screen, frame) for p in particles: if p.alive: p.update(blackhole_pos) p.draw(screen, show_trail) draw_event_horizon(screen, blackhole_pos, blackhole_radius) draw_nebula(screen, blackhole_pos, blackhole_radius, frame) shaken_pos = apply_camera_shake(blackhole_pos) pygame.draw.circle(screen, BLACK, shaken_pos, int(blackhole_radius)) pygame.draw.circle(screen, (255, 255, 255), shaken_pos, int(blackhole_radius), 2) draw_flickering_atoms(screen, shaken_pos, blackhole_radius, frame) while len([p for p in particles if p.alive]) < 300: particles.append(Particle()) pygame.display.flip() clock.tick(FPS)