1 | from random import randrange |
||
2 | |||
3 | import pygame |
||
4 | |||
5 | __release__ = "04/05/2020" |
||
6 | __version__ = 2.0 |
||
7 | |||
8 | |||
9 | class Game: |
||
10 | |||
11 | def __init__(self): |
||
12 | pygame.init() |
||
13 | pygame.mixer.init() |
||
14 | |||
15 | self.clock = pygame.time.Clock() |
||
16 | self.screen = pygame.display.set_mode((1280, 720)) |
||
17 | |||
18 | pygame.display.set_icon(load("assets/images/icon.png")) |
||
19 | self.font = { |
||
20 | size: pygame.font.Font("assets/fonts/setbackt.ttf", size) |
||
21 | for size in (48, 64, 96, 128) |
||
22 | } |
||
23 | |||
24 | self.show_fps = True |
||
25 | self.player = Player() |
||
26 | |||
27 | self.run = True |
||
28 | self.pause = False |
||
29 | self.over = False |
||
30 | |||
31 | self.textures = { |
||
32 | "bg": load("assets/images/bg.png"), |
||
33 | "platform": load("assets/images/platform.png"), |
||
34 | "bullet": load("assets/images/bullet-bill.png") |
||
35 | } |
||
36 | |||
37 | self.events = { |
||
38 | pygame.K_ESCAPE: self.pause_screen, |
||
39 | pygame.K_SPACE: self.player.jump, |
||
40 | pygame.K_d: self.player.accelerate, |
||
41 | pygame.K_a: self.player.decelerate, |
||
42 | pygame.K_f: self.toggle_fps |
||
43 | } |
||
44 | |||
45 | self.platforms = [] |
||
46 | self.bullets = [] |
||
47 | self.backgrounds = [] |
||
48 | self.limit = 4000 |
||
49 | self.score = 0 |
||
50 | |||
51 | def setup(self): |
||
52 | pygame.mixer.music.load("assets/musics/music.mp3") |
||
53 | pygame.mixer.music.set_volume(0.4) |
||
54 | pygame.mixer.music.play() |
||
55 | |||
56 | self.platforms = [ |
||
57 | Platform(x, y) for x, y in ((280, 620), (960, 640), (1620, 660)) |
||
58 | ] |
||
59 | |||
60 | self.bullets = [Bullet() for _ in range(3)] |
||
61 | self.player.reset() |
||
62 | self.backgrounds = [ScrollingBackground(1280), ScrollingBackground(0)] |
||
63 | self.over = False |
||
64 | self.limit = 4000 |
||
65 | self.score = 0 |
||
66 | |||
67 | def toggle_fps(self): |
||
68 | self.show_fps = not self.show_fps |
||
69 | |||
70 | def main(self): |
||
71 | self.setup() |
||
72 | |||
73 | while self.run: |
||
74 | self.screen.fill((121, 201, 249), ((0, 0), (1280, 360))) |
||
75 | self.screen.fill((127, 173, 113), ((0, 593), (1280, 720))) |
||
76 | for background in self.backgrounds: |
||
77 | background.update() |
||
78 | self.screen.blit( |
||
79 | self.textures["bg"], |
||
80 | (background.rect.x, 350), |
||
81 | (0, 0, 1280, 360) |
||
82 | ) |
||
83 | |||
84 | for platform in self.platforms: |
||
85 | platform.check_hit_box() |
||
86 | platform.move() |
||
87 | self.screen.blit(self.textures["platform"], platform.rect) |
||
88 | |||
89 | self.player.move() |
||
90 | self.player.apply_gravity() |
||
91 | self.screen.blit(self.player.texture, self.player.rect) |
||
92 | |||
93 | for bullet in self.bullets: |
||
94 | bullet.move() |
||
95 | self.screen.blit(game.textures["bullet"], bullet.rect) |
||
0 ignored issues
–
show
introduced
by
![]() |
|||
96 | bullet.check_hit_box() |
||
97 | |||
98 | if len(self.bullets) < 3: |
||
99 | self.bullets.append(Bullet()) |
||
100 | |||
101 | pygame.draw.rect( |
||
102 | self.screen, (255, 255, 255), ((5, 5), (1270, 710)), 3 |
||
103 | ) |
||
104 | |||
105 | for event in pygame.event.get(): |
||
106 | if event.type == pygame.KEYDOWN: |
||
107 | if event.key in self.events: |
||
108 | self.events[event.key]() |
||
109 | |||
110 | elif event.type == pygame.KEYUP: |
||
111 | if event.key == pygame.K_SPACE: |
||
112 | self.player.jump_available = True |
||
113 | |||
114 | elif event.key in [pygame.K_a, pygame.K_d]: |
||
115 | self.player.walk() |
||
116 | |||
117 | elif event.type == pygame.QUIT: |
||
118 | self.run = False |
||
119 | |||
120 | if self.over: |
||
121 | self.over_screen() |
||
122 | |||
123 | else: |
||
124 | pygame.display.set_caption( |
||
125 | f"Duck Jump 2 | score : {self.score}" |
||
126 | + f"| {self.clock.get_fps()} " * self.show_fps |
||
127 | ) |
||
128 | |||
129 | pygame.display.update() |
||
130 | self.score += int(self.player.ax) |
||
131 | self.clock.tick(100) |
||
132 | |||
133 | def pause_screen(self): |
||
134 | pygame.mixer.music.pause() |
||
135 | self.fade((0, 128, 255, 1), 64) |
||
136 | pygame.display.set_caption( |
||
137 | "Duck Jump 2 | score : %i | Paused" % self.score |
||
138 | ) |
||
139 | |||
140 | self.screen.blit( |
||
141 | *get_text( |
||
142 | "Paused", |
||
143 | self.font[96], |
||
144 | (255, 255, 255), |
||
145 | (640, 300), |
||
146 | centered=True) |
||
147 | ) |
||
148 | |||
149 | self.screen.blit( |
||
150 | *get_text( |
||
151 | "press escape to unpause", |
||
152 | self.font[48], |
||
153 | (255, 255, 255), |
||
154 | (640, 400), |
||
155 | centered=True |
||
156 | ) |
||
157 | ) |
||
158 | pygame.display.update() |
||
159 | |||
160 | self.pause = True |
||
161 | while self.pause: |
||
162 | event = pygame.event.wait() |
||
163 | if event.type == pygame.KEYDOWN: |
||
164 | if event.key == pygame.K_ESCAPE: |
||
165 | pygame.mixer.music.unpause() |
||
166 | pygame.event.clear() |
||
167 | self.pause = False |
||
168 | |||
169 | elif event.type == pygame.QUIT: |
||
170 | self.pause = False |
||
171 | self.run = False |
||
172 | |||
173 | def over_screen(self): |
||
174 | pygame.mixer.music.pause() |
||
175 | self.fade((255, 32, 32, 1), 128) |
||
176 | pygame.display.set_caption( |
||
177 | "Duck Jump 2 | score : %i | GameOver" % self.score |
||
178 | ) |
||
179 | |||
180 | self.screen.blit( |
||
181 | *get_text( |
||
182 | "Game Over", |
||
183 | self.font[96], |
||
184 | (255, 255, 255), |
||
185 | (640, 300), |
||
186 | centered=True |
||
187 | ) |
||
188 | ) |
||
189 | |||
190 | self.screen.blit( |
||
191 | *get_text( |
||
192 | "press space to retry", |
||
193 | self.font[48], |
||
194 | (255, 255, 255), |
||
195 | (640, 400), |
||
196 | centered=True |
||
197 | ) |
||
198 | ) |
||
199 | |||
200 | pygame.display.update() |
||
201 | |||
202 | self.pause = True |
||
203 | while self.pause: |
||
204 | event = pygame.event.wait() |
||
205 | if event.type == pygame.KEYDOWN: |
||
206 | if event.key == pygame.K_SPACE: |
||
207 | game.setup() |
||
0 ignored issues
–
show
|
|||
208 | self.pause = False |
||
209 | |||
210 | elif event.type == pygame.QUIT: |
||
211 | self.pause = False |
||
212 | self.run = False |
||
213 | |||
214 | def fade(self, c, iterations): |
||
215 | alpha_layer = pygame.Surface((1280, 720), pygame.SRCALPHA) |
||
216 | alpha_layer.fill(c) |
||
217 | |||
218 | for _ in range(iterations): |
||
219 | self.screen.blit(alpha_layer, (0, 0)) |
||
220 | |||
221 | pygame.draw.rect( |
||
222 | self.screen, (255, 255, 255), ((5, 5), (1270, 710)), 3 |
||
223 | ) |
||
224 | |||
225 | for e in pygame.event.get(): |
||
226 | if e.type == pygame.QUIT: |
||
227 | break |
||
228 | |||
229 | pygame.display.update() |
||
230 | |||
231 | |||
232 | class Platform: |
||
233 | |||
234 | def __init__(self, x, y): |
||
235 | self.rect = game.textures["platform"].get_rect() |
||
0 ignored issues
–
show
|
|||
236 | self.rect.x, self.rect.y = x, y |
||
237 | self.initial_y = self.rect.y |
||
238 | |||
239 | def move(self): |
||
240 | if self.rect.x < -500: |
||
241 | self.rect.x = max( |
||
242 | platform.rect.x for platform in game.platforms |
||
0 ignored issues
–
show
|
|||
243 | ) + randrange(600, 1000) |
||
244 | |||
245 | self.rect.y = randrange(400, 620) |
||
246 | self.initial_y = self.rect.y |
||
247 | |||
248 | else: |
||
249 | self.rect.x -= int(game.player.ax) |
||
250 | |||
251 | def check_hit_box(self): |
||
252 | if any( |
||
253 | [ |
||
254 | self.rect.collidepoint( |
||
255 | game.player.rect.x, game.player.rect.y + 68 |
||
0 ignored issues
–
show
|
|||
256 | ), |
||
257 | self.rect.collidepoint( |
||
258 | game.player.rect.x + 50, game.player.rect.y + 68 |
||
259 | ) |
||
260 | ] |
||
261 | ): |
||
262 | |||
263 | game.player.rect.y = self.rect.y - 68 + 1 |
||
264 | game.player.jump_count = 1 |
||
265 | self.rect.x += randrange(0, 2) - 1 |
||
266 | self.rect.y += 2 |
||
267 | |||
268 | elif self.rect.y > self.initial_y: |
||
269 | self.rect.y -= 1 |
||
270 | |||
271 | if any( |
||
272 | [ |
||
273 | self.rect.collidepoint( |
||
274 | game.player.rect.x + 50, game.player.rect.y |
||
275 | ), |
||
276 | self.rect.collidepoint( |
||
277 | game.player.rect.x + 50, game.player.rect.y + 66 |
||
278 | ) |
||
279 | ] |
||
280 | ): |
||
281 | game.player.rect.x = self.rect.x - 51 |
||
282 | if game.player.rect.x < 0: |
||
283 | game.over = True |
||
284 | |||
285 | |||
286 | class ScrollingBackground: |
||
287 | |||
288 | def __init__(self, offset): |
||
289 | self.rect = game.textures["bg"].get_rect() |
||
0 ignored issues
–
show
|
|||
290 | self.rect.x = offset |
||
291 | |||
292 | def update(self): |
||
293 | self.rect.x = self.rect.x - 1 if self.rect.x > -1280 else 1280 |
||
294 | |||
295 | |||
296 | class Bullet: |
||
297 | |||
298 | def __init__(self): |
||
299 | self.rect = game.textures["bullet"].get_rect() |
||
0 ignored issues
–
show
|
|||
300 | self.rect.x, self.rect.y = randrange(1300, 3000), randrange(720) |
||
301 | |||
302 | def move(self): |
||
303 | if self.rect.x < -50: |
||
304 | self.rect.x = randrange(1300, 3000) |
||
305 | self.rect.y = randrange(100, 620) |
||
306 | else: |
||
307 | self.rect.x -= 2 * int(game.player.ax) |
||
0 ignored issues
–
show
|
|||
308 | |||
309 | def check_hit_box(self): |
||
310 | if self.rect.colliderect(game.player.rect): |
||
0 ignored issues
–
show
|
|||
311 | print(game.player.rect) |
||
312 | game.over = True |
||
313 | |||
314 | |||
315 | class Player: |
||
316 | |||
317 | def __init__(self): |
||
318 | self.jump_sound = pygame.mixer.Sound("assets/sounds/jump.wav") |
||
319 | self.texture = load("assets/images/duck3.png") |
||
320 | self.rect = self.texture.get_rect() |
||
321 | self.rect.x, self.rect.y = 300, -100 |
||
322 | |||
323 | self.ax = 0 |
||
324 | self.ay = 0 |
||
325 | self.gravity = 0.1 |
||
326 | self.max_speed_y = 8 |
||
327 | self.max_speed_x = 10 |
||
328 | self.jump_count = 2 |
||
329 | self.currently_in_jump = False |
||
330 | self.jump_available = True |
||
331 | self.behavior = "walk" |
||
332 | |||
333 | def reset(self): |
||
334 | self.rect.x = 300 |
||
335 | self.rect.y = -100 |
||
336 | self.behavior = "walk" |
||
337 | self.ax = 0 |
||
338 | self.ay = 0 |
||
339 | |||
340 | def move(self): |
||
341 | if self.behavior == "walk": |
||
342 | self.ax += 0.2 if self.ax < 4 else -0.2 |
||
343 | |||
344 | elif self.behavior == "accelerate": |
||
345 | self.ax = self.max_speed_x \ |
||
346 | if self.ax > self.max_speed_x else self.ax + 0.6 |
||
347 | |||
348 | else: |
||
349 | self.ax = 1 if self.ax <= 1 else self.ax - 0.2 |
||
350 | |||
351 | def jump(self): |
||
352 | if self.jump_available and self.jump_count: |
||
353 | self.jump_sound.play() |
||
354 | self.ay = -self.max_speed_y |
||
355 | self.jump_count -= 1 |
||
356 | |||
357 | if not self.currently_in_jump: |
||
358 | self.currently_in_jump = True |
||
359 | |||
360 | self.jump_available = False |
||
361 | |||
362 | def apply_gravity(self): |
||
363 | |||
364 | self.ay += self.gravity |
||
365 | if self.ay > self.max_speed_y: |
||
366 | self.ay = self.max_speed_y |
||
367 | |||
368 | elif self.ay < -self.max_speed_y: |
||
369 | self.ay = -self.max_speed_y |
||
370 | |||
371 | self.rect.y += int(self.ay) |
||
372 | if self.rect.y < 0: |
||
373 | self.rect.y = 0 |
||
374 | |||
375 | elif self.rect.y > 720: |
||
376 | game.over = True |
||
0 ignored issues
–
show
|
|||
377 | |||
378 | def accelerate(self): |
||
379 | self.behavior = "accelerate" |
||
380 | |||
381 | def decelerate(self): |
||
382 | self.behavior = "decelerate" |
||
383 | |||
384 | def walk(self): |
||
385 | self.behavior = "walk" |
||
386 | |||
387 | |||
388 | def load(path, alpha=True): |
||
389 | return pygame.image.load(path).convert_alpha() \ |
||
390 | if alpha else pygame.image.load(path).convert() |
||
391 | |||
392 | |||
393 | def get_text(text, font, c, pos, centered=False): |
||
394 | text = font.render(text, True, c, None) |
||
395 | text_rect = text.get_rect() |
||
396 | if centered: |
||
397 | text_rect.center = pos |
||
398 | else: |
||
399 | text_rect.x, text_rect.y = pos |
||
400 | return text, text_rect |
||
401 | |||
402 | |||
403 | if __name__ == "__main__": |
||
404 | game = Game() |
||
405 | game.main() |
||
406 |