Mercurial > skaapsteker
view skaapsteker/levelscene.py @ 288:ddcfc159dc2a
Combine 'fox' and 'player' sections in game.json.
author | Simon Cross <hodgestar@gmail.com> |
---|---|
date | Fri, 08 Apr 2011 21:23:00 +0200 |
parents | 95e2ef31e714 |
children | c68f2f3efc7f |
line wrap: on
line source
"""Scene wrapping a level object.""" from pygame.locals import (KEYDOWN, KEYUP, K_DOWN, K_ESCAPE, K_LEFT, K_RIGHT, K_SEMICOLON, K_UP, K_p, K_q, K_x, K_z, K_RETURN) import pygame import time from . import options from . import engine from . import level from . import physics from . import constants from .sprites import player from .widgets.text import Text from .widgets.bubble import DialogueWidget class LevelScene(engine.Scene): def __init__(self, game_state, soundsystem, doorway_def=None): super(LevelScene, self).__init__(game_state, soundsystem) if doorway_def is not None: fox = self.game_state.world.fox fox.level, fox.doorway = doorway_def.split('.') self._level = level.Level(self.game_state.world.fox.level, soundsystem) self._player_dead = False self._dialogue = None self.setup_player() self._level_surface = self._level.get_surface() self._clip_rect = None self._world = physics.World() self._paused = False for sprite in self._level.sprites: self._world.add(sprite) for sprite in self.game_state.create_sprites(self._level.name): self._world.add(sprite) self._world.add(self._player) self._build_action_map() self._key_sequence = [] def setup_player(self): doorway = self._level.doorways[self.game_state.world.fox.doorway] self._player = player.Player(self.game_state.world, self._soundsystem) self._player.set_facing(doorway.facing) self._player.set_image() self._player.set_pos(doorway._starting_tile_pos) # Double tap stuff self._last_keys_down = [] self._last_keydown_time = None self._last_keyup_time = None def _build_action_map(self): action = lambda s: getattr(self._player, 'action_%s' % s) self._quit_keys = set([K_q, K_ESCAPE]) self._restart_keys = set([K_x, K_z, K_RETURN]) self._fast_key_map = { K_LEFT: action('left'), K_RIGHT: action('right'), K_UP: action('up'), K_DOWN: action('down'), } self._fast_keys_down = set() self._slow_key_map = { K_ESCAPE: self._quit, K_p: self._toggle_pause, } if options['dvorak']: self._slow_key_map[K_SEMICOLON] = action('fire1') self._slow_key_map[K_q] = action('fire2') else: self._slow_key_map[K_x] = action('fire1') self._slow_key_map[K_z] = action('fire2') self._slow_key_map[K_q] = self._quit self._key_tap_map = { (K_LEFT, K_LEFT) : action('double_left'), (K_RIGHT, K_RIGHT) : action('double_right'), (K_DOWN, K_DOWN) : action('double_down'), } def _quit(self, pause=True): import menuscene # avoid circular import if pause: 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, self._soundsystem, None)) def _restart(self): if self._player_dead: self._player.restore() engine.ChangeScene.post(LevelScene(self.game_state, self._soundsystem)) def _toggle_pause(self): if self._paused: self._world.thaw() self._paused = False else: self._world.freeze() self._paused = True def _open_dialogue(self, npc): if npc.dsm.has_text(): if self._dialogue is not None: self._dialogue.close() self._world.freeze() self._dialogue = DialogueWidget(npc) else: self._close_dialogue() def _close_dialogue(self): if self._dialogue is not None: self._world.thaw() self._dialogue.close() self._dialogue = None def leave(self): """Freeze the scene, for serialization""" self._world.freeze() self._level.leave() def enter(self): """Unfreeze""" self._world.thaw() self._level.enter() def draw(self, screen_surface, engine): if self._clip_rect is None: self._clip_rect = pygame.Rect((0, 0), screen_surface.get_size()) if not self._paused and not self._dialogue: for key in self._fast_keys_down: self._fast_key_map[key]() self._world.update() self._update_clip_rect() self._level_surface.set_clip(self._clip_rect) self._level.draw(self._level_surface) self._world.draw(self._level_surface) if self._dialogue: self._dialogue.draw(self._level_surface) fps_text_pos = self._clip_rect.left + 10, self._clip_rect.top + 10 fps_text = Text('FPS: %.1f' % engine.get_fps(), fps_text_pos, shadow='white') fps_text.draw(self._level_surface) if self._paused: paused_text_pos = self._clip_rect.centerx - 10, self._clip_rect.centery - 10 paused_text = Text('Paused', paused_text_pos) paused_text.draw(self._level_surface) if self._player_dead: death_text_pos = self._clip_rect.centerx - 100, self._clip_rect.centery - 100 death_text = Text("You've died.\nPress Escape to exit or Return to restart the level", death_text_pos) death_text.draw(self._level_surface) screen_surface.blit(self._level_surface, (0, 0), self._clip_rect) def _update_clip_rect(self): cr = self._clip_rect lr = self._level_surface.get_rect() cr.center = self._player.collide_rect.move(0, -level.TILE_SIZE[0]).midbottom cr.clamp_ip(lr) def _detect_key_sequence(self, ev): if ev.key not in self._fast_key_map: self._key_sequence = [] return False if ev.type is KEYUP: if (not self._key_sequence or ev.key != self._key_sequence[-1] or (time.time() - self._last_keydown_time) > constants.DOUBLE_TAP_TIME): self._key_sequence = [] return False self._last_keyup_time = time.time() return False if ev.type is KEYDOWN: if self._last_keyup_time is None or (time.time() - self._last_keyup_time) > constants.DOUBLE_TAP_TIME: self._key_sequence = [] self._key_sequence.append(ev.key) self._last_keydown_time = time.time() for seq in self._key_tap_map: if seq == tuple(self._key_sequence[-len(seq):]): self._key_sequence = self._key_sequence[-len(seq):] return True return False def dispatch(self, ev): if ev.type is KEYDOWN: if self._player_dead: if ev.key in self._restart_keys: self._restart() elif ev.key in self._quit_keys: self._quit(False) return if self._dialogue: self._dialogue.dispatch(ev) return if self._detect_key_sequence(ev): print "Detected double-tap:", self._key_sequence action = self._key_tap_map.get(tuple(self._key_sequence)) if action is not None: action() if ev.key in self._fast_key_map: self._fast_keys_down.add(ev.key) action = self._slow_key_map.get(ev.key) if action is not None: action() elif ev.type is KEYUP: self._detect_key_sequence(ev) if ev.key in self._fast_key_map: self._fast_keys_down.discard(ev.key) elif engine.PlayerDied.matches(ev): self._player_dead = True elif engine.OpenDialog.matches(ev): self._open_dialogue(ev.npc) elif engine.CloseDialog.matches(ev): self._close_dialogue()