Move viewport management down into the engine and add suitable events. Cache initial...
authorNeil <neil@dip.sun.ac.za>
Wed, 2 Mar 2016 14:36:11 +0000 (16:36 +0200)
committerNeil <neil@dip.sun.ac.za>
Wed, 2 Mar 2016 14:36:11 +0000 (16:36 +0200)
koperkapel/scenes/base.py
koperkapel/scenes/credits.py
koperkapel/scenes/level.py
koperkapel/scenes/viewlevel.py

index 58f3874f204b87a874751d593f4360a785791a70..c6b8752d41de58893a8ac3174ace3f2b37b5c284 100644 (file)
@@ -18,6 +18,7 @@ class Engine:
     def __init__(self, app, scene):
         self._app = app
         self._scene = scene
+        self._viewport = (0, 0)
 
     def _apply_events(self, events):
         if not events:
@@ -34,12 +35,16 @@ class Engine:
         from pgzero.game import exit
         exit()
 
+    def move_screen(self, offset):
+        self._viewport = (self._viewport[0] + offset[0],
+                            self._viewport[1] + offset[1])
+
     @apply_events
     def update(self, dt):
         return self._scene.update(dt)
 
     def draw(self):
-        self._scene.draw(self._app.screen)
+        self._scene.draw(self._app.screen, self._viewport)
 
     @apply_events
     def on_mouse_down(self, pos, button):
@@ -87,6 +92,12 @@ class QuitEvent(Event):
     ENGINE_METHOD = "quit_game"
 
 
+class MoveViewportEvent(Event):
+    """ Change to a new scene. """
+
+    ENGINE_METHOD = "move_screen"
+
+
 class Actors:
     """ A list of actors. """
 
@@ -121,7 +132,7 @@ class Scene:
     def update(self, dt):
         pass
 
-    def draw(self, screen):
+    def draw(self, screen, viewport):
         screen.clear()
         self.actors.draw(screen)
 
index 772943e51e57127cf9c8aa14e184e7b77b7a5df7..3c1551c5281b0760f96746acba9b828d83081ba1 100644 (file)
@@ -7,7 +7,7 @@ from .base import Scene, ChangeSceneEvent
 class CreditsScene(Scene):
     """ Credits scene. """
 
-    def draw(self, screen):
+    def draw(self, screen, viewport):
         screen.clear()
         screen.draw.text("Credits", (300, 300))
 
index 71373c06a08a80c86f1d9368074d94ba53f9a6f9..c37b3e339c62a399e49e2cbb918750643e95b88c 100644 (file)
@@ -1,6 +1,7 @@
 """Render a level"""
 
 from pgzero.constants import keys
+from pygame import Surface
 from ..loaders.levelloader import levels
 from .base import Scene, ChangeSceneEvent
 from ..constants import TILE_SIZE, WIDTH, HEIGHT
@@ -12,19 +13,30 @@ class LevelScene(Scene):
     def __init__(self, level_name):
         self._level_data = levels.load(level_name)
         self._tiles = self._level_data['tiles']
+        self._surface = None
+        self._render()
 
-    def draw(self, screen, viewport=(0, 0)):
-        screen.clear()
+    def _render(self):
+        # We cache the rendered surface to avoid doing a large number
+        # of blits each frame, as that introduces a large performance
+        # overhead.
+        self._surface = Surface((len(self._tiles[0]) * TILE_SIZE,
+                                 len(self._tiles) * TILE_SIZE))
         for y, row in enumerate(self._tiles):
             for x, tile in enumerate(row):
-                pos = (x * TILE_SIZE - viewport[0],
-                       y * TILE_SIZE - viewport[1])
+                pos = (x * TILE_SIZE, y * TILE_SIZE)
                 if 'image' not in tile:
                     # Skip broken tiles for now
                     continue
-                if 0 <= pos[0] < WIDTH:
-                    if 0 <= pos[1] < HEIGHT:
-                        screen.blit(tile['image'], pos)
+                self._surface.blit(tile['image'], pos)
+
+    def draw(self, screen, viewport):
+        screen.clear()
+        # Viewport is the position of the screen relative to the
+        # surface. We need the position of the surface relative to
+        # the screen for the blit, so this conversion
+        screen_pos = -viewport[0], -viewport[1]
+        screen.blit(self._surface, screen_pos)
 
     def on_key_down(self, key, mod, unicode):
         if key == keys.ESCAPE:
index 8a101df27e1a815d6bca2b9ece97775b2d6a6306..46b8a002c365abf5efeb2e6726e628cfda5a6f8c 100644 (file)
@@ -2,30 +2,23 @@
 
 from pgzero.constants import keys
 from .level import LevelScene
+from .base import MoveViewportEvent
 from ..constants import TILE_SIZE
 
 
 class ViewLevelScene(LevelScene):
     """ Level scene. """
 
-    def __init__(self, level_name):
-        super(ViewLevelScene, self).__init__(level_name)
-        self._pos = (0, 0)
-
-    def draw(self, screen):
-        super(ViewLevelScene, self).draw(screen, self._pos)
-
     def on_key_down(self, key, mod, unicode):
+        offset = None
         if key == keys.DOWN:
-            self._pos = self._pos[0], self._pos[1] + TILE_SIZE
-            return
+            offset = (0, TILE_SIZE)
         elif key == keys.UP:
-            self._pos = self._pos[0], self._pos[1] - TILE_SIZE
-            return
+            offset = (0, -TILE_SIZE)
         elif key == keys.LEFT:
-            self._pos = self._pos[0] - TILE_SIZE, self._pos[1]
-            return
+            offset = (-TILE_SIZE, 0)
         elif key == keys.RIGHT:
-            self._pos = self._pos[0] + TILE_SIZE, self._pos[1]
-            return
+            offset = (TILE_SIZE, 0)
+        if offset:
+            return [MoveViewportEvent(offset)]
         return super(ViewLevelScene, self).on_key_down(key, mod, unicode)