diff --git a/asteroids.py b/asteroids.py index 1976fc8..07b6bf2 100644 --- a/asteroids.py +++ b/asteroids.py @@ -2,9 +2,11 @@ import pygame import sys import random import math +import numpy as np # Initialize Pygame pygame.init() +pygame.mixer.init(frequency=22050, size=-16, channels=2, buffer=512) # Set up the display width, height = 800, 600 @@ -32,6 +34,93 @@ asteroid_count = 10 # Particles particles = [] +# Sound generation functions +def generate_sine_wave(frequency, duration, sample_rate=22050, volume=0.3): + frames = int(duration * sample_rate) + arr = np.zeros((frames, 2), dtype=np.int16) + for i in range(frames): + t = float(i) / sample_rate + wave = volume * 32767.0 * np.sin(2 * np.pi * frequency * t) + arr[i] = [wave, wave] + return pygame.sndarray.make_sound(arr) + +def generate_laser_sound(): + sample_rate = 22050 + duration = 0.1 + frames = int(duration * sample_rate) + arr = np.zeros((frames, 2), dtype=np.int16) + + for i in range(frames): + t = float(i) / sample_rate + # Descending frequency sweep + frequency = 800 * (1 - t / duration * 0.5) + envelope = np.exp(-t * 20) # Quick decay + wave = envelope * 0.2 * 32767.0 * np.sin(2 * np.pi * frequency * t) + arr[i] = [wave, wave] + + return pygame.sndarray.make_sound(arr) + +def generate_explosion_sound(): + sample_rate = 22050 + duration = 0.3 + frames = int(duration * sample_rate) + arr = np.zeros((frames, 2), dtype=np.int16) + + for i in range(frames): + t = float(i) / sample_rate + envelope = np.exp(-t * 5) # Exponential decay + # White noise with low-pass filter effect + noise = np.random.normal(0, 1) * envelope * 0.15 * 32767.0 + arr[i] = [noise, noise] + + return pygame.sndarray.make_sound(arr) + +def generate_thrust_sound(): + sample_rate = 22050 + duration = 0.4 + frames = int(duration * sample_rate) + arr = np.zeros((frames, 2), dtype=np.int16) + + for i in range(frames): + t = float(i) / sample_rate + # Smooth low rumble without noise + wave = (0.15 * 32767.0 * np.sin(2 * np.pi * 30 * t) + + 0.08 * 32767.0 * np.sin(4 * np.pi * 30 * t) + + 0.04 * 32767.0 * np.sin(6 * np.pi * 30 * t)) + arr[i] = [wave, wave] + + return pygame.sndarray.make_sound(arr) + +def generate_background_rumble(): + sample_rate = 22050 + duration = 2.0 + frames = int(duration * sample_rate) + arr = np.zeros((frames, 2), dtype=np.int16) + + for i in range(frames): + t = float(i) / sample_rate + # Very low frequency with random variations + frequency = 20 + np.random.normal(0, 2) + wave = 0.05 * 32767.0 * np.sin(2 * np.pi * frequency * t) + arr[i] = [wave, wave] + + return pygame.sndarray.make_sound(arr) + +# Create sound effects +laser_sound = generate_laser_sound() +explosion_sound = generate_explosion_sound() +thrust_sound = generate_thrust_sound() +background_rumble = generate_background_rumble() + +# Sound channels +thrust_channel = pygame.mixer.Channel(0) +effects_channel = pygame.mixer.Channel(1) +background_channel = pygame.mixer.Channel(2) + +# Background rumble disabled - uncomment to enable +# background_channel.play(background_rumble, loops=-1) +# background_channel.set_volume(0.2) + # Score score = 0 font = pygame.font.Font(None, 36) @@ -108,6 +197,7 @@ while True: sys.exit() elif event.key == pygame.K_SPACE and not game_over: bullets.append([ship_pos[0], ship_pos[1], ship_angle]) + effects_channel.play(laser_sound) if not game_over: # Ship movement @@ -154,6 +244,14 @@ while True: # Create thrust particles create_thrust_particles() + + # Handle thrust sound + if ship_speed > 0: + if not thrust_channel.get_busy(): + thrust_channel.play(thrust_sound, loops=-1) + thrust_channel.set_volume(0.2) + else: + thrust_channel.stop() # Update asteroids for asteroid in asteroids[:]: @@ -175,6 +273,7 @@ while True: if (abs(asteroid["pos"][0] - ship_pos[0]) < asteroid["size"] and abs(asteroid["pos"][1] - ship_pos[1]) < asteroid["size"]): create_explosion(ship_pos[0], ship_pos[1], (255, 0, 0)) + effects_channel.play(explosion_sound) game_over = True # Check collision with bullets @@ -182,6 +281,7 @@ while True: if (abs(asteroid["pos"][0] - bullet[0]) < asteroid["size"] and abs(asteroid["pos"][1] - bullet[1]) < asteroid["size"]): create_explosion(asteroid["pos"][0], asteroid["pos"][1]) + effects_channel.play(explosion_sound) asteroids.remove(asteroid) bullets.remove(bullet) score += 1