Mercurial > skaapsteker
changeset 262:de60329cfc9f
Factor out sound stuff
author | Neil Muller <drnlmuller@gmail.com> |
---|---|
date | Fri, 08 Apr 2011 11:29:37 +0200 |
parents | 7668243695f4 |
children | 44cd7cfd2de3 |
files | data/sounds/silence.ogg data/sounds/sources.txt skaapsteker/__main__.py skaapsteker/cutscene.py skaapsteker/engine.py skaapsteker/level.py skaapsteker/levelscene.py skaapsteker/menuscene.py skaapsteker/sound.py |
diffstat | 9 files changed, 98 insertions(+), 50 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/sounds/sources.txt Fri Apr 08 11:29:37 2011 +0200 @@ -0,0 +1,6 @@ +Sources for the various sound files: + +[silent.ogg] +Generated 2 secs of silence - dd if=/dev/zero of=silence.pcm bs=176400 count=2 ; oggenc -r silence.pcm +Generated by Neil Muller, Aug 2010 +Not copyrightable.
--- a/skaapsteker/__main__.py Fri Apr 08 10:40:16 2011 +0200 +++ b/skaapsteker/__main__.py Fri Apr 08 11:29:37 2011 +0200 @@ -8,10 +8,11 @@ from pygame.locals import SWSURFACE from . import options -from .constants import SCREEN, FREQ, BITSIZE, CHANNELS, BUFFER, DEBUG +from .constants import SCREEN, DEBUG from .engine import Engine from .levelscene import LevelScene from .menuscene import MenuScene +from .sound import SoundSystem def parse_args(args): @@ -39,27 +40,17 @@ level = parse_args(sys.argv) pygame.display.init() pygame.font.init() - if options['sound']: - try: - pygame.mixer.init(FREQ, BITSIZE, CHANNELS, BUFFER) - except pygame.error, exc: - raise - # TODO: bail out to no_sound(exc) - else: - # Ensure get_sound returns nothing, so everything else just works - # TODO: bail out to disable_sound() - pass - + soundsystem = SoundSystem(options['sound']) pygame.display.set_mode(SCREEN, SWSURFACE) #pygame.display.set_icon(pygame.image.load( # data.filepath('icons/nine_tales24x24.png'))) pygame.display.set_caption("Nine Tales") - engine = Engine() + engine = Engine(soundsystem) if level is not None: - engine.change_scene(LevelScene(engine.game_state, level)) + engine.change_scene(LevelScene(engine.game_state, soundsystem, level)) else: - engine.change_scene(MenuScene(engine.game_state)) + engine.change_scene(MenuScene(engine.game_state, soundsystem)) try: engine.run() except KeyboardInterrupt:
--- a/skaapsteker/cutscene.py Fri Apr 08 10:40:16 2011 +0200 +++ b/skaapsteker/cutscene.py Fri Apr 08 11:29:37 2011 +0200 @@ -9,15 +9,14 @@ from .widgets.text import Text, ButtonSet, TextButton, unindent_text class CutScene(Scene): - def __init__(self, game_state, text, background, music=None): - super(CutScene, self).__init__(game_state) + def __init__(self, game_state, soundsystem, text, background, music=None): + super(CutScene, self).__init__(game_state, soundsystem) self.background = data.load_image('backgrounds/' + background) self.start_time = pygame.time.get_ticks() self.run_time = 60000 # ms self._background_music = None - if music and pygame.mixer.get_init(): - self._background_music = data.filepath(music) + self._background_music = music text_widget = Text(text, pygame.Rect(20, 20, 800-40, 600-40), size=24, shadow='gray', wrap=True) @@ -56,15 +55,10 @@ def enter(self): if self._background_music: - pygame.mixer.music.load(self._background_music) - pygame.mixer.music.play(-1) - - def leave(self): - if self._background_music: - pygame.mixer.music.stop() + self._soundsystem.play_background_music(self._background_music) -def opening_cutscene(game_state): +def opening_cutscene(game_state, soundsystem): text = u""" Many moons ago, an evil nine-tailed kitsune, a fearsome fox god, ruled the land. @@ -82,4 +76,4 @@ The kitsune stole your tail. Now it’s time to get it back. """ text = unindent_text(text) - return CutScene(game_state, text, 'background_01_back.png') + return CutScene(game_state, soundsystem, text, 'background_01_back.png')
--- a/skaapsteker/engine.py Fri Apr 08 10:40:16 2011 +0200 +++ b/skaapsteker/engine.py Fri Apr 08 11:29:37 2011 +0200 @@ -8,7 +8,7 @@ class Engine(object): - def __init__(self): + def __init__(self, soundsystem): # avoid circular imports from .gamestate import GameState self._framerate = 60 @@ -16,8 +16,10 @@ self._fpss = [self._framerate] * 100 self._cur_frame = 0 self.game_state = GameState("game.json") + self.soundsystem = soundsystem def change_scene(self, next_scene): + self.soundsystem.stop_music() if self._current_scene is not None: self._current_scene.leave() self._current_scene = next_scene @@ -51,9 +53,10 @@ class Scene(object): - def __init__(self, game_state): + def __init__(self, game_state, soundsystem): self.widgets = [] self.game_state = game_state + self._soundsystem = soundsystem def post(self, ev): """Post an event to pygame's event loop."""
--- a/skaapsteker/level.py Fri Apr 08 10:40:16 2011 +0200 +++ b/skaapsteker/level.py Fri Apr 08 11:29:37 2011 +0200 @@ -53,34 +53,32 @@ class Level(object): - def __init__(self, leveldef, player): + def __init__(self, leveldef, player, soundsystem): self.name = leveldef self.level_data = json.loads(data.load('levels/' + leveldef + '.json').read()) self.sprites = LayeredUpdates() + self._soundsystem = soundsystem self.build_backgrounds() self.build_tiles() self.setup_enemies() self.setup_doorways() self.setup_player(player) self._background_music = None - if 'music' in self.level_data and mixer.get_init(): - self._background_music = data.filepath('music/' + self.level_data['music']) + if 'music' in self.level_data: + # soundsystem will call data.filepath + self._background_music = 'music/' + self.level_data['music'] def build_backgrounds(self): self.backgrounds = [] for background in self.level_data['backgrounds']: self.backgrounds.append(data.load_image('backgrounds/' + background)) + def enter(self): + if self._background_music: + self._soundsystem.play_background_music(self._background_music) def leave(self): - if self._background_music: - mixer.music.stop() - - - def enter(self): - if self._background_music: - mixer.music.load(self._background_music) - mixer.music.play(-1) + pass def build_tiles(self): self.tileset = TileSet(self.level_data['tileset'])
--- a/skaapsteker/levelscene.py Fri Apr 08 10:40:16 2011 +0200 +++ b/skaapsteker/levelscene.py Fri Apr 08 11:29:37 2011 +0200 @@ -16,11 +16,11 @@ class LevelScene(engine.Scene): - def __init__(self, game_state, leveldef): - super(LevelScene, self).__init__(game_state) + def __init__(self, game_state, soundsystem, leveldef): + super(LevelScene, self).__init__(game_state, soundsystem) self._player = player.Player(game_state.world) - self._level = level.Level(leveldef, self._player) + self._level = level.Level(leveldef, self._player, soundsystem) self._leveldef = leveldef self._player_dead = False self._dialogue = None @@ -67,18 +67,18 @@ def _quit(self, pause=True): import menuscene # avoid circular import if pause: - engine.ChangeScene.post(menuscene.MenuScene(self.game_state, self)) + engine.ChangeScene.post(menuscene.MenuScene(self.game_state, self._soundsystem, self)) else: # FIXME: When starting the game, we shoudl ensure we have sane # states if self._player_dead: self._player.restore() - engine.ChangeScene.post(menuscene.MenuScene(self.game_state, None)) + engine.ChangeScene.post(menuscene.MenuScene(self.game_state, self._soundsystem, None)) def _restart(self): if self._player_dead: self._player.restore() - engine.ChangeScene.post(LevelScene(self.game_state, self._leveldef)) + engine.ChangeScene.post(LevelScene(self.game_state, self._soundsystem, self._leveldef)) def _toggle_pause(self): if self._paused:
--- a/skaapsteker/menuscene.py Fri Apr 08 10:40:16 2011 +0200 +++ b/skaapsteker/menuscene.py Fri Apr 08 11:29:37 2011 +0200 @@ -8,8 +8,8 @@ class MenuScene(Scene): - def __init__(self, game_state, cur_game=None): - super(MenuScene, self).__init__(game_state) + def __init__(self, game_state, soundsystem, cur_game=None): + super(MenuScene, self).__init__(game_state, soundsystem) self.widgets.append(Text("MENU:", (50, 50), color='white', size=48)) self.cur_game = cur_game menu_options = [ @@ -32,11 +32,11 @@ if data == 'resume': ChangeScene.post(self.cur_game) elif data == 'cutscene': - ChangeScene.post(opening_cutscene(self.game_state)) + ChangeScene.post(opening_cutscene(self.game_state, self._soundsystem)) elif data == 'quit': pygame.event.post(pygame.event.Event(QUIT)) else: - ChangeScene.post(LevelScene(self.game_state, data)) + ChangeScene.post(LevelScene(self.game_state, self._soundsystem, data)) def draw(self, surface, engine): surface.fill(pygame.Color('black'))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/skaapsteker/sound.py Fri Apr 08 11:29:37 2011 +0200 @@ -0,0 +1,56 @@ +"""Support for playing sounds and music""" + +from pygame import mixer +import pygame +from . import data +from .constants import FREQ, BITSIZE, CHANNELS, BUFFER + +class SoundSystem(object): + + def __init__(self, want_sound): + if want_sound: + # See if we can actually enabled sound + try: + mixer.init(FREQ, BITSIZE, CHANNELS, BUFFER) + test_sound = mixer.Sound(data.filepath('sounds/silence.ogg')) + test_sound.play() + self.sound_enabled = True + except pygame.error: + print 'Unable to enable sound' + self.sound_enabled = False + else: + self.sound_enabled = False + + self._sounds = {} + + + def play_background_music(self, track_name): + if self.sound_enabled: + try: + mixer.music.load(data.filepath(track_name)) + mixer.music.play(-1) # Loop forever + except pygame.error: + print 'Unable to load track' + + def stop_music(self): + if self.sound_enabled: + mixer.music.stop() + + def load_sound(self, key, track_name): + if key in self._sounds: + # First caller wins on duplicate keys + return + if not self.sound_enabled: + self._sounds[key] = None + else: + self._sounds[key] = pygame.sound.Sound(data.filepath(track_name)) + + def play_sound(self, key): + sound = self._sounds.get(key, None) + if sound: + sound.play() + + def stop_all_sounds(self): + if self.sound_enabled: + mixer.stop() +