pygstormgames/__init__.py

206 lines
6.6 KiB
Python

"""
Core initialization module for PygStormGames framework.
Provides the main PygStormGames class that serves as the central hub for game functionality.
"""
import pyglet
import time
from .config import Config
from .display import Display
from .menu import Menu
from .scoreboard import Scoreboard
from .sound import Sound
from .speech import Speech
class pygstormgames:
"""Main class that coordinates all game systems."""
def __init__(self, gameTitle):
"""Initialize the game framework.
Args:
gameTitle (str): Title of the game
"""
self.gameTitle = gameTitle
self._paused = False
# Initialize core systems
self.config = Config(gameTitle)
self.display = Display(self)
self.speech = Speech()
self.sound = Sound(self)
self.scoreboard = Scoreboard(self)
self.menu = Menu(self)
# Play intro sound if available
try:
player = self.sound.play_sound('game-intro')
if player:
startTime = time.time()
duration = player.source.duration
# Make sure to give pyglet enough cycles to start playing
pyglet.clock.tick()
interrupted = self.wait_for_completion(
lambda: not player.playing or (time.time() - startTime) >= duration
)
if interrupted:
player.pause()
except:
pass
# Set up window event handlers after intro is complete
self.display.window.push_handlers(self.on_key_press)
def on_key_press(self, symbol, modifiers):
"""Handle global keyboard events.
Args:
symbol: Pyglet key symbol
modifiers: Key modifiers
"""
if self._paused:
if symbol == pyglet.window.key.BACKSPACE:
self._paused = False
self.sound.resume()
self.speech.speak("Game resumed")
else:
# Global exit handler
if symbol == pyglet.window.key.ESCAPE:
self.exit_game()
# Global pause handler
if symbol == pyglet.window.key.BACKSPACE:
self.pause_game()
def run(self):
"""Start the game loop."""
pyglet.app.run()
def pause_game(self):
"""Pause all game systems and wait for resume."""
self._paused = True
self.sound.pause()
self.speech.speak("Game paused, press backspace to resume.")
def exit_game(self):
"""Clean up and exit the game."""
self.sound.cleanup()
self.speech.cleanup()
pyglet.app.exit()
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. 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 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, 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 or timeout, False if condition was met
"""
if validKeys is None:
validKeys = [pyglet.window.key.ESCAPE,
pyglet.window.key.RETURN,
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]
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)