Add procedural sound effects with thrust, laser, and explosion sounds using NumPy synthesis
This commit is contained in:
100
asteroids.py
100
asteroids.py
@@ -2,9 +2,11 @@ import pygame
|
|||||||
import sys
|
import sys
|
||||||
import random
|
import random
|
||||||
import math
|
import math
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
# Initialize Pygame
|
# Initialize Pygame
|
||||||
pygame.init()
|
pygame.init()
|
||||||
|
pygame.mixer.init(frequency=22050, size=-16, channels=2, buffer=512)
|
||||||
|
|
||||||
# Set up the display
|
# Set up the display
|
||||||
width, height = 800, 600
|
width, height = 800, 600
|
||||||
@@ -32,6 +34,93 @@ asteroid_count = 10
|
|||||||
# Particles
|
# Particles
|
||||||
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
|
||||||
score = 0
|
score = 0
|
||||||
font = pygame.font.Font(None, 36)
|
font = pygame.font.Font(None, 36)
|
||||||
@@ -108,6 +197,7 @@ while True:
|
|||||||
sys.exit()
|
sys.exit()
|
||||||
elif event.key == pygame.K_SPACE and not game_over:
|
elif event.key == pygame.K_SPACE and not game_over:
|
||||||
bullets.append([ship_pos[0], ship_pos[1], ship_angle])
|
bullets.append([ship_pos[0], ship_pos[1], ship_angle])
|
||||||
|
effects_channel.play(laser_sound)
|
||||||
|
|
||||||
if not game_over:
|
if not game_over:
|
||||||
# Ship movement
|
# Ship movement
|
||||||
@@ -155,6 +245,14 @@ while True:
|
|||||||
# Create thrust particles
|
# Create thrust particles
|
||||||
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
|
# Update asteroids
|
||||||
for asteroid in asteroids[:]:
|
for asteroid in asteroids[:]:
|
||||||
asteroid["pos"][0] += math.cos(asteroid["angle"]) * asteroid["speed"]
|
asteroid["pos"][0] += math.cos(asteroid["angle"]) * asteroid["speed"]
|
||||||
@@ -175,6 +273,7 @@ while True:
|
|||||||
if (abs(asteroid["pos"][0] - ship_pos[0]) < asteroid["size"] and
|
if (abs(asteroid["pos"][0] - ship_pos[0]) < asteroid["size"] and
|
||||||
abs(asteroid["pos"][1] - ship_pos[1]) < asteroid["size"]):
|
abs(asteroid["pos"][1] - ship_pos[1]) < asteroid["size"]):
|
||||||
create_explosion(ship_pos[0], ship_pos[1], (255, 0, 0))
|
create_explosion(ship_pos[0], ship_pos[1], (255, 0, 0))
|
||||||
|
effects_channel.play(explosion_sound)
|
||||||
game_over = True
|
game_over = True
|
||||||
|
|
||||||
# Check collision with bullets
|
# Check collision with bullets
|
||||||
@@ -182,6 +281,7 @@ while True:
|
|||||||
if (abs(asteroid["pos"][0] - bullet[0]) < asteroid["size"] and
|
if (abs(asteroid["pos"][0] - bullet[0]) < asteroid["size"] and
|
||||||
abs(asteroid["pos"][1] - bullet[1]) < asteroid["size"]):
|
abs(asteroid["pos"][1] - bullet[1]) < asteroid["size"]):
|
||||||
create_explosion(asteroid["pos"][0], asteroid["pos"][1])
|
create_explosion(asteroid["pos"][0], asteroid["pos"][1])
|
||||||
|
effects_channel.play(explosion_sound)
|
||||||
asteroids.remove(asteroid)
|
asteroids.remove(asteroid)
|
||||||
bullets.remove(bullet)
|
bullets.remove(bullet)
|
||||||
score += 1
|
score += 1
|
||||||
|
|||||||
Reference in New Issue
Block a user