206 lines
6.6 KiB
Python
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)
|