view mamba/engine.py @ 555:c014f5023cd2

Test run replays
author Neil Muller <drnlmuller@gmail.com>
date Thu, 22 Sep 2011 17:32:38 +0200
parents 165fcc747951
children 4c30776673c6
line wrap: on
line source

"""Game engine and top-level game loop."""

from mamba.constants import SCREEN, FPS
from mamba.sound import stop_sound

import pygame.event
import pygame.display
import pygame.time
import pygame
from pygame.locals import QUIT, USEREVENT


class Engine(object):
    def __init__(self):
        self._habitat = None
        self._fps = FPS

    def set_habitat(self, habitat):
        if self._habitat is not None:
            self._habitat.on_exit()
        self._habitat = habitat
        if self._habitat is not None:
            self._habitat.on_enter()

    def run(self):
        """Game loop."""
        get_events = pygame.event.get
        flip = pygame.display.flip
        clock = pygame.time.Clock()
        while True:
            events = get_events()
            for ev in events:
                if ev.type is QUIT:
                    return
                elif NewHabitatEvent.matches(ev):
                    self.set_habitat(ev.habitat)
                else:
                    self._habitat.dispatch(ev)
            surface = pygame.display.get_surface()
            self._habitat.draw(surface)
            flip()
            self._fps = 1000.0 / clock.tick(FPS)


class Habitat(object):

    def __init__(self, size=SCREEN):
        from mamba.widgets.base import Container
        stop_sound()  # Always stop any music on scene changes
        self.surface_size = size
        self.surface = None
        self.container = Container(pygame.Rect((0, 0), self.surface_size))

    def on_enter(self):
        """Called when this becomes the current habitat."""
        # Create the surface here as flipping between editor and
        # other things kills pygame.display
        self.surface = pygame.Surface(self.surface_size)

    def on_exit(self):
        """Called when this stops being the current habitat."""
        self.surface = None

    def dispatch(self, ev):
        self.container.event(ev)

    def draw_background(self):
        self.surface.fill(pygame.Color('gray'))

    def draw(self, surface):
        if self.surface:
            self.draw_background()
            self.container.draw(self.surface)
            surface.blit(self.surface, self.surface.get_rect())

    def display_dialog(self, dialog):
        self.container.paused = True
        self.container.add(dialog)
        dialog.grab_focus()


class UserEvent(object):

    TYPE = "UNKNOWN"

    @classmethod
    def post(cls, **kws):
        ev = pygame.event.Event(USEREVENT, utype=cls.TYPE, **kws)
        pygame.event.post(ev)

    @classmethod
    def matches(cls, ev):
        return ev.type is USEREVENT and ev.utype == cls.TYPE


class NewHabitatEvent(UserEvent):

    TYPE = "NEW_HABITAT"

    @classmethod
    def post(cls, habitat):
        super(NewHabitatEvent, cls).post(habitat=habitat)


class SnakeDiedEvent(UserEvent):

    TYPE = "SNAKE_DIED"

    @classmethod
    def post(cls, reason):
        super(SnakeDiedEvent, cls).post(reason=reason)


class LevelCompletedEvent(UserEvent):

    TYPE = "LEVEL_COMPLETED"

    @classmethod
    def post(cls):
        super(LevelCompletedEvent, cls).post()


class FlipArrowsEvent(UserEvent):

    TYPE = "FLIP_ARROWS"

    @classmethod
    def post(cls):
        super(FlipArrowsEvent, cls).post()


class ReplayEvent(UserEvent):

    TYPE = "REPLAY_EVENT"

    @classmethod
    def post(cls, run, replay_pos):
        super(ReplayEvent, cls).post(run=run, replay_pos=replay_pos)


class HabitatSetupEvent(UserEvent):

    TYPE = "SETUP_HABITAT"

    @classmethod
    def post(cls):
        super(HabitatSetupEvent, cls).post()