More bug fixes, modified wait methods to send modifiers too. Only show text nav instructions the first time desplay_text() is used.

This commit is contained in:
Storm Dragon 2025-02-23 14:51:49 -05:00
parent 99d26b7951
commit 576f4cc87a
3 changed files with 149 additions and 125 deletions

View File

@ -89,34 +89,35 @@ class pygstormgames:
self.speech.cleanup() self.speech.cleanup()
pyglet.app.exit() pyglet.app.exit()
def wait(self, valid_keys=None): def wait(self, validKeys=None):
"""Wait for key press(es). """Wait for key press(es).
Args: Args:
valid_keys (list, optional): List of pyglet.window.key values to wait for. validKeys (list, optional): List of pyglet.window.key values to wait for.
If None, accepts any key press. If None, accepts any key press.
Returns: Returns:
int: The key that was pressed tuple: (key, modifiers) that were pressed
""" """
result = [None] # Use list to allow modification in closure keyResult = [None, None] # Use list to allow modification in closure
def on_key_press(symbol, modifiers): def on_key_press(symbol, modifiers):
if valid_keys is None or symbol in valid_keys: if validKeys is None or symbol in validKeys:
result[0] = symbol keyResult[0] = symbol
keyResult[1] = modifiers
return pyglet.event.EVENT_HANDLED return pyglet.event.EVENT_HANDLED
# Register temporary handler # Register temporary handler
self.display.window.push_handlers(on_key_press=on_key_press) self.display.window.push_handlers(on_key_press=on_key_press)
# Wait for valid key press # Wait for valid key press
while result[0] is None: while keyResult[0] is None:
self.display.window.dispatch_events() self.display.window.dispatch_events()
pyglet.clock.tick() pyglet.clock.tick()
# Clean up # Clean up
self.display.window.remove_handlers() self.display.window.remove_handlers()
return result[0] return tuple(keyResult)
def wait_for_completion(self, condition, validKeys=None): def wait_for_completion(self, condition, validKeys=None):
"""Wait for either a condition to be met or valid keys to be pressed. """Wait for either a condition to be met or valid keys to be pressed.
@ -134,18 +135,18 @@ class pygstormgames:
pyglet.window.key.RETURN, pyglet.window.key.RETURN,
pyglet.window.key.SPACE] pyglet.window.key.SPACE]
wasInterrupted = [False] # Use list to allow modification in closure interrupted = [False] # Use list to allow modification in closure
def on_key_press(symbol, modifiers): def on_key_press(symbol, modifiers):
if symbol in validKeys: if symbol in validKeys:
wasInterrupted[0] = True interrupted[0] = True
return pyglet.event.EVENT_HANDLED return pyglet.event.EVENT_HANDLED
self.display.window.push_handlers(on_key_press=on_key_press) self.display.window.push_handlers(on_key_press=on_key_press)
while not condition() and not wasInterrupted[0]: while not condition() and not interrupted[0]:
self.display.window.dispatch_events() self.display.window.dispatch_events()
pyglet.clock.tick() pyglet.clock.tick()
self.display.window.remove_handlers() self.display.window.remove_handlers()
return wasInterrupted[0] return interrupted[0]

View File

@ -25,6 +25,7 @@ class Display:
""" """
self.game = game self.game = game
self.window = pyglet.window.Window(800, 600, caption=game.gameTitle) self.window = pyglet.window.Window(800, 600, caption=game.gameTitle)
self.displayedInstructions = False
self.currentText = [] self.currentText = []
self.currentIndex = 0 self.currentIndex = 0
self.gameTitle = game.gameTitle self.gameTitle = game.gameTitle
@ -43,10 +44,12 @@ class Display:
self.navText = [line for line in text if line.strip()] self.navText = [line for line in text if line.strip()]
# Add instructions at start # Add instructions at start
if not self.displayedInstructions:
instructions = ("Press space to read the whole text. Use up and down arrows to navigate " instructions = ("Press space to read the whole text. Use up and down arrows to navigate "
"the text line by line. Press c to copy the current line to the clipboard " "the text line by line. Press c to copy the current line to the clipboard "
"or t to copy the entire text. Press enter or escape when you are done reading.") "or t to copy the entire text. Press enter or escape when you are done reading.")
self.navText.insert(0, instructions) self.navText.insert(0, instructions)
self.displayedInstructions = True
# Add end marker # Add end marker
self.navText.append("End of text.") self.navText.append("End of text.")
@ -68,7 +71,7 @@ class Display:
] ]
while True: while True:
key = self.game.wait(validKeys) key, _ = self.game.wait(validKeys)
if key in (pyglet.window.key.ESCAPE, pyglet.window.key.RETURN): if key in (pyglet.window.key.ESCAPE, pyglet.window.key.RETURN):
break break
@ -142,7 +145,7 @@ def messagebox(self, text):
self.game.speech.speak(text) self.game.speech.speak(text)
# Wait for any key # Wait for any key
key = self.game.wait() key, _ = self.game.wait()
# Exit if enter/escape pressed # Exit if enter/escape pressed
if key in (pyglet.window.key.RETURN, pyglet.window.key.ESCAPE): if key in (pyglet.window.key.RETURN, pyglet.window.key.ESCAPE):

144
menu.py
View File

@ -32,73 +32,81 @@ class Menu:
self.currentIndex = 0 self.currentIndex = 0
lastSpoken = -1 lastSpoken = -1
selection = None # Add this to store the selection
if title: if title:
self.game.speech.speak(title) self.game.speech.speak(title)
def key_handler(symbol, modifiers): # Define handler outside event validKeys = [
nonlocal selection, lastSpoken pyglet.window.key.ESCAPE,
pyglet.window.key.RETURN,
pyglet.window.key.UP,
pyglet.window.key.DOWN,
pyglet.window.key.W,
pyglet.window.key.S,
pyglet.window.key.HOME,
pyglet.window.key.END,
pyglet.window.key.PAGEUP,
pyglet.window.key.PAGEDOWN,
pyglet.window.key.INSERT,
pyglet.window.key.DELETE
]
while True:
# Speak current option if changed
if self.currentIndex != lastSpoken:
self.game.speech.speak(options[self.currentIndex])
lastSpoken = self.currentIndex
key, keyModifiers = self.game.wait(validKeys)
# Handle Alt+volume controls # Handle Alt+volume controls
if modifiers & key.MOD_ALT: if keyModifiers & pyglet.window.key.MOD_ALT:
if symbol == key.PAGEUP: if key == pyglet.window.key.PAGEUP:
self.game.sound.adjust_master_volume(0.1) self.game.sound.adjust_master_volume(0.1)
elif symbol == key.PAGEDOWN: elif key == pyglet.window.key.PAGEDOWN:
self.game.sound.adjust_master_volume(-0.1) self.game.sound.adjust_master_volume(-0.1)
elif symbol == key.HOME: elif key == pyglet.window.key.HOME:
self.game.sound.adjust_bgm_volume(0.1) self.game.sound.adjust_bgm_volume(0.1)
elif symbol == key.END: elif key == pyglet.window.key.END:
self.game.sound.adjust_bgm_volume(-0.1) self.game.sound.adjust_bgm_volume(-0.1)
elif symbol == key.INSERT: elif key == pyglet.window.key.INSERT:
self.game.sound.adjust_sfx_volume(0.1) self.game.sound.adjust_sfx_volume(0.1)
elif symbol == key.DELETE: elif key == pyglet.window.key.DELETE:
self.game.sound.adjust_sfx_volume(-0.1) self.game.sound.adjust_sfx_volume(-0.1)
return continue
if symbol == key.ESCAPE: if key == pyglet.window.key.ESCAPE:
selection = "exit" if "exit" in options:
return pyglet.event.EVENT_HANDLED # Handle exit cleanup immediately
self.game.sound.cleanup()
self.game.display.window.remove_handlers()
self.game.speech.cleanup()
pyglet.app.exit()
return "exit"
if symbol == key.HOME and self.currentIndex != 0: if key == pyglet.window.key.HOME and self.currentIndex != 0:
self.currentIndex = 0 self.currentIndex = 0
self.game.sound.play_sound('menu-move') self.game.sound.play_sound('menu-move')
lastSpoken = -1 # Force speech lastSpoken = -1 # Force speech
elif symbol == key.END and self.currentIndex != len(options) - 1: elif key == pyglet.window.key.END and self.currentIndex != len(options) - 1:
self.currentIndex = len(options) - 1 self.currentIndex = len(options) - 1
self.game.sound.play_sound('menu-move') self.game.sound.play_sound('menu-move')
lastSpoken = -1 # Force speech lastSpoken = -1 # Force speech
elif symbol in (key.DOWN, key.S) and self.currentIndex < len(options) - 1: elif key in (pyglet.window.key.DOWN, pyglet.window.key.S) and self.currentIndex < len(options) - 1:
self.currentIndex += 1 self.currentIndex += 1
self.game.sound.play_sound('menu-move') self.game.sound.play_sound('menu-move')
lastSpoken = -1 # Force speech lastSpoken = -1 # Force speech
elif symbol in (key.UP, key.W) and self.currentIndex > 0: elif key in (pyglet.window.key.UP, pyglet.window.key.W) and self.currentIndex > 0:
self.currentIndex -= 1 self.currentIndex -= 1
self.game.sound.play_sound('menu-move') self.game.sound.play_sound('menu-move')
lastSpoken = -1 # Force speech lastSpoken = -1 # Force speech
elif symbol == key.RETURN: elif key == pyglet.window.key.RETURN:
self.game.sound.play_sound('menu-select') self.game.sound.play_sound('menu-select')
selection = options[self.currentIndex] return options[self.currentIndex]
return pyglet.event.EVENT_HANDLED
return pyglet.event.EVENT_HANDLED
# Register the handler
self.game.display.window.push_handlers(on_key_press=key_handler)
# Main menu loop
while selection is None:
if self.currentIndex != lastSpoken:
self.game.speech.speak(options[self.currentIndex])
lastSpoken = self.currentIndex
self.game.display.window.dispatch_events()
# Clean up
self.game.display.window.remove_handlers()
return selection
def game_menu(self): def game_menu(self):
"""Show main game menu.""" """Show main game menu."""
@ -153,6 +161,12 @@ class Menu:
if self.game.sound.currentBgm: if self.game.sound.currentBgm:
self.game.sound.currentBgm.play() self.game.sound.currentBgm.play()
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): def learn_sounds(self):
"""Interactive menu for learning game sounds. """Interactive menu for learning game sounds.
@ -178,39 +192,45 @@ class Menu:
and (f.split('.')[0].lower() not in ["game-intro", "music_menu"]) and (f.split('.')[0].lower() not in ["game-intro", "music_menu"])
and (not f.lower().startswith("_"))] and (not f.lower().startswith("_"))]
# Track last spoken index to avoid repetition if not soundFiles:
lastSpoken = -1 self.game.speech.speak("No sounds available to learn.")
while True:
if self.currentIndex != lastSpoken:
self.game.speech.speak(soundFiles[self.currentIndex][:-4])
lastSpoken = self.currentIndex
event = self.game.display.window.dispatch_events()
@self.game.display.window.event
def on_key_press(symbol, modifiers):
if symbol == key.ESCAPE:
try:
self.game.sound.currentBgm.unpause()
except:
pass
self.game.display.window.remove_handler('on_key_press', on_key_press)
return "menu" return "menu"
if symbol in [key.DOWN, key.S] and self.currentIndex < len(soundFiles) - 1: validKeys = [
pyglet.window.key.ESCAPE,
pyglet.window.key.RETURN,
pyglet.window.key.UP,
pyglet.window.key.DOWN,
pyglet.window.key.W,
pyglet.window.key.S
]
# Speak initial sound name
self.game.speech.speak(soundFiles[self.currentIndex][:-4])
while True:
key, _ = self.game.wait(validKeys)
if key == pyglet.window.key.ESCAPE:
try:
self.game.sound.currentBgm.play()
except:
pass
return "menu"
if key in [pyglet.window.key.DOWN, pyglet.window.key.S]:
if self.currentIndex < len(soundFiles) - 1:
self.game.sound.stop_all_sounds() self.game.sound.stop_all_sounds()
self.currentIndex += 1 self.currentIndex += 1
self.game.speech.speak(soundFiles[self.currentIndex][:-4])
if symbol in [key.UP, key.W] and self.currentIndex > 0: if key in [pyglet.window.key.UP, pyglet.window.key.W]:
if self.currentIndex > 0:
self.game.sound.stop_all_sounds() self.game.sound.stop_all_sounds()
self.currentIndex -= 1 self.currentIndex -= 1
self.game.speech.speak(soundFiles[self.currentIndex][:-4])
if symbol == key.RETURN: if key == pyglet.window.key.RETURN:
try:
soundName = soundFiles[self.currentIndex][:-4] soundName = soundFiles[self.currentIndex][:-4]
self.game.sound.stop_all_sounds() self.game.sound.stop_all_sounds()
self.game.sound.play_sound(soundName) self.game.sound.play_sound(soundName)
except:
lastSpoken = -1
self.game.speech.speak("Could not play sound.")