Merge of doom
[koperkapel.git] / koperkapel / scenes / level.py
1 """Render a level"""
2
3 from pgzero.constants import keys
4 from pygame import Surface
5 import pygame.locals as pgl
6 from ..loaders.levelloader import levels
7 from .base import Scene, ChangeSceneEvent
8 from ..constants import TILE_SIZE
9
10
11 class LevelScene(Scene):
12     """ Level scene. """
13
14     def enter(self, world):
15         self._level_data = levels.load(world.level.name)
16         self._tiles = self._level_data['tiles']
17         self._level_layer = 'floor'
18         self._surfaces = {}
19         self._overlay = {}
20         for layer in ['floor', 'tunnels']:
21             self._surfaces[layer] = self._render(layer)
22         self._overlay = self._surfaces['floor'].copy()
23
24     def _render(self, layer):
25         # We cache the rendered surface to avoid doing a large number
26         # of blits each frame, as that introduces a large performance
27         # overhead.
28         surface = Surface((len(self._tiles[0]) * TILE_SIZE,
29                            len(self._tiles) * TILE_SIZE))
30         layer_key = '%s image' % layer
31         for y, row in enumerate(self._tiles):
32             for x, tile in enumerate(row):
33                 pos = (x * TILE_SIZE, y * TILE_SIZE)
34                 if layer_key not in tile:
35                     # Skip broken tiles for now
36                     continue
37                 surface.blit(tile[layer_key], pos)
38         return surface.convert_alpha()
39
40     def draw(self, screen, viewport):
41         screen.clear()
42         # Viewport is the position of the screen relative to the
43         # surface. We need the position of the surface relative to
44         # the screen for the blit, so this conversion
45         screen_pos = -viewport[0], -viewport[1]
46         if self._level_layer == 'floor':
47             screen.blit(self._surfaces[self._level_layer], screen_pos)
48         else:
49             # blit tunnels, with translucent overlay
50             # We need to call pygame.Surface.blit ourselves,
51             # since pgzero's screen blit hides the blend flags
52             # from us
53             tunnels = self._surfaces[self._level_layer].copy()
54             tunnels.blit(self._overlay, (0, 0),
55                          special_flags=pgl.BLEND_MULT)
56             screen.blit(tunnels, screen_pos)
57
58     def on_key_down(self, key, mod, unicode):
59         if key == keys.ESCAPE:
60             from .menu import MenuScene
61             return [ChangeSceneEvent(MenuScene())]