Basics of 2D side-scrolling platform game
authorTJ <git@iam.tj>
Sat, 9 Nov 2013 20:23:25 +0000 (20:23 +0000)
committerTJ <git@iam.tj>
Sat, 9 Nov 2013 20:23:25 +0000 (20:23 +0000)
pygame-scroller.py [new file with mode: 0755]
resources/20661978_l.jpg [new file with mode: 0644]
resources/Music/Free Music Archive: Rolemusic - Savage Steel Fun Club.desktop [new file with mode: 0644]
resources/Music/Rolemusic_-_Savage_Steel_Fun_Club.mp3 [new file with mode: 0644]
resources/binary.jpg [new file with mode: 0644]

diff --git a/pygame-scroller.py b/pygame-scroller.py
new file mode 100755 (executable)
index 0000000..3a363b4
--- /dev/null
@@ -0,0 +1,189 @@
+#!/usr/bin/python3
+
+import sys, os, time, random, pygame
+
+DEBUG = True
+
+pygame.init()
+
+class Channel:
+ # use integers to control volume which avoids float rounding error issues
+ MAX = 100
+ MIN = 0
+ step = 5
+ def __init__(self, volume=1.0, channel_id=0): 
+  self.volume = int(volume*100)
+  self.channel_id = 0
+  if channel_id == -1:
+   self.channel_id = channel_id
+   self.channel = None # flag to show this uses pygame.mixer.music 
+  elif channel_id < pygame.mixer.get_num_channels():
+   self.channel_id = channel_id
+   self.channel = pygame.mixer.Channel(self.channel_id)
+
+ def set_volume(self, new_level):
+  if new_level >= Channel.MIN and new_level <= Channel.MAX:
+   self.volume = new_level
+   if self.channel == None:
+    pygame.mixer.music.set_volume(self.volume/100)
+   else:
+    self.channel.set_volume(self.volume/100)
+   if DEBUG: print("Channel.set_volume(", self.volume, ")")
+ def up(self):
+  if self.volume+self.step <= Channel.MAX:
+   self.set_volume(self.volume + self.step)
+ def down(self):
+  if self.volume-self.step >= Channel.MIN:
+   self.set_volume(self.volume - self.step)
+ def get(self):
+  return self.volume
+ def queue(self, sound):
+  if self.channel != None:
+   self.channel.queue(sound)
+ def get_queue(self):
+  return self.channel.get_queue() if self.channel != None else None
+ def play(self, sound, loops=0, maxtime=0, fade_ms=0):
+  if self.channel != None:
+   # allow 'sound' to be a path string or an object
+   sound = pygame.mixer.Sound(sound)
+   self.channel.play(sound, loops, maxtime, fade_ms)
+  else:
+   pygame.mixer.music.load(sound)
+   pygame.mixer.music.play(loops)
+
+# container for all game control and configuration items
+class Config:
+ config = dict()
+ soundtrack = Channel(channel_id=-1)
+ sound_effects = Channel(channel_id=0)
+ def __init__(self, width=0, height=0, title=""):
+  self.config.update({'width':width, 'height':height})
+  self.config.update({'title':title})
+  self.config.update({'sound':1})
+  self.play = False
+  self.resolution = width, height
+  self.debug = DEBUG
+
+class SeamlessBackground:
+ image_path = None
+ image = None
+ offset_x = 0
+ width = None
+ def __init__(self, filename, offset=0):
+  if os.path.exists(filename):
+   self.image_path = filename
+   self.image = pygame.image.load(self.image_path) #.convert()
+   self.offset = offset
+   self.width = self.image.get_size()[0]
+  if self.image == None:
+   print("Failed to load image", filename)
+
+ def draw(self, screen,  x_pos, step):
+  if DEBUG: print("SeamlessBackground(screen, %d, %d)" % (x_pos, step))
+  if self.image != None:
+   resolution = screen.get_size()
+   if step > 0:
+    x_pos = x_pos + resolution[0] - step
+   
+   bk_x_start = x_pos % self.width
+   bk_rect = pygame.Rect(bk_x_start, 0, abs(step) if step != 0 else resolution[0], resolution[1])
+   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 pixels because we're just wrapped around the background image
+    patch.blit(self.image, (4,0), pygame.Rect(0, 0, remainder, resolution[1]))
+    if DEBUG: print("Wrap-around, remainder=%d" % remainder)
+
+   scr_x_dest = resolution[0] - step if step > 0 else 0
+   if DEBUG: print("x_pos=%d, scr_x_dest=%d, bk_x_start=%d, bk_rect=%s" % (x_pos, scr_x_dest, bk_x_start, bk_rect))
+   screen.blit(patch, (scr_x_dest, 0))
+  else:
+   print("No image to draw")
+
+myGame = Config(1500, 1000)
+flags = pygame.OPENGL & pygame.DOUBLEBUF
+depth = 0
+
+# main loop sleep (100 milliseconds)
+delay = 0.01
+
+pygame.display.set_caption("TJ's platform scroller")
+
+# background colour
+stepping = 8 # pixels scrolled each flip
+background_colour = (20, 20, 64)
+screen = pygame.display.set_mode(myGame.resolution, flags, depth)
+resolution = screen.get_size()
+screen.fill(background_colour)
+
+# background image
+background_image = SeamlessBackground(os.path.join("resources", "binary.jpg"))
+background_image.draw(screen, 0, 0)
+pygame.display.flip()
+
+# scrolling object
+blip = pygame.Surface((abs(stepping), abs(stepping)), pygame.HWSURFACE)
+blip_colour = (128, 128, 128)
+blip.fill(blip_colour)
+
+# starting position
+y = resolution[1] / 2
+
+if myGame.config['sound'] == 1:
+ myGame.soundtrack.play(os.path.join("resources","Music","Rolemusic_-_Savage_Steel_Fun_Club.mp3"), loops=-1)
+
+x_pos = 0
+myGame.play = True
+while (myGame.play):
+ # update game state
+ x_pos += stepping
+
+ # 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 new 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 position up or down randomly by one step
+ dy = random.randrange(-1,2) * abs(stepping)
+ if((y + dy) < resolution[1] and (y + dy) >= 0):
+  # screen.fill(background_colour, pygame.Rect(resolution[0] - abs(stepping), y, abs(stepping), abs(stepping) ))
+  y += dy
+
+ # debug info
+ #if myGame.debug:
+  #print(y, blip_colour)
+
+ # redraw the display
+ screen.scroll(-stepping, 0)
+ background_image.draw(screen, x_pos, stepping)
+ screen.blit(blip, (resolution[0] - abs(stepping), y))
+ pygame.display.flip()
+ # manage the frame-rate
+ time.sleep(delay)
+
+ # process events
+ for event in pygame.event.get():
+  if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_q):
+   myGame.play = False
+  if event.type == pygame.KEYDOWN:
+   k = event.key
+   if k == pygame.K_p:
+    time.sleep(10)
+
+ keys_pressed = pygame.key.get_pressed()
+ if sum(keys_pressed):
+  if keys_pressed[pygame.K_6]:
+   # volume down
+   myGame.soundtrack.down()
+  elif keys_pressed[pygame.K_7]:
+   # volume up
+   myGame.soundtrack.up()
+
+time.sleep(10)
+pygame.display.quit()
+exit(0)
diff --git a/resources/20661978_l.jpg b/resources/20661978_l.jpg
new file mode 100644 (file)
index 0000000..c8b0046
Binary files /dev/null and b/resources/20661978_l.jpg differ
diff --git a/resources/Music/Free Music Archive: Rolemusic - Savage Steel Fun Club.desktop b/resources/Music/Free Music Archive: Rolemusic - Savage Steel Fun Club.desktop
new file mode 100644 (file)
index 0000000..6c4ee31
--- /dev/null
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=Link to Free Music Archive: Rolemusic - Savage Steel Fun Club
+Type=Link
+URL=http://freemusicarchive.org/music/Rolemusic/~/Savage_Steel_Fun_Club
+Icon=text-html
diff --git a/resources/Music/Rolemusic_-_Savage_Steel_Fun_Club.mp3 b/resources/Music/Rolemusic_-_Savage_Steel_Fun_Club.mp3
new file mode 100644 (file)
index 0000000..7db5c20
Binary files /dev/null and b/resources/Music/Rolemusic_-_Savage_Steel_Fun_Club.mp3 differ
diff --git a/resources/binary.jpg b/resources/binary.jpg
new file mode 100644 (file)
index 0000000..08d3321
Binary files /dev/null and b/resources/binary.jpg differ