Compare commits
4 Commits
619cb5508a
...
3b01662d98
| Author | SHA1 | Date | |
|---|---|---|---|
| 3b01662d98 | |||
| 5e926fa7eb | |||
| e272da1177 | |||
| 1bb9e18ea2 |
+33
-15
@@ -53,22 +53,40 @@ def initialize_gui(gameTitle):
|
||||
# Enable key repeat for volume controls
|
||||
pygame.key.set_repeat(500, 100)
|
||||
|
||||
# Load sound files
|
||||
try:
|
||||
from os import listdir
|
||||
from os.path import isfile, join
|
||||
soundFiles = [f for f in listdir("sounds/")
|
||||
if isfile(join("sounds/", f))
|
||||
and (f.split('.')[1].lower() in ["ogg", "wav"])]
|
||||
except Exception as e:
|
||||
print("No sounds found.")
|
||||
Speech.get_instance().speak("No sounds found.", False)
|
||||
soundFiles = []
|
||||
|
||||
# Create dictionary of sound objects
|
||||
# Load sound files recursively including subdirectories
|
||||
soundData = {}
|
||||
for f in soundFiles:
|
||||
soundData[f.split('.')[0]] = pygame.mixer.Sound("sounds/" + f)
|
||||
try:
|
||||
import os
|
||||
|
||||
soundDir = "sounds/"
|
||||
# Walk through directory tree
|
||||
for dirPath, dirNames, fileNames in os.walk(soundDir):
|
||||
# Get relative path from soundDir
|
||||
relPath = os.path.relpath(dirPath, soundDir)
|
||||
|
||||
# Process each file
|
||||
for fileName in fileNames:
|
||||
# Check if file is a valid sound file
|
||||
if fileName.lower().endswith(('.ogg', '.wav')):
|
||||
# Full path to the sound file
|
||||
fullPath = os.path.join(dirPath, fileName)
|
||||
|
||||
# Create sound key (remove extension)
|
||||
baseName = os.path.splitext(fileName)[0]
|
||||
|
||||
# If in root sounds dir, just use basename
|
||||
if relPath == '.':
|
||||
soundKey = baseName
|
||||
else:
|
||||
# Otherwise use relative path + basename, normalized with forward slashes
|
||||
soundKey = os.path.join(relPath, baseName).replace('\\', '/')
|
||||
|
||||
# Load the sound
|
||||
soundData[soundKey] = pygame.mixer.Sound(fullPath)
|
||||
except Exception as e:
|
||||
print("Error loading sounds:", e)
|
||||
Speech.get_instance().speak("Error loading sounds.", False)
|
||||
soundData = {}
|
||||
|
||||
# Play intro sound if available
|
||||
from .sound import cut_scene
|
||||
|
||||
@@ -256,9 +256,15 @@ def learn_sounds(sounds):
|
||||
"""Interactive menu for learning game sounds.
|
||||
|
||||
Allows users to:
|
||||
- Navigate through available sounds
|
||||
- Play selected sounds
|
||||
- Return to menu with escape key
|
||||
- Navigate through available sounds with up/down arrows
|
||||
- Navigate between sound categories (folders) using Page Up/Page Down or Left/Right arrows
|
||||
- Play selected sounds with Enter
|
||||
- Return to menu with Escape
|
||||
|
||||
Excluded sounds:
|
||||
- Files in folders named 'ambience' (at any level)
|
||||
- Files in any directory starting with '.'
|
||||
- Files starting with 'game-intro', 'music_menu', or '_'
|
||||
|
||||
Args:
|
||||
sounds (dict): Dictionary of available sound objects
|
||||
@@ -269,56 +275,134 @@ def learn_sounds(sounds):
|
||||
# Get speech instance
|
||||
speech = Speech.get_instance()
|
||||
|
||||
currentIndex = 0
|
||||
# Define exclusion criteria
|
||||
excludedPrefixes = ["game-intro", "music_menu", "_"]
|
||||
excludedDirs = ["ambience", "."]
|
||||
|
||||
# Get list of available sounds, excluding special sounds
|
||||
soundFiles = [f for f in listdir("sounds/")
|
||||
if isfile(join("sounds/", f))
|
||||
and (f.split('.')[1].lower() in ["ogg", "wav"])
|
||||
and (f.split('.')[0].lower() not in ["game-intro", "music_menu"])
|
||||
and (not f.lower().startswith("_"))]
|
||||
# Organize sounds by directory
|
||||
soundsByDir = {}
|
||||
|
||||
# Sort the sound files alphabetically
|
||||
soundFiles.sort()
|
||||
# Process each sound key in the dictionary
|
||||
for soundKey in sounds.keys():
|
||||
# Skip if key has any excluded prefix
|
||||
if any(soundKey.lower().startswith(prefix.lower()) for prefix in excludedPrefixes):
|
||||
continue
|
||||
|
||||
# Split key into path parts
|
||||
parts = soundKey.split('/')
|
||||
|
||||
# Skip if any part of the path is an excluded directory
|
||||
if any(part.lower() == dirName.lower() or part.startswith('.') for part in parts for dirName in excludedDirs):
|
||||
continue
|
||||
|
||||
# Determine the directory
|
||||
if '/' in soundKey:
|
||||
directory = soundKey.split('/')[0]
|
||||
else:
|
||||
directory = 'root' # Root directory sounds
|
||||
|
||||
# Add to sounds by directory
|
||||
if directory not in soundsByDir:
|
||||
soundsByDir[directory] = []
|
||||
soundsByDir[directory].append(soundKey)
|
||||
|
||||
# Total number of sound files
|
||||
totalSounds = len(soundFiles)
|
||||
# Sort each directory's sounds
|
||||
for directory in soundsByDir:
|
||||
soundsByDir[directory].sort()
|
||||
|
||||
# Track last spoken index to avoid repetition
|
||||
# If no sounds found, inform the user and return
|
||||
if not soundsByDir:
|
||||
speech.speak("No sounds available to learn.")
|
||||
return "menu"
|
||||
|
||||
# Get list of directories in sorted order
|
||||
directories = sorted(soundsByDir.keys())
|
||||
|
||||
# Start with first directory
|
||||
currentDirIndex = 0
|
||||
currentDir = directories[currentDirIndex]
|
||||
currentSoundKeys = soundsByDir[currentDir]
|
||||
currentSoundIndex = 0
|
||||
|
||||
# Display appropriate message based on number of directories
|
||||
if len(directories) > 1:
|
||||
messagebox(f"Starting with {currentDir if currentDir != 'root' else 'root directory'} sounds. Use left and right arrows or page up and page down to navigate categories.")
|
||||
|
||||
# Track last spoken to avoid repetition
|
||||
lastSpoken = -1
|
||||
directoryChanged = True # Flag to track if directory just changed
|
||||
|
||||
# Flag to track when to exit the loop
|
||||
returnToMenu = False
|
||||
|
||||
while not returnToMenu:
|
||||
if currentIndex != lastSpoken:
|
||||
# Speak the sound name followed by its position in the list
|
||||
speech.speak(f"{soundFiles[currentIndex][:-4]}, {currentIndex + 1} of {totalSounds}")
|
||||
lastSpoken = currentIndex
|
||||
# Announce current sound
|
||||
if currentSoundIndex != lastSpoken:
|
||||
totalSounds = len(currentSoundKeys)
|
||||
soundName = currentSoundKeys[currentSoundIndex]
|
||||
|
||||
# Remove directory prefix if present
|
||||
if '/' in soundName:
|
||||
displayName = '/'.join(soundName.split('/')[1:])
|
||||
else:
|
||||
displayName = soundName
|
||||
|
||||
# If directory just changed, include directory name in announcement
|
||||
if directoryChanged:
|
||||
dirDescription = "Root directory" if currentDir == 'root' else currentDir
|
||||
announcement = f"{dirDescription}: {displayName}, {currentSoundIndex + 1} of {totalSounds}"
|
||||
directoryChanged = False # Reset flag after announcement
|
||||
else:
|
||||
announcement = f"{displayName}, {currentSoundIndex + 1} of {totalSounds}"
|
||||
|
||||
speech.speak(announcement)
|
||||
lastSpoken = currentSoundIndex
|
||||
|
||||
event = pygame.event.wait()
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_ESCAPE:
|
||||
returnToMenu = True
|
||||
|
||||
if event.key in [pygame.K_DOWN, pygame.K_s] and currentIndex < len(soundFiles) - 1:
|
||||
# Sound navigation
|
||||
elif event.key in [pygame.K_DOWN, pygame.K_s] and currentSoundIndex < len(currentSoundKeys) - 1:
|
||||
pygame.mixer.stop()
|
||||
currentIndex += 1
|
||||
currentSoundIndex += 1
|
||||
|
||||
if event.key in [pygame.K_UP, pygame.K_w] and currentIndex > 0:
|
||||
elif event.key in [pygame.K_UP, pygame.K_w] and currentSoundIndex > 0:
|
||||
pygame.mixer.stop()
|
||||
currentIndex -= 1
|
||||
currentSoundIndex -= 1
|
||||
|
||||
if event.key == pygame.K_RETURN:
|
||||
# Directory navigation
|
||||
elif event.key in [pygame.K_PAGEDOWN, pygame.K_RIGHT] and currentDirIndex < len(directories) - 1:
|
||||
pygame.mixer.stop()
|
||||
currentDirIndex += 1
|
||||
currentDir = directories[currentDirIndex]
|
||||
currentSoundKeys = soundsByDir[currentDir]
|
||||
currentSoundIndex = 0
|
||||
directoryChanged = True # Set flag on directory change
|
||||
lastSpoken = -1 # Force announcement
|
||||
|
||||
elif event.key in [pygame.K_PAGEUP, pygame.K_LEFT] and currentDirIndex > 0:
|
||||
pygame.mixer.stop()
|
||||
currentDirIndex -= 1
|
||||
currentDir = directories[currentDirIndex]
|
||||
currentSoundKeys = soundsByDir[currentDir]
|
||||
currentSoundIndex = 0
|
||||
directoryChanged = True # Set flag on directory change
|
||||
lastSpoken = -1 # Force announcement
|
||||
|
||||
# Play sound
|
||||
elif event.key == pygame.K_RETURN:
|
||||
try:
|
||||
soundName = soundFiles[currentIndex][:-4]
|
||||
soundName = currentSoundKeys[currentSoundIndex]
|
||||
pygame.mixer.stop()
|
||||
sounds[soundName].play()
|
||||
except:
|
||||
lastSpoken = -1
|
||||
except Exception as e:
|
||||
print(f"Error playing sound: {e}")
|
||||
speech.speak("Could not play sound.")
|
||||
|
||||
event = pygame.event.clear()
|
||||
pygame.event.pump() # Process pygame's internal events
|
||||
time.sleep(0.001)
|
||||
|
||||
return "menu"
|
||||
|
||||
@@ -8,6 +8,7 @@ Provides functionality for:
|
||||
- Volume controls
|
||||
"""
|
||||
|
||||
import os
|
||||
import pygame
|
||||
import random
|
||||
import re
|
||||
@@ -44,46 +45,41 @@ class Sound:
|
||||
self.load_sounds()
|
||||
|
||||
def load_sounds(self):
|
||||
"""Load all sound files from the sound directory."""
|
||||
"""Load all sound files from the sound directory and its subdirectories.
|
||||
|
||||
Searches recursively through subdirectories and loads all sound files with
|
||||
.ogg or .wav extensions. Sound names are stored as relative paths from the
|
||||
sound directory, with directory separators replaced by forward slashes.
|
||||
"""
|
||||
try:
|
||||
soundFiles = [f for f in listdir(self.soundDir)
|
||||
if isfile(join(self.soundDir, f))
|
||||
and (f.split('.')[1].lower() in ["ogg", "wav"])]
|
||||
|
||||
# Create dictionary of sound objects
|
||||
for f in soundFiles:
|
||||
self.sounds[f.split('.')[0]] = pygame.mixer.Sound(join(self.soundDir, f))
|
||||
|
||||
# Walk through directory tree
|
||||
for dirPath, dirNames, fileNames in os.walk(self.soundDir):
|
||||
# Get relative path from soundDir
|
||||
relPath = os.path.relpath(dirPath, self.soundDir)
|
||||
|
||||
# Process each file
|
||||
for fileName in fileNames:
|
||||
# Check if file is a valid sound file
|
||||
if fileName.lower().endswith(('.ogg', '.wav')):
|
||||
# Full path to the sound file
|
||||
fullPath = os.path.join(dirPath, fileName)
|
||||
|
||||
# Create sound key (remove extension)
|
||||
baseName = os.path.splitext(fileName)[0]
|
||||
|
||||
# If in root sounds dir, just use basename
|
||||
if relPath == '.':
|
||||
soundKey = baseName
|
||||
else:
|
||||
# Otherwise use relative path + basename, normalized with forward slashes
|
||||
soundKey = os.path.join(relPath, baseName).replace('\\', '/')
|
||||
|
||||
# Load the sound
|
||||
self.sounds[soundKey] = pygame.mixer.Sound(fullPath)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error loading sounds: {e}")
|
||||
|
||||
def play_intro(self):
|
||||
"""Play the game intro sound if available."""
|
||||
if 'game-intro' in self.sounds:
|
||||
self.cut_scene('game-intro')
|
||||
|
||||
def get_sounds(self):
|
||||
"""Get the dictionary of loaded sound objects.
|
||||
|
||||
Returns:
|
||||
dict: Dictionary of loaded sound objects
|
||||
"""
|
||||
return self.sounds
|
||||
|
||||
def play_bgm(self, musicFile):
|
||||
"""Play background music with proper volume settings.
|
||||
|
||||
Args:
|
||||
musicFile (str): Path to the music file to play
|
||||
"""
|
||||
try:
|
||||
pygame.mixer.music.stop()
|
||||
pygame.mixer.music.load(musicFile)
|
||||
pygame.mixer.music.set_volume(self.volumeService.get_bgm_volume())
|
||||
pygame.mixer.music.play(-1) # Loop indefinitely
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
def play_sound(self, soundName, volume=1.0):
|
||||
"""Play a sound with current volume settings applied.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user