Refactor experimental demo into final state for developing the game
[base2-runner.git] / base2-runner.py
diff --git a/base2-runner.py b/base2-runner.py
new file mode 100755 (executable)
index 0000000..091c75b
--- /dev/null
@@ -0,0 +1,153 @@
+#!/usr/bin/python3
+# (c) Copyright 2013 TJ <hacker@iam.tj>
+# Licensed on the terms of the GNU General Public License version 3 (see COPYING)
+#
+# 2D platform scrolling game that teaches binary logic
+
+import sys, os, time, random, pygame
+import engine
+
+# Use conditionals in the code to print useful information to the console using the form:
+# if self.debug: engine.debug_pr("some_var=%d, another_var=%s" % (some_var, another_var), somevalue, another_value)
+
+class Base2Runner:
+ background_image = None
+ stepping = 8 # pixels scrolled each flip
+ delay = 0.01  # main loop sleep (100 milliseconds)
+ background_colour = (0, 0, 0)
+ background_image = None
+ icon_image = None
+ flags = pygame.OPENGL & pygame.DOUBLEBUF
+ depth = 0
+ screen = None # the pygame Screen for the game window
+
+ def __init__(self, width, height, title, resources={}, debug=False):
+  pygame.init()
+  self.debug = debug
+  self.myGame = engine.Game(width, height, title, resources, debug=self.debug)
+  self.background_colour = (20, 20, 64)
+  if 'icon' in self.myGame.resources:
+   if self.debug: engine.debug_pr("pygame.image.get_extended()=%r" % pygame.image.get_extended())
+   # pygame.display.set_mode((1,1), self.flags, self.depth) # needed simply to use convert_alpha() on icon
+   self.icon_image = pygame.image.load(self.myGame.resources['icon']) #.convert_alpha()
+   # pygame.display.quit() # need to close display now that icon has been converted
+   # pygame.display.init() # and now re-initialise the display!
+   pygame.display.set_icon(self.icon_image)
+
+ def play(self):
+  self.screen = pygame.display.set_mode(self.myGame.resolution, self.flags, self.depth)
+  self.screen.fill(self.background_colour)
+  pygame.display.set_caption(self.myGame.config['title'])
+  resolution = self.screen.get_size()
+
+  # background image
+  self.background_image = engine.SeamlessBackground(self.myGame.resources['background'], debug=self.debug)
+  self.background_image.draw(self.screen, -1, 0) # -1 flags initial background drawing
+  pygame.display.update()
+
+  # scrolling object
+  blip = pygame.Surface((abs(self.stepping), abs(self.stepping)), pygame.HWSURFACE)
+  blip_colour = (128, 128, 128)
+  blip.fill(blip_colour)
+
+  # starting position
+  y = resolution[1] / 2
+
+  if self.myGame.config['sound'] == 1:
+   self.myGame.soundtrack.playlist(self.myGame.resources['soundtrack'])
+
+  self.myGame.config['auto_scroll'] = False
+  movement = 0 # represents number of pixels, and direction, of next scroll
+  x_pos = 0 # coordinate of left side of viewport
+
+  self.myGame.play = True # start the game
+  while (self.myGame.play):
+
+   if not self.myGame.paused:
+    # update game state
+    if x_pos + movement >= 0:
+     x_pos += movement
+    else:
+     movement = 0
+
+    # change colour randomly
+    d_red = random.randrange(-1,2) *8
+    d_green = random.randrange(-1,2) *8
+    d_blue = random.randrange(-1,2) *8
+    # build a modified colour tuple, ensuring all values are valid
+    blip_colour = tuple( b+d if b+d < 256 and b+d >=0 else b for b, d in zip(blip_colour, (d_red, d_green, d_blue)) )
+    blip.fill(blip_colour)
+
+    # change blip position up or down randomly by one step
+    dy = random.randrange(-1,2) * abs(self.stepping)
+    if((y + dy) < resolution[1] and (y + dy) >= 0):
+     # TODO: no longer need to redraw background colour if using a background image
+     # screen.fill(background_colour, pygame.Rect(resolution[0] - abs(stepping), y, abs(stepping), abs(stepping) ))
+     y += dy
+
+    # redraw the display
+    self.screen.scroll(-movement, 0)
+    self.background_image.draw(self.screen, x_pos, movement)
+    self.screen.blit(blip, (resolution[0] - abs(self.stepping), y))
+    pygame.display.update()
+   
+   # manage the frame-rate
+   time.sleep(self.delay)
+
+   # process events
+   for event in pygame.event.get():
+    if event.type == pygame.QUIT or (event.type == pygame.KEYUP and event.key == pygame.K_q):
+     self.myGame.play = False
+    if event.type ==  pygame.ACTIVEEVENT:
+     if self.debug: engine.debug_pr("active=%d, pygame.ACTIVEEVENT:" % pygame.display.get_active(), event)
+    if event.type == pygame.KEYUP:
+     k = event.key
+     if k == pygame.K_p:
+      time.sleep(10)
+     elif k == pygame.K_7:
+      self.myGame.soundtrack.pause()
+     elif k == pygame.K_l:
+      self.myGame.config['auto_scroll'] = True if self.myGame.config['auto_scroll'] == False else False
+
+    if event.type == pygame.USEREVENT:
+     if self.debug: engine.debug_pr("pygame.USEREVENT received; calling playlist_next()")
+     self.myGame.soundtrack.playlist_next()
+
+   if not self.myGame.config['auto_scroll']:
+    # reset if not auto-scrolling
+    movement = 0
+
+   # detect which keys are held down
+   keys_pressed = pygame.key.get_pressed()
+   if sum(keys_pressed):
+    if keys_pressed[pygame.K_6]:
+     # volume down
+     self.myGame.soundtrack.volume_down()
+    elif keys_pressed[pygame.K_8]:
+     # volume up
+     self.myGame.soundtrack.volume_up()
+    elif keys_pressed[pygame.K_d]:
+     # move right
+     movement = self.stepping
+    elif keys_pressed[pygame.K_a]:
+     # move left
+     movement = -self.stepping
+
+  # end of game
+  self.myGame.soundtrack.fadeout(5000)
+  time.sleep(5)
+  pygame.display.quit()
+
+
+def main(width, height, title, resources={}, debug=False):
+ game = Base2Runner(width, height, title, resources, debug)
+ game.play()
+ exit(0)
+
+if __name__ == '__main__':
+ resources = {}
+ resources['path'] = 'resources'
+ resources['icon'] = 'base2runner-icon.png'
+ resources['background'] = 'binary-1024x1024.jpg'
+ resources['soundtrack'] = 'Music'
+ main(900, 600, "BaseĀ² Runner", resources, debug=True)