Added exit_game method that handles cleanup. A few other small modifications.
This commit is contained in:
parent
576f4cc87a
commit
a6702edf16
38
__init__.py
38
__init__.py
@ -150,3 +150,41 @@ class pygstormgames:
|
||||
|
||||
self.display.window.remove_handlers()
|
||||
return interrupted[0]
|
||||
|
||||
def exit_game(self):
|
||||
"""Closes the game cleanly"""
|
||||
try:
|
||||
self.sound.cleanup()
|
||||
except Exception as e:
|
||||
print(f"Error with sound cleanup: {e}")
|
||||
pass
|
||||
|
||||
try:
|
||||
self.display.window.remove_handlers()
|
||||
except Exception as e:
|
||||
print(f"Error with handler cleanup: {e}")
|
||||
pass
|
||||
|
||||
try:
|
||||
self.speech.cleanup()
|
||||
except Exception as e:
|
||||
print(f"Error with speech cleanup: {e}")
|
||||
pass
|
||||
|
||||
try:
|
||||
# Try to close the window explicitly
|
||||
if hasattr(self.display, 'window'):
|
||||
self.display.window.close()
|
||||
except Exception as e:
|
||||
print(f"Error closing window: {e}")
|
||||
pass
|
||||
|
||||
try:
|
||||
pyglet.app.exit()
|
||||
except Exception as e:
|
||||
print(f"Error while exiting: {e}")
|
||||
pass
|
||||
|
||||
# Force exit if pyglet.app.exit() didn't work
|
||||
import sys
|
||||
sys.exit(0)
|
||||
|
41
display.py
41
display.py
@ -57,7 +57,6 @@ class Display:
|
||||
self.currentIndex = 0
|
||||
speech.speak(self.navText[self.currentIndex])
|
||||
|
||||
# Use the game's existing input handlers
|
||||
validKeys = [
|
||||
pyglet.window.key.ESCAPE,
|
||||
pyglet.window.key.RETURN,
|
||||
@ -131,25 +130,25 @@ class Display:
|
||||
|
||||
self.display_text(info, speech)
|
||||
|
||||
def messagebox(self, text):
|
||||
"""Display a simple message box with text.
|
||||
def messagebox(self, text):
|
||||
"""Display a simple message box with text.
|
||||
|
||||
Shows a message that can be repeated until the user chooses to continue.
|
||||
|
||||
Args:
|
||||
text (str): Message to display
|
||||
"""
|
||||
text = text + "\nPress any key to repeat or enter to continue."
|
||||
while True:
|
||||
# Speak the text
|
||||
self.game.speech.speak(text)
|
||||
Shows a message that can be repeated until the user chooses to continue.
|
||||
|
||||
# Wait for any key
|
||||
key, _ = self.game.wait()
|
||||
Args:
|
||||
text (str): Message to display
|
||||
"""
|
||||
text = text + "\nPress any key to repeat or enter to continue."
|
||||
while True:
|
||||
# Speak the text
|
||||
self.game.speech.speak(text)
|
||||
|
||||
# Exit if enter/escape pressed
|
||||
if key in (pyglet.window.key.RETURN, pyglet.window.key.ESCAPE):
|
||||
break
|
||||
# Wait for any key
|
||||
key, _ = self.game.wait()
|
||||
|
||||
# Exit if enter/escape pressed
|
||||
if key in (pyglet.window.key.RETURN, pyglet.window.key.ESCAPE):
|
||||
break
|
||||
|
||||
def get_input(self, prompt="Enter text:", defaultText=""):
|
||||
"""Display a dialog box for text input.
|
||||
@ -173,5 +172,11 @@ def messagebox(self, text):
|
||||
|
||||
def donate(self, speech):
|
||||
"""Open the donation webpage."""
|
||||
speech.speak("Opening donation page.")
|
||||
speech.speak("Opening donation page. Press space or enter to continue.")
|
||||
webbrowser.open('https://ko-fi.com/stormux')
|
||||
validKeys = [
|
||||
pyglet.window.key.ESCAPE,
|
||||
pyglet.window.key.RETURN,
|
||||
pyglet.window.key.SPACE
|
||||
]
|
||||
key, _ = self.game.wait(validKeys)
|
||||
|
28
menu.py
28
menu.py
@ -78,11 +78,8 @@ class Menu:
|
||||
if key == pyglet.window.key.ESCAPE:
|
||||
if "exit" in options:
|
||||
# Handle exit cleanup immediately
|
||||
self.game.sound.cleanup()
|
||||
self.game.display.window.remove_handlers()
|
||||
self.game.speech.cleanup()
|
||||
pyglet.app.exit()
|
||||
return "exit"
|
||||
self.game.exit_game()
|
||||
return
|
||||
|
||||
if key == pyglet.window.key.HOME and self.currentIndex != 0:
|
||||
self.currentIndex = 0
|
||||
@ -126,14 +123,12 @@ class Menu:
|
||||
return selection
|
||||
elif selection == "instructions":
|
||||
# Pause menu music
|
||||
if self.game.sound.currentBgm:
|
||||
self.game.sound.currentBgm.pause()
|
||||
self.game.sound.pause_bgm()
|
||||
|
||||
self.game.display.instructions(self.game.speech)
|
||||
|
||||
# Resume menu music
|
||||
if self.game.sound.currentBgm:
|
||||
self.game.sound.currentBgm.play()
|
||||
self.game.sound.resume_bgm()
|
||||
|
||||
elif selection == "learn_sounds":
|
||||
if self.learn_sounds() == "menu":
|
||||
@ -141,30 +136,23 @@ class Menu:
|
||||
|
||||
elif selection == "credits":
|
||||
# Pause menu music
|
||||
if self.game.sound.currentBgm:
|
||||
self.game.sound.currentBgm.pause()
|
||||
self.game.sound.pause_bgm()
|
||||
|
||||
self.game.display.credits(self.game.speech)
|
||||
|
||||
# Resume menu music
|
||||
if self.game.sound.currentBgm:
|
||||
self.game.sound.currentBgm.play()
|
||||
self.game.sound.resume_bgm()
|
||||
|
||||
elif selection == "donate":
|
||||
# Pause menu music
|
||||
if self.game.sound.currentBgm:
|
||||
self.game.sound.currentBgm.pause()
|
||||
self.game.sound.pause_bgm()
|
||||
|
||||
self.game.display.donate(self.game.speech)
|
||||
|
||||
# Resume menu music
|
||||
if self.game.sound.currentBgm:
|
||||
self.game.sound.currentBgm.play()
|
||||
self.game.sound.resume_bgm()
|
||||
|
||||
elif selection == "exit":
|
||||
self.game.sound.cleanup() # Stop all sounds first
|
||||
self.game.display.window.remove_handlers() # Remove handlers before closing speech
|
||||
self.game.speech.cleanup() # Clean up speech last
|
||||
self.game.exit_game()
|
||||
|
||||
def learn_sounds(self):
|
||||
|
61
sound.py
61
sound.py
@ -82,6 +82,16 @@ class Sound:
|
||||
except Exception as e:
|
||||
print(f"Error playing background music: {e}")
|
||||
|
||||
def pause_bgm(self):
|
||||
"""Pause background music."""
|
||||
if self.currentBgm and self.currentBgm.playing:
|
||||
self.currentBgm.pause()
|
||||
|
||||
def resume_bgm(self):
|
||||
"""Resume background music from paused state."""
|
||||
if self.currentBgm and not self.currentBgm.playing:
|
||||
self.currentBgm.play()
|
||||
|
||||
def play_sound(self, soundName, volume=1.0):
|
||||
"""Play a sound effect with volume settings.
|
||||
|
||||
@ -220,15 +230,7 @@ class Sound:
|
||||
player.cone_orientation = direction
|
||||
|
||||
def cut_scene(self, soundName):
|
||||
"""Play a sound as a cut scene, stopping other sounds and waiting for completion.
|
||||
|
||||
Args:
|
||||
soundName (str): Name of sound to play
|
||||
|
||||
The method will block until either:
|
||||
- The sound finishes playing
|
||||
- The user presses ESC/RETURN/SPACE (if window is provided)
|
||||
"""
|
||||
"""Play a sound as a cut scene, stopping other sounds and waiting for completion."""
|
||||
# Stop all current sounds
|
||||
self.stop_all_sounds()
|
||||
if self.currentBgm:
|
||||
@ -241,44 +243,19 @@ class Sound:
|
||||
player = pyglet.media.Player()
|
||||
player.queue(self.sounds[soundName])
|
||||
player.volume = self.sfxVolume * self.masterVolume
|
||||
|
||||
# Flag to track if we should continue waiting
|
||||
shouldContinue = True
|
||||
|
||||
def on_player_eos():
|
||||
nonlocal shouldContinue
|
||||
shouldContinue = False
|
||||
|
||||
# Set up completion callback
|
||||
player.push_handlers(on_eos=on_player_eos)
|
||||
|
||||
# Get window from game display
|
||||
window = self.game.display.window
|
||||
|
||||
# If we have a window, set up key handler for skipping
|
||||
if window:
|
||||
skipKeys = [key.ESCAPE, key.RETURN, key.SPACE]
|
||||
|
||||
@window.event
|
||||
def on_key_press(symbol, modifiers):
|
||||
nonlocal shouldContinue
|
||||
if symbol in skipKeys:
|
||||
shouldContinue = False
|
||||
return True
|
||||
|
||||
|
||||
# Start playback
|
||||
player.play()
|
||||
|
||||
# Wait for completion or skip
|
||||
while shouldContinue and player.playing:
|
||||
if window:
|
||||
window.dispatch_events()
|
||||
pyglet.clock.tick()
|
||||
|
||||
|
||||
# Wait for completion or skip using game's wait_for_completion method
|
||||
interrupted = self.game.wait_for_completion(
|
||||
lambda: not player.playing
|
||||
)
|
||||
|
||||
# Ensure cleanup
|
||||
player.pause()
|
||||
player.delete()
|
||||
|
||||
|
||||
# Resume background music if it was playing
|
||||
if self.currentBgm:
|
||||
self.currentBgm.play()
|
||||
|
20
speech.py
20
speech.py
@ -15,6 +15,7 @@ class Speech:
|
||||
def __init__(self):
|
||||
"""Initialize speech system with fallback providers."""
|
||||
self._lastSpoken = {"text": None, "time": 0}
|
||||
self._active = False
|
||||
self._speechDelay = 250 # ms delay between identical messages
|
||||
|
||||
# Try to initialize speech providers in order of preference
|
||||
@ -22,11 +23,13 @@ class Speech:
|
||||
import speechd
|
||||
self._speech = speechd.Client()
|
||||
self._provider = "speechd"
|
||||
self._active = True
|
||||
except ImportError:
|
||||
try:
|
||||
import accessible_output2.outputs.auto
|
||||
self._speech = accessible_output2.outputs.auto.Auto()
|
||||
self._provider = "accessible_output2"
|
||||
self._active = True
|
||||
except ImportError:
|
||||
raise RuntimeError("No speech providers found. Install either speechd or accessible_output2.")
|
||||
|
||||
@ -60,12 +63,15 @@ class Speech:
|
||||
self._lastSpoken["time"] = currentTime
|
||||
|
||||
# Handle speech output based on provider
|
||||
if self._provider == "speechd":
|
||||
if interrupt:
|
||||
self._speech.cancel()
|
||||
self._speech.speak(text)
|
||||
else:
|
||||
self._speech.speak(text, interrupt=interrupt)
|
||||
try:
|
||||
if self._provider == "speechd":
|
||||
if interrupt:
|
||||
self._speech.cancel()
|
||||
self._speech.speak(text)
|
||||
else:
|
||||
self._speech.speak(text, interrupt=interrupt)
|
||||
except Exception as e:
|
||||
self._active = False
|
||||
|
||||
# Update display text
|
||||
self._font.text = text
|
||||
@ -76,6 +82,8 @@ class Speech:
|
||||
|
||||
def cleanup(self):
|
||||
"""Clean up speech system resources."""
|
||||
if not self._active:
|
||||
return
|
||||
if self._provider == "speechd":
|
||||
self._speech.close()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user