3 import sys, os, time, random, pygame
10 # use integers to control volume which avoids float rounding error issues
14 def __init__(self, volume=1.0, channel_id=0):
15 self.volume = int(volume*100)
18 self.channel_id = channel_id
19 self.channel = None # flag to show this uses pygame.mixer.music
20 elif channel_id < pygame.mixer.get_num_channels():
21 self.channel_id = channel_id
22 self.channel = pygame.mixer.Channel(self.channel_id)
24 def set_volume(self, new_level):
25 if new_level >= Channel.MIN and new_level <= Channel.MAX:
26 self.volume = new_level
27 if self.channel == None:
28 pygame.mixer.music.set_volume(self.volume/100)
30 self.channel.set_volume(self.volume/100)
31 if DEBUG: print("Channel.set_volume(", self.volume, ")")
33 if self.volume+self.step <= Channel.MAX:
34 self.set_volume(self.volume + self.step)
36 if self.volume-self.step >= Channel.MIN:
37 self.set_volume(self.volume - self.step)
40 def queue(self, sound):
41 if self.channel != None:
42 self.channel.queue(sound)
44 return self.channel.get_queue() if self.channel != None else None
45 def fadeout(self, time):
46 if self.channel == None:
47 pygame.mixer.music.fadeout(time)
49 self.channel.fadeout(time)
50 def play(self, sound, loops=0, maxtime=0, fade_ms=0):
51 if self.channel != None:
52 # allow 'sound' to be a path string or an object
53 sound = pygame.mixer.Sound(sound)
54 self.channel.play(sound, loops, maxtime, fade_ms)
56 pygame.mixer.music.load(sound)
57 pygame.mixer.music.play(loops)
59 # container for all game control and configuration items
62 soundtrack = Channel(channel_id=-1)
63 sound_effects = Channel(channel_id=0)
64 def __init__(self, width=0, height=0, title=""):
65 self.config.update({'width':width, 'height':height})
66 self.config.update({'title':title})
67 self.config.update({'sound':1})
69 self.resolution = width, height
72 class SeamlessBackground:
77 def __init__(self, filename, offset=0):
78 if os.path.exists(filename):
79 self.image_path = filename
80 self.image = pygame.image.load(self.image_path) #.convert()
82 self.width = self.image.get_size()[0]
83 if self.image == None:
84 print("Failed to load image", filename)
86 def draw(self, screen, x_pos, step):
87 if DEBUG: print("SeamlessBackground(screen, %d, %d)" % (x_pos, step))
88 if self.image != None:
89 resolution = screen.get_size()
91 x_pos = x_pos + resolution[0] - step
93 bk_x_start = x_pos % self.width
94 bk_rect = pygame.Rect(bk_x_start, 0, abs(step) if step != 0 else resolution[0], resolution[1])
95 patch = pygame.Surface((bk_rect.width, bk_rect.height))
96 patch.blit(self.image, (0, 0), bk_rect)
97 remainder = self.width - bk_x_start
98 if remainder < abs(step):
99 # need more pixels because we're just wrapped around the background image
100 patch.blit(self.image, (4,0), pygame.Rect(0, 0, remainder, resolution[1]))
101 if DEBUG: print("Wrap-around, remainder=%d" % remainder)
103 scr_x_dest = resolution[0] - step if step > 0 else 0
104 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))
105 screen.blit(patch, (scr_x_dest, 0))
107 print("No image to draw")
109 myGame = Config(1500, 1000)
110 flags = pygame.OPENGL & pygame.DOUBLEBUF
113 # main loop sleep (100 milliseconds)
116 pygame.display.set_caption("TJ's platform scroller")
119 stepping = 8 # pixels scrolled each flip
120 background_colour = (20, 20, 64)
121 screen = pygame.display.set_mode(myGame.resolution, flags, depth)
122 resolution = screen.get_size()
123 screen.fill(background_colour)
126 background_image = SeamlessBackground(os.path.join("resources", "binary.jpg"))
127 background_image.draw(screen, 0, 0)
128 pygame.display.flip()
131 blip = pygame.Surface((abs(stepping), abs(stepping)), pygame.HWSURFACE)
132 blip_colour = (128, 128, 128)
133 blip.fill(blip_colour)
136 y = resolution[1] / 2
138 if myGame.config['sound'] == 1:
139 myGame.soundtrack.play(os.path.join("resources","Music","Rolemusic_-_Savage_Steel_Fun_Club.mp3"), loops=-1)
147 if x_pos + movement >= 0:
153 # change colour randomly
154 d_red = random.randrange(-1,2) *8
155 d_green = random.randrange(-1,2) *8
156 d_blue = random.randrange(-1,2) *8
157 # build a new tuple, ensuring all values are valid
158 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)) )
159 blip.fill(blip_colour)
161 # change position up or down randomly by one step
162 dy = random.randrange(-1,2) * abs(stepping)
163 if((y + dy) < resolution[1] and (y + dy) >= 0):
164 # screen.fill(background_colour, pygame.Rect(resolution[0] - abs(stepping), y, abs(stepping), abs(stepping) ))
169 #print(y, blip_colour)
172 screen.scroll(-movement, 0)
173 background_image.draw(screen, x_pos, stepping)
174 screen.blit(blip, (resolution[0] - abs(stepping), y))
175 pygame.display.flip()
177 # manage the frame-rate
181 for event in pygame.event.get():
182 if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_q):
184 if event.type == pygame.KEYDOWN:
190 keys_pressed = pygame.key.get_pressed()
191 if sum(keys_pressed):
192 if keys_pressed[pygame.K_6]:
194 myGame.soundtrack.down()
195 elif keys_pressed[pygame.K_7]:
197 myGame.soundtrack.up()
198 elif keys_pressed[pygame.K_d]:
200 elif keys_pressed[pygame.K_a]:
202 elif keys_pressed[pygame.K_l]:
203 auto_scroll = True if auto_scroll == False else False
205 myGame.soundtrack.fadeout(10000)
207 pygame.display.quit()