Optional timeouts for wait methods. Various bug fixes.
This commit is contained in:
parent
6bddf282a7
commit
4d59a610a0
39
__init__.py
39
__init__.py
@ -89,46 +89,55 @@ class pygstormgames:
|
||||
self.speech.cleanup()
|
||||
pyglet.app.exit()
|
||||
|
||||
def wait(self, validKeys=None):
|
||||
"""Wait for key press(es).
|
||||
def wait(self, validKeys=None, timeout=None):
|
||||
"""Wait for key press(es) with optional timeout.
|
||||
|
||||
Args:
|
||||
validKeys (list, optional): List of pyglet.window.key values to wait for.
|
||||
If None, accepts any key press.
|
||||
timeout (float, optional): Time in seconds to wait for input.
|
||||
If None, waits indefinitely.
|
||||
|
||||
Returns:
|
||||
tuple: (key, modifiers) that were pressed
|
||||
tuple: (key, modifiers) that were pressed. Returns (None, None) on timeout.
|
||||
"""
|
||||
keyResult = [None, None] # Use list to allow modification in closure
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
def on_key_press(symbol, modifiers):
|
||||
if validKeys is None or symbol in validKeys:
|
||||
keyResult[0] = symbol
|
||||
keyResult[1] = modifiers
|
||||
return pyglet.event.EVENT_HANDLED
|
||||
|
||||
|
||||
# Register temporary handler
|
||||
self.display.window.push_handlers(on_key_press=on_key_press)
|
||||
|
||||
# Wait for valid key press
|
||||
# Wait for valid key press or timeout
|
||||
while keyResult[0] is None:
|
||||
self.display.window.dispatch_events()
|
||||
pyglet.clock.tick()
|
||||
|
||||
|
||||
# Check for timeout
|
||||
if timeout is not None and time.time() - start_time > timeout:
|
||||
break
|
||||
|
||||
# Clean up
|
||||
self.display.window.remove_handlers()
|
||||
return tuple(keyResult)
|
||||
|
||||
def wait_for_completion(self, condition, validKeys=None):
|
||||
"""Wait for either a condition to be met or valid keys to be pressed.
|
||||
def wait_for_completion(self, condition, validKeys=None, timeout=None):
|
||||
"""Wait for either a condition to be met, valid keys to be pressed, or timeout.
|
||||
|
||||
Args:
|
||||
condition: Function that returns True when waiting should end
|
||||
validKeys (list, optional): List of pyglet.window.key values that can interrupt
|
||||
If None, uses ESCAPE, RETURN, and SPACE
|
||||
timeout (float, optional): Time in seconds to wait before timing out
|
||||
If None, waits indefinitely
|
||||
|
||||
Returns:
|
||||
bool: True if interrupted by key press, False if condition was met
|
||||
bool: True if interrupted by key press or timeout, False if condition was met
|
||||
"""
|
||||
if validKeys is None:
|
||||
validKeys = [pyglet.window.key.ESCAPE,
|
||||
@ -136,18 +145,24 @@ class pygstormgames:
|
||||
pyglet.window.key.SPACE]
|
||||
|
||||
interrupted = [False] # Use list to allow modification in closure
|
||||
start_time = time.time()
|
||||
|
||||
def on_key_press(symbol, modifiers):
|
||||
if symbol in validKeys:
|
||||
interrupted[0] = True
|
||||
return pyglet.event.EVENT_HANDLED
|
||||
|
||||
|
||||
self.display.window.push_handlers(on_key_press=on_key_press)
|
||||
|
||||
while not condition() and not interrupted[0]:
|
||||
self.display.window.dispatch_events()
|
||||
pyglet.clock.tick()
|
||||
|
||||
|
||||
# Check for timeout
|
||||
if timeout is not None and time.time() - start_time > timeout:
|
||||
interrupted[0] = True
|
||||
break
|
||||
|
||||
self.display.window.remove_handlers()
|
||||
return interrupted[0]
|
||||
|
||||
|
15
display.py
15
display.py
@ -37,6 +37,8 @@ class Display:
|
||||
text (list): List of text lines to display
|
||||
speech (Speech): Speech system for audio output
|
||||
"""
|
||||
# Stop bgm if present.
|
||||
self.game.sound.pause_bgm()
|
||||
# Store original text with blank lines for copying
|
||||
self.originalText = text.copy()
|
||||
|
||||
@ -152,22 +154,31 @@ class Display:
|
||||
|
||||
def get_input(self, prompt="Enter text:", defaultText=""):
|
||||
"""Display a dialog box for text input.
|
||||
|
||||
|
||||
Args:
|
||||
prompt (str): Prompt text to display
|
||||
defaultText (str): Initial text in input box
|
||||
|
||||
|
||||
Returns:
|
||||
str: User input text, or None if cancelled
|
||||
"""
|
||||
app = wx.App(False)
|
||||
dialog = wx.TextEntryDialog(None, prompt, "Input", defaultText)
|
||||
dialog.SetValue(defaultText)
|
||||
|
||||
# Bring dialog to front and give it focus
|
||||
dialog.Raise()
|
||||
dialog.SetFocus()
|
||||
|
||||
if dialog.ShowModal() == wx.ID_OK:
|
||||
userInput = dialog.GetValue()
|
||||
else:
|
||||
userInput = None
|
||||
dialog.Destroy()
|
||||
|
||||
# Return focus to game window
|
||||
self.window.activate()
|
||||
|
||||
return userInput
|
||||
|
||||
def donate(self, speech):
|
||||
|
@ -3,6 +3,7 @@
|
||||
Handles high score tracking with player names and score management.
|
||||
"""
|
||||
|
||||
import pyglet
|
||||
import time
|
||||
|
||||
class Scoreboard:
|
||||
@ -93,34 +94,40 @@ class Scoreboard:
|
||||
|
||||
def add_high_score(self):
|
||||
"""Add current score to high scores if it qualifies.
|
||||
|
||||
|
||||
Returns:
|
||||
bool: True if score was added, False if not
|
||||
"""
|
||||
position = self.check_high_score()
|
||||
if position is None:
|
||||
return False
|
||||
|
||||
|
||||
# Get player name
|
||||
self.game.speech.speak("New high score! Enter your name:")
|
||||
name = self.game.display.get_input("New high score! Enter your name:", "Player")
|
||||
if name is None: # User cancelled
|
||||
name = "Player"
|
||||
|
||||
|
||||
# Insert new score at correct position
|
||||
self.highScores.insert(position - 1, {
|
||||
'name': name,
|
||||
'score': self.currentScore
|
||||
})
|
||||
|
||||
|
||||
# Keep only top 10
|
||||
self.highScores = self.highScores[:10]
|
||||
|
||||
|
||||
# Save to config
|
||||
for i, entry in enumerate(self.highScores):
|
||||
self.game.config.set_value("scoreboard", f"score_{i+1}", str(entry['score']))
|
||||
self.game.config.set_value("scoreboard", f"name_{i+1}", entry['name'])
|
||||
|
||||
|
||||
# Force window refresh after dialog
|
||||
self.game.display.window.dispatch_events()
|
||||
|
||||
self.game.speech.speak(f"Congratulations {name}! You got position {position} on the scoreboard!")
|
||||
time.sleep(1)
|
||||
|
||||
# Make sure window is still responsive
|
||||
self.game.display.window.dispatch_events()
|
||||
return True
|
||||
|
21
sound.py
21
sound.py
@ -236,23 +236,30 @@ class Sound:
|
||||
self.stop_all_sounds()
|
||||
if self.currentBgm:
|
||||
self.currentBgm.pause()
|
||||
|
||||
if soundName not in self.sounds:
|
||||
|
||||
# Find all matching sound variations
|
||||
matches = [name for name in self.sounds.keys()
|
||||
if re.match(f"^{soundName}.*", name)]
|
||||
|
||||
if not matches:
|
||||
return
|
||||
|
||||
|
||||
# Pick a random variation
|
||||
selected_sound = random.choice(matches)
|
||||
|
||||
# Create and configure the player
|
||||
player = pyglet.media.Player()
|
||||
player.queue(self.sounds[soundName])
|
||||
player.queue(self.sounds[selected_sound])
|
||||
player.volume = self.sfxVolume * self.masterVolume
|
||||
|
||||
# Start playback
|
||||
player.play()
|
||||
|
||||
|
||||
# Make sure to give pyglet enough cycles to start playing
|
||||
startTime = time.time()
|
||||
duration = self.sounds[soundName].duration
|
||||
duration = self.sounds[selected_sound].duration
|
||||
pyglet.clock.tick()
|
||||
|
||||
|
||||
# Wait for completion or skip
|
||||
interrupted = self.game.wait_for_completion(
|
||||
lambda: not player.playing or (time.time() - startTime) >= duration
|
||||
|
Loading…
x
Reference in New Issue
Block a user