Refactor experimental demo into final state for developing the game
[base2-runner.git] / engine / SeamlessBackground.py
diff --git a/engine/SeamlessBackground.py b/engine/SeamlessBackground.py
new file mode 100755 (executable)
index 0000000..ebdd66b
--- /dev/null
@@ -0,0 +1,79 @@
+#!/usr/bin/python3
+# (c) Copyright 2013 TJ <hacker@iam.tj>
+# Licensed on the terms of the GNU General Public License version 3 (see COPYING)
+#
+# Game engine: scrolling seamless background image manager
+
+import os, time, pygame, engine
+
+class SeamlessBackground:
+ """ The game window has a scrolling background image that is seamless, which allows it to be tiled
+     so that as the viewport scrolls the image appears to be continuous in both directions.
+
+     The game window only scrolls left or right, which means that the background needs to be redrawn 
+     at the left or right margins (depending on direction of scroll) or, as a one-off, the entire
+     background image needs drawing at the beginning of the game.
+
+     The seamless background image provided should be larger (wider) than the intended game window to
+     allow the wrapping of the image to work correctly.
+ """
+ image_path = None
+ image = None
+ width = None
+
+ def __init__(self, filename, debug=False):
+  """ Constructor.
+   filename:  absolute or relative path to seamless background image file (JPeG, PNG, etc.)
+  """
+  self.debug = debug
+  if os.path.exists(filename):
+   self.image_path = filename
+   self.image = pygame.image.load(self.image_path).convert()
+   self.width = self.image.get_size()[0]
+
+  if self.image == None:
+   print("Error: failed to load image", filename)
+
+ def draw(self, screen, x_pos, step):
+  """ Redraw damaged areas of the game screen.
+   x_pos:  -1 == request the full screen be painted, not just the damaged left/right margins. Otherwise, 
+           it is the current game-level's left-edge x coordinate.
+   step:   the number of pixels, and direction, the screen has just scrolled (negative, 0, or positive)
+  """
+  if self.image != None:
+   # resolution[0] = width, [1] = height
+   resolution = screen.get_size()
+   # adjust x_pos to be x coord of damaged rectangle (left or right side of screen)
+   if step > 0:
+    x_pos += resolution[0] - step
+   elif step < 0:
+    x_pos -= step
+   elif step == 0 and x_pos >= 0:
+    # nothing to do if not drawing the initial background
+    return
+
+   # calculate the offset into the background image such that the scrolled
+   # game window and the background image will match
+
+   # if drawing the background for the first time (x_pos==-1) use the entire image
+   # use modulo to get the offset within the image of the first damaged column
+   bk_x_start = x_pos % self.width if x_pos != -1 else 0
+   bk_rect = pygame.Rect(bk_x_start, 0, resolution[0] if x_pos == -1 else abs(step), resolution[1])
+   # When the image wraps there might not be 'step' columns of pixels available from the right side of 
+   # the seamless image. Therefore use an intermediate 'patch' image to build the complete image to be drawn
+   # to the game window
+   patch = pygame.Surface((bk_rect.width, bk_rect.height))
+   patch.blit(self.image, (0, 0), bk_rect)
+
+   remainder = self.width - bk_x_start
+   if remainder < abs(step):
+    # need more pixel columns because the seamless image just wrapped around
+    patch.blit(self.image, (4,0), pygame.Rect(0, 0, remainder, resolution[1]))
+
+   # calculate the left coord in the game window where the new background should be drawn
+   scr_x_dest = resolution[0] - step if step > 0 else 0
+
+   screen.blit(patch, (scr_x_dest, 0))
+  else:
+   print("Warning: SeamlessBackground: No image to draw")
+