Split level scene for game play extensions
[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, WIDTH, HEIGHT
9
10
11 class BaseLevelScene(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.surface.blit(self._surfaces[self._level_layer], (0, 0),
46                             area=(viewport[0], viewport[1], WIDTH, HEIGHT))
47         if self._level_layer != 'floor':
48             screen.surface.blit(self._overlay, (0, 0),
49                          area=(viewport[0], viewport[1], WIDTH, HEIGHT), 
50                          special_flags=pgl.BLEND_ADD)
51
52     def on_key_down(self, key, mod, unicode):
53         if key == keys.ESCAPE:
54             from .menu import MenuScene
55             return [ChangeSceneEvent(MenuScene())]
56
57
58 class GameLevelScene(BaseLevelScene):
59     pass