forked from Prophetwei/group7_project
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
556 lines (461 loc) · 23.7 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
import pygame
import pandas as pd
# Initialize Pygame
pygame.init()
pygame.mixer.init()
# Set up display
WIDTH, HEIGHT = 500, 500
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Flappy Bird")
# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (192, 192, 192)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
GOLD = (255, 215, 0)
BLUE = (0, 0, 255)
# Load Sound files
jump_sound = pygame.mixer.Sound('final/audio/jump1.wav')
jump_sound.set_volume(1.0) # Set the volume to 100%
score_sound = pygame.mixer.Sound('final/audio/score.wav')
game_over_sound = pygame.mixer.Sound('final/audio/game_over.wav')
game_over_sound.set_volume(1.0) # Set the volume to 100%
pygame.time.delay(1000)
background_music = pygame.mixer.music.load('final/audio/background.wav')
background_music2 = pygame.mixer.music.load('final/audio/background_music2.wav')
pygame.mixer.music.set_volume(0.5)
# Score
font = pygame.font.SysFont(None, 30)
# Background image
background_image = pygame.image.load('final/images/background.jpg')
background_image = pygame.transform.scale(background_image, (WIDTH, HEIGHT))
# Return button image
return_button_image = pygame.image.load('final/images/return.png')
return_button_image = pygame.transform.scale(return_button_image, (50, 50))
# Left button image
left_button_image = pygame.image.load('final/images/left.png').convert_alpha()
left_button_image = pygame.transform.scale(left_button_image, (50, 50))
# Right button image
right_button_image = pygame.image.load('final/images/right.png').convert_alpha()
right_button_image = pygame.transform.scale(right_button_image, (50, 50))
# Setting button image
setting_button_image = pygame.image.load('final/images/setting.png').convert_alpha()
setting_button_image = pygame.transform.scale(setting_button_image, (50, 50))
# Pause button image
pause_button_image = pygame.image.load('final/images/pause.png').convert_alpha()
pause_button_image = pygame.transform.scale(pause_button_image, (50, 50))
# Sound button image
louder_button_image = pygame.image.load('final/images/loudersound.png').convert_alpha()
louder_button_image = pygame.transform.scale(louder_button_image, (50, 50))
lower_button_image = pygame.image.load('final/images/lowersound.png').convert_alpha()
lower_button_image = pygame.transform.scale(lower_button_image, (50, 50))
mute_button_image = pygame.image.load('final/images/mute.png').convert_alpha()
mute_button_image = pygame.transform.scale(mute_button_image, (50, 50))
# bird image
Normal_Bird_image = pygame.image.load('final/images/normal bird.png').convert_alpha()
Lazy_Bird_image = pygame.image.load('final/images/lazy bird.png').convert_alpha()
Small_Bird_image = pygame.image.load('final/images/small bird.png').convert_alpha()
from final.button import Button, ImagesButton
from final.gameobject import GameObject, RegularPlayer, HeavyPlayer, SmallPlayer, Obstacle
class Game:
BUTTON_GAP = 20
def __init__(self):
self.players = [RegularPlayer, HeavyPlayer, SmallPlayer] # List of player classes
self.player_parameters = [(50, HEIGHT // 2 - 25, 50, Normal_Bird_image),
(50, HEIGHT // 2 - 25, 50, Lazy_Bird_image),
(50, HEIGHT // 2 - 25, 30, Small_Bird_image)] # List of player classes
self.current_player_index = 0 # Start with the first player class
self.player = self.get_current_player() # Get the current player object
self.obstacles = []
self.score = 0
self.best_scores = [0] # List to store all scores obtained from previous games
# Create buttons
self.create_buttons()
# Play background music
background_music2 = pygame.mixer.music.load('final/audio/background_music2.wav')
pygame.mixer.music.play(-1)
self.game_started = False
self.game_over = False
# Create current player image
self.current_player_image = pygame.Surface((50, 50))
self.current_player_image_rect = self.current_player_image.get_rect(center=(WIDTH // 2, HEIGHT // 2))
self.paused = False
def create_buttons(self):
# Start button
button_width, button_height = 100, 50
button_x = (WIDTH - button_width) // 2
start_button_y = HEIGHT // 2 - button_height - self.BUTTON_GAP // 2
self.start_button = Button(button_x, start_button_y, button_width, button_height, GRAY, 'Start')
# Ranking button
ranking_button_y = start_button_y + self.BUTTON_GAP * 8 # Adjusted gap
self.ranking_button = Button(button_x, ranking_button_y, button_width, button_height, GRAY, 'Ranking')
# Select button
select_button_y = start_button_y + self.BUTTON_GAP * 4 # Adjusted gap
self.select_button = Button(button_x, select_button_y, button_width, button_height, GRAY, 'Select')
#Setting button
setting_button_x = WIDTH - 50 # Adjusted x-coordinate
setting_button_y = 0 # Adjusted y-coordinate
self.setting_button = ImagesButton(setting_button_x, setting_button_y, button_width, button_height, setting_button_image)
# Create left button
left_button_width, left_button_height = 50, 50
left_button_x = WIDTH // 2 - 100
left_button_y = HEIGHT // 2
self.left_button = ImagesButton(left_button_x, left_button_y, left_button_width, left_button_height, left_button_image)
# Create right button
right_button_width, right_button_height = 50, 50
right_button_x = WIDTH // 2 + 50
right_button_y = HEIGHT // 2
self.right_button = ImagesButton(right_button_x, right_button_y, right_button_width, right_button_height, right_button_image)
# Create pause button
pause_button_x = WIDTH - 50
pause_button_y = 0
self.pause_button = ImagesButton(pause_button_x, pause_button_y, 50, 50, pause_button_image)
# Create resume button
resume_button_width, resume_button_height = 150, 50
resume_button_x = (WIDTH - resume_button_width) // 2
resume_button_y = HEIGHT // 2 + 50
self.resume_button = Button(resume_button_x, resume_button_y, resume_button_width, resume_button_height, GRAY, 'Resume')
# Create restart button
restart_button_width, restart_button_height = 150, 50
restart_button_x = (WIDTH - restart_button_width) // 2
restart_button_y = HEIGHT // 2 + 120
self.restart_button = Button(restart_button_x, restart_button_y, restart_button_width, restart_button_height, GRAY, 'Restart')
def draw_score(self):
score_text = font.render(f"Score: {self.score}", True, WHITE)
WIN.blit(score_text, (10, 10))
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
if event.type == pygame.MOUSEBUTTONDOWN:
if not self.game_started and not self.game_over:
if self.start_button.is_clicked(pygame.mouse.get_pos()):
self.start_game()
elif self.ranking_button.is_clicked(pygame.mouse.get_pos()):
self.show_ranking()
elif self.select_button.is_clicked(pygame.mouse.get_pos()):
self.show_character_select_window() # Show character select window when select button is clicked
elif self.setting_button.is_clicked(pygame.mouse.get_pos()):
self.show_setting_window()
elif self.game_over:
if self.start_button.is_clicked(pygame.mouse.get_pos()):
self.start_game() # Restart the game when start button is clicked
elif self.ranking_button.is_clicked(pygame.mouse.get_pos()):
self.show_ranking() # Show ranking when ranking button is clicked
elif self.select_button.is_clicked(pygame.mouse.get_pos()):
self.show_character_select_window() # Show character select window when select button is clicked
elif self.setting_button.is_clicked(pygame.mouse.get_pos()):
self.show_setting_window() #Show setting window when setting button is clicked
elif self.paused:
if self.resume_button.is_clicked(pygame.mouse.get_pos()):
self.paused = False
elif self.restart_button.is_clicked(pygame.mouse.get_pos()):
self.start_game()
self.paused = False
else:
if self.pause_button.is_clicked(pygame.mouse.get_pos()):
self.paused = True
if event.type == pygame.KEYDOWN and self.game_started and not self.paused: # Only handle key events when the game is started
if event.key == pygame.K_SPACE:
self.player.jump()
jump_sound.play()
elif event.key == pygame.K_p:
self.paused = not self.paused
return True
def start_game(self):
self.game_started = True
self.score = 0
self.player.rect.y = HEIGHT // 2 - 25
self.player.vel = 0 # Reset player's velocity
self.obstacles = []
self.game_over = False
self.gap = 200
if self.current_player_index == 0:
self.obstacles_distance = 200
elif self.current_player_index == 1:
self.obstacles_distance = 300
elif self.current_player_index == 2:
self.obstacles_distance = 150
pygame.mixer.music.stop()
background_music = pygame.mixer.music.load('final/audio/background.wav')
pygame.mixer.music.play(-1) # Play the new background music indefinitely
def update(self):
if self.game_started and not self.paused: # Update the game only if it's not paused
self.player.rect.y += self.player.vel
self.player.vel += 1
if self.player.rect.y <= 0 or self.player.rect.y + self.player.rect.height >= HEIGHT:
self.end_game()
if len(self.obstacles) == 0 or self.obstacles[-1].rect.x < WIDTH - self.obstacles_distance:
Obstacle.generate_obstacle(WIDTH, self.obstacles, self.gap)
self.gap = self.gap - 5 if self.gap > 70 else 70
for obstacle in self.obstacles:
obstacle.rect.x -= 5
if obstacle.rect.colliderect(self.player.rect):
self.end_game()
else:
if not obstacle.collided and obstacle.rect.x + obstacle.rect.width < self.player.rect.x:
obstacle.collided = True
score_sound.play()
if obstacle.color == GREEN:
self.score += 1
elif obstacle.color == RED:
self.score += 3
elif obstacle.color == GOLD:
self.score += 5
self.obstacles = [obstacle for obstacle in self.obstacles if obstacle.rect.x + obstacle.rect.width > 0]
return True
def draw(self):
if not self.paused: # Only draw game elements if the game is not paused
WIN.blit(background_image, (0, 0))
self.player.draw(WIN)
for obstacle in self.obstacles:
obstacle.draw(WIN)
self.draw_score()
if not self.game_started:
if not self.game_over:
self.start_button.draw(WIN, WHITE)
self.select_button.draw(WIN, WHITE)
self.ranking_button.draw(WIN, WHITE)
self.setting_button.draw(WIN)
else:
self.start_button.draw(WIN, WHITE)
self.select_button.draw(WIN, WHITE)
self.ranking_button.draw(WIN, WHITE)
self.setting_button.draw(WIN)
elif self.game_started and not self.game_over:
self.pause_button.draw(WIN)
pygame.display.update()
else:
# Draw pause text
font = pygame.font.SysFont('comicsans', 50)
text = font.render('Paused', 1, WHITE)
WIN.blit(text, (WIDTH // 2 - text.get_width() // 2, HEIGHT // 2 - text.get_height() // 2))
# Draw resume button
self.resume_button.draw(WIN)
#Draw restart button
self.restart_button.draw(WIN)
pygame.display.update()
def end_game(self):
self.game_started = False
self.game_over = True
self.best_scores.append(self.score) # Add the current score to the list of all scores
self.best_scores.sort(reverse=True) # Sort the list of all scores in descending order
self.best_scores = self.best_scores[:10] # Keep only the top 10 scores
self.player.vel = 0 # Reset the player's velocity for the next game
self.paused = False # Ensure the game is not paused when ending
pygame.mixer.music.stop()
game_over_sound.play()
background_music2 = pygame.mixer.music.load('final/audio/background_music2.wav')
pygame.mixer.music.play(-1) # Play the new background music indefinitely
# Display scores using Pandas
self.display_scores_with_pandas()
# Export scores to CSV
self.export_scores_to_csv()
def display_scores_with_pandas(self):
# Ensure there are at least 3 scores
while len(self.best_scores) < 3:
self.best_scores.append(0)
scorelist = self.best_scores[:-2]
# Create a DataFrame
df = pd.DataFrame(scorelist, columns=['Score'])
df.index.name = 'Rank'
df.index += 1 # Rank starts from 1
print("Best Scores DataFrame:")
print(df)
def export_scores_to_csv(self, filename='best_scores.csv'):
# Ensure there are at least 3 scores
while len(self.best_scores) < 3:
self.best_scores.append(0)
scorelist = self.best_scores[:-2]
# Create a DataFrame
df = pd.DataFrame(scorelist, columns=['Score'])
df.index.name = 'Rank'
df.index += 1 # Rank starts from 1
# Save the DataFrame to a CSV file
df.to_csv(filename)
def read_scores_from_csv(self, filename='best_scores.csv'):
# Read the scores from the CSV file into a DataFrame
df = pd.read_csv(filename, index_col='Rank')
# Update best_scores list with the scores from the DataFrame
self.best_scores = df['Score'].tolist()
def show_ranking(self):
ranking = self.best_scores[:3] # Get the best scores
while len(ranking) < 3: # Fill the remaining slots with zeros if needed
ranking.append(0)
ranking_screen = True
return_button_x = (WIDTH - 50) // 2
return_button_y = HEIGHT - 100
return_button_rect = pygame.Rect(return_button_x, return_button_y, 50, 50)
while ranking_screen:
WIN.blit(background_image, (0, 0))
font = pygame.font.SysFont('comicsans', 40)
title = font.render('Best Scores', 1, WHITE)
WIN.blit(title, (WIDTH // 2 - title.get_width() // 2, 50))
for i, score in enumerate(ranking):
text = font.render(str(score), 1, WHITE)
WIN.blit(text, (WIDTH // 2 - text.get_width() // 2, 150 + i * 50))
# Draw return button
WIN.blit(return_button_image, (return_button_x, return_button_y))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.MOUSEBUTTONDOWN:
if return_button_rect.collidepoint(event.pos): # Check if return button is clicked
ranking_screen = False
def show_character_select_window(self):
# Character select window
character_select_window = True
return_button_x = (WIDTH - 50) // 2
return_button_y = HEIGHT - 100
return_button_rect = pygame.Rect(return_button_x, return_button_y, 50, 50)
while character_select_window:
WIN.blit(background_image, (0, 0)) # Draw background image
# Draw current player's image
self.update_current_player_image()
# Draw text describing player characteristics
font = pygame.font.SysFont('comicsans', 24)
text = font.render(self.get_current_player_description(), 1, BLACK)
text_rect = text.get_rect(center=(WIDTH // 2, HEIGHT // 2 + 70))
# Create a surface with a white background
description_surface = pygame.Surface((text_rect.width + 10, text_rect.height + 10))
description_surface.fill(WHITE)
# Blit the text onto the description surface
description_surface.blit(text, (5, 5))
# Blit the description surface onto the window
WIN.blit(description_surface, (text_rect.x - 5, text_rect.y - 5))
self.left_button.draw(WIN)
self.right_button.draw(WIN)
# Draw return button
WIN.blit(return_button_image, (return_button_x, return_button_y))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == pygame.MOUSEBUTTONDOWN:
# Check if left button is clicked
if self.left_button.rect.collidepoint(event.pos):
# Switch to the previous character
self.player = self.switch_to_previous_character()
# Redraw the current player's image
self.update_current_player_image()
# Check if right button is clicked
elif self.right_button.rect.collidepoint(event.pos):
# Switch to the next character
self.player = self.switch_to_next_character()
# Redraw the current player's image
self.update_current_player_image()
# Check if return button is clicked
elif return_button_rect.collidepoint(event.pos):
character_select_window = False
def show_setting_window(self):
setting_window = True
return_button_x = (WIDTH - 50) // 2
return_button_y = HEIGHT - 100
return_button_rect = pygame.Rect(return_button_x, return_button_y, 50, 50)
lower_button_x = (HEIGHT - 200) // 2
lower_button_y = HEIGHT // 2 + 50
lower_button_rect = pygame.Rect(lower_button_x, lower_button_y, 50, 50)
louder_button_x = lower_button_x + 150
louder_button_y = HEIGHT // 2 + 50
louder_button_rect = pygame.Rect(louder_button_x, louder_button_y, 50, 50)
mute_button_x = lower_button_x + 75
mute_button_y = HEIGHT // 2 + 50
mute_button_rect = pygame.Rect(mute_button_x, mute_button_y, 50, 50)
while setting_window:
WIN.blit(background_image, (0, 0))
# Display setting window content
self.display_setting_window(WIN)
# Draw return button
WIN.blit(return_button_image, (return_button_x, return_button_y))
# Draw volume buttons
WIN.blit(louder_button_image, (louder_button_x, louder_button_y))
WIN.blit(lower_button_image, (lower_button_x, lower_button_y))
WIN.blit(mute_button_image, (mute_button_x, mute_button_y))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == pygame.MOUSEBUTTONDOWN:
# Check if return button is clicked
if return_button_rect.collidepoint(event.pos):
setting_window = False
elif mute_button_rect.collidepoint(event.pos):
pygame.mixer.music.set_volume(0)
elif lower_button_rect.collidepoint(event.pos):
if pygame.mixer.music.get_volume() > 0:
pygame.mixer.music.set_volume(pygame.mixer.music.get_volume() - 0.1)
elif louder_button_rect.collidepoint(event.pos):
if pygame.mixer.music.get_volume() < 1:
pygame.mixer.music.set_volume(pygame.mixer.music.get_volume() + 0.1)
def display_setting_window(self, window):
font = pygame.font.SysFont('comicsans', 24)
text = [
"Game Rules:",
"- Press SPACE to make the cube jump.",
"- Press P to pause the game.",
"- Avoid colliding with obstacles.",
"- Collect green obstacles to score 2 point.",
"- Collect red obstacles to score 6 points.",
"- Collect gold obstacles to score 10 points.",
"- Have fun!"
]
y_offset = 50
for line in text:
line_surface = font.render(line, True, BLACK) # Render text with black color
line_rect = line_surface.get_rect(center=(WIDTH // 2, y_offset))
# Create a surface with a white background
background_surface = pygame.Surface((line_rect.width + 20, line_rect.height + 20))
background_surface.fill(WHITE)
# Blit the text onto the background surface
background_surface.blit(line_surface, (10, 10))
# Blit the background surface onto the window
window.blit(background_surface, (line_rect.x - 10, line_rect.y - 10))
y_offset += 30 # Adjust vertical spacing
def switch_to_previous_character(self):
self.current_player_index -= 1
if self.current_player_index < 0:
self.current_player_index = len(self.players) - 1
return self.get_current_player()
def switch_to_next_character(self):
self.current_player_index += 1
if self.current_player_index >= len(self.players):
self.current_player_index = 0
return self.get_current_player()
def get_current_player(self):
player_class = self.players[self.current_player_index]
player_params = self.player_parameters[self.current_player_index]
return player_class(*player_params) # Instantiate player object with parameters
def update_current_player_image(self):
if self.current_player_index == 0:
self.current_player_image = Normal_Bird_image
elif self.current_player_index == 1:
self.current_player_image = Lazy_Bird_image
elif self.current_player_index == 2:
self.current_player_image = Small_Bird_image
self.current_player_image = pygame.transform.scale(self.current_player_image, (self.player.rect.width, self.player.rect.height))
self.current_player_image_rect = self.current_player_image.get_rect(center=(WIDTH // 2, HEIGHT // 2))
# Blit the updated image onto the window
WIN.blit(self.current_player_image, self.current_player_image_rect)
def get_current_player_description(self):
descriptions = ["Regular Bird: Jumps normally.",
"Heavy Bird: Jumps less higher.",
"Small Bird: Smaller size."]
return descriptions[self.current_player_index]
def run(self):
clock = pygame.time.Clock()
running = True
while running:
clock.tick(30)
running = self.handle_events()
if not running:
break
running = self.update()
if not running:
break
self.draw()
pygame.quit()
if __name__ == "__main__":
game = Game()
game.run()