#this imports all the assets needed for the game import pygame from pygame.locals import * from pygame import mixer import pickle from os import path import time from pgu import gui pygame.mixer.pre_init(44100, -16, 2, 512) mixer.init() pygame.init() #sets FPS and the game timer clock = pygame.time.Clock() fps = 60 #sets the window size screen_width = 1000 screen_height = 1000 screen = pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption('Mushroom Mania') #defines font font = pygame.font.SysFont('Bauhaus 93', 70) font_score = pygame.font.SysFont('Bauhaus 93', 30) font_stopwatch = pygame.font.SysFont('Bauhaus 93', 30) #defines game variables tile_size = 50 game_over = 0 main_menu = True level = 3 max_levels = 7 score = 0 # Stopwatch variables start_time = 0 stopwatch_active = False #defines colours white = (255, 255, 255) blue = (0, 0, 255) red = (136, 8, 8) # loads the images bg_img = pygame.image.load('img/sky.png') restart_img = pygame.image.load('img/restart_btn.png') start_img = pygame.image.load('img/start_btn.png') exit_img = pygame.image.load('img/exit_btn.png') instructions_img = pygame.image.load('img/instructions_btn.png') #loads the sounds pygame.mixer.music.load('img/music.wav') pygame.mixer.music.play(-1, 0.0, 5000) coin_fx = pygame.mixer.Sound('img/coin.wav') coin_fx.set_volume(0.5) jump_fx = pygame.mixer.Sound('img/jump.wav') jump_fx.set_volume(0.5) game_over_fx = pygame.mixer.Sound('img/game_over.wav') game_over_fx.set_volume(0.5) #adds text def draw_text(text, font, text_col, x, y): img = font.render(text, True, text_col) screen.blit(img, (x, y)) # function to reset level def reset_level(level): player.reset(100, screen_height - 130) blob_group.empty() platform_group.empty() coin_group.empty() lava_group.empty() exit_group.empty() # load in level data and create world if path.exists(f'level{level}_data'): pickle_in = open(f'level{level}_data', 'rb') world_data = pickle.load(pickle_in) world = World(world_data) # create dummy coin for showing the score score_coin = Coin(tile_size // 2, tile_size // 2) coin_group.add(score_coin) return world #adds the buttons class Button(): def __init__(self, x, y, image): self.image = image self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y self.clicked = False def draw(self): action = False # get mouse position pos = pygame.mouse.get_pos() # check mouseover and clicked conditions if self.rect.collidepoint(pos): if pygame.mouse.get_pressed()[0] == 1 and not self.clicked: action = True self.clicked = True if pygame.mouse.get_pressed()[0] == 0: self.clicked = False # draw button screen.blit(self.image, self.rect) return action #this is for player related things class Player(): def __init__(self, x, y): self.reset(x, y) def update(self, game_over): global stopwatch_active dx = 0 dy = 0 walk_cooldown = 5 col_thresh = 20 if game_over == 0: # get keypresses key = pygame.key.get_pressed() if key[pygame.K_SPACE] and not self.jumped and not self.in_air: jump_fx.play() self.vel_y = -15 self.jumped = True if not stopwatch_active: start_time = time.time() stopwatch_active = True if not key[pygame.K_SPACE]: self.jumped = False if key[pygame.K_LEFT]: dx -= 5 self.counter += 1 self.direction = -1 if key[pygame.K_RIGHT]: dx += 5 self.counter += 1 self.direction = 1 if not key[pygame.K_LEFT] and not key[pygame.K_RIGHT]: self.counter = 0 self.index = 0 if self.direction == 1: self.image = self.images_right[self.index] if self.direction == -1: self.image = self.images_left[self.index] #this handles animation if self.counter > walk_cooldown: self.counter = 0 self.index += 1 if self.index >= len(self.images_right): self.index = 0 if self.direction == 1: self.image = self.images_right[self.index] if self.direction == -1: self.image = self.images_left[self.index] #Thiss adds gravity self.vel_y += 1 if self.vel_y > 10: self.vel_y = 10 dy += self.vel_y #This checks for collision self.in_air = True for tile in world.tile_list: #This checks for collision in x direction if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height): dx = 0 #This checks for collision in y direction if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height): if self.vel_y < 0: dy = tile[1].bottom - self.rect.top self.vel_y = 0 elif self.vel_y >= 0: dy = tile[1].top - self.rect.bottom self.vel_y = 0 self.in_air = False #This checks for collision with enemies if pygame.sprite.spritecollide(self, blob_group, False): game_over = -1 game_over_fx.play() #This checks for collision with lava if pygame.sprite.spritecollide(self, lava_group, False): game_over = -1 game_over_fx.play() #This checks for collision with exit if pygame.sprite.spritecollide(self, exit_group, False): game_over = 1 #This checks for collision with platforms for platform in platform_group: if platform.rect.colliderect(self.rect.x + dx, self.rect.y, self.width, self.height): dx = 0 if platform.rect.colliderect(self.rect.x, self.rect.y + dy, self.width, self.height): if abs((self.rect.top + dy) - platform.rect.bottom) < col_thresh: self.vel_y = 0 dy = platform.rect.bottom - self.rect.top elif abs((self.rect.bottom + dy) - platform.rect.top) < col_thresh: self.rect.bottom = platform.rect.top - 1 self.in_air = False dy = 0 if platform.move_x != 0: self.rect.x += platform.move_direction self.rect.x += dx self.rect.y += dy #game over elif game_over == -1: self.image = pygame.transform.scale(self.dead_image, (tile_size + 10, tile_size + 10)) draw_text(' YOU DIED', font, red, (screen_width // 2) - 200, screen_height // 2) self.rect.y -= 1 screen.blit(self.image, self.rect) return game_over #for when a character resets def reset(self, x, y): self.images_right = [] self.images_left = [] self.index = 0 self.counter = 0 for num in range(1, 5): img_right = pygame.image.load(f'img/guy{num}.png') img_right = pygame.transform.scale(img_right, (48, 64)) img_left = pygame.transform.flip(img_right, True, False) self.images_right.append(img_right) self.images_left.append(img_left) self.dead_image = pygame.image.load('img/guy1.png') self.image = self.images_right[self.index] self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y self.width = self.image.get_width() self.height = self.image.get_height() self.vel_y = 0 self.jumped = False self.direction = 0 self.in_air = True #everything to do with loading the game class World(): def __init__(self, data): self.tile_list = [] #This loads images dirt_img = pygame.image.load('img/dirt.png') grass_img = pygame.image.load('img/grass.png') grass_right_img = pygame.image.load('img/grass_left.png') grass_left_img = pygame.image.load('img/grass_right.png') grass_down_img = pygame.image.load('img/grass_down.png') grass_full = pygame.image.load('img/grass_full.png') grass_full_right = pygame.image.load('img/grass_full_right.png') row_count = 0 for row in data: col_count = 0 for tile in row: if tile == 1: img = pygame.transform.scale(dirt_img, (tile_size, tile_size)) img_rect = img.get_rect() img_rect.x = col_count * tile_size img_rect.y = row_count * tile_size tile = (img, img_rect) self.tile_list.append(tile) if tile == 2: img = pygame.transform.scale(grass_img, (tile_size, tile_size)) img_rect = img.get_rect() img_rect.x = col_count * tile_size img_rect.y = row_count * tile_size tile = (img, img_rect) self.tile_list.append(tile) if tile == 3: blob = Enemy(col_count * tile_size, row_count * tile_size) blob_group.add(blob) if tile == 4: platform = Platform(col_count * tile_size, row_count * tile_size, 1, 0) platform_group.add(platform) if tile == 5: platform = Platform(col_count * tile_size, row_count * tile_size, 0, 1) platform_group.add(platform) if tile == 6: lava = Lava(col_count * tile_size, row_count * tile_size + (tile_size // 2)) lava_group.add(lava) if tile == 7: coin = Coin(col_count * tile_size + (tile_size // 2), row_count * tile_size + (tile_size // 2)) coin_group.add(coin) if tile == 8: exit = Exit(col_count * tile_size, row_count * tile_size - (tile_size // 2)) exit_group.add(exit) if tile == 9: img = pygame.transform.scale(grass_right_img, (tile_size, tile_size)) img_rect = img.get_rect() img_rect.x = col_count * tile_size img_rect.y = row_count * tile_size tile = (img, img_rect) self.tile_list.append(tile) if tile == 10: img = pygame.transform.scale(grass_left_img, (tile_size, tile_size)) img_rect = img.get_rect() img_rect.x = col_count * tile_size img_rect.y = row_count * tile_size tile = (img, img_rect) self.tile_list.append(tile) if tile == 11: img = pygame.transform.scale(grass_down_img, (tile_size, tile_size)) img_rect = img.get_rect() img_rect.x = col_count * tile_size img_rect.y = row_count * tile_size tile = (img, img_rect) self.tile_list.append(tile) if tile == 12: img = pygame.transform.scale(grass_full, (tile_size, tile_size)) img_rect = img.get_rect() img_rect.x = col_count * tile_size img_rect.y = row_count * tile_size tile = (img, img_rect) self.tile_list.append(tile) if tile == 13: img = pygame.transform.scale(grass_full_right, (tile_size, tile_size)) img_rect = img.get_rect() img_rect.x = col_count * tile_size img_rect.y = row_count * tile_size tile = (img, img_rect) self.tile_list.append(tile) col_count += 1 row_count += 1 def draw(self): for tile in self.tile_list: screen.blit(tile[0], tile[1]) #Code for enemy class Enemy(pygame.sprite.Sprite): def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load('img/blob.png').convert_alpha() self.image = pygame.transform.scale(self.image, (tile_size, tile_size)) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y self.move_direction = 1 self.move_counter = 0 def update(self): self.rect.x += self.move_direction self.move_counter += 1 if abs(self.move_counter) > 50: self.move_direction *= -1 self.move_counter *= -1 #code for the platforms class Platform(pygame.sprite.Sprite): def __init__(self, x, y, move_x, move_y): pygame.sprite.Sprite.__init__(self) img = pygame.image.load('img/platform.png') self.image = pygame.transform.scale(img, (tile_size, tile_size // 2)) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y self.move_counter = 0 self.move_direction = 1 self.move_x = move_x self.move_y = move_y def update(self): self.rect.x += self.move_direction * self.move_x self.rect.y += self.move_direction * self.move_y self.move_counter += 1 if abs(self.move_counter) > 50: self.move_direction *= -1 self.move_counter *= -1 #code for the lava class Lava(pygame.sprite.Sprite): def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) img = pygame.image.load('img/lava.png') self.image = pygame.transform.scale(img, (tile_size, tile_size // 2)) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y #code for the coins class Coin(pygame.sprite.Sprite): def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) img = pygame.image.load('img/coin.png') self.image = pygame.transform.scale(img, (tile_size // 2, tile_size // 2)) self.rect = self.image.get_rect() self.rect.center = (x, y) #code to exit the game class Exit(pygame.sprite.Sprite): def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) img = pygame.image.load('img/exit.png') self.image = pygame.transform.scale(img, (tile_size, int(tile_size * 1.5))) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y #defines certain assets player = Player(100, screen_height - 130) blob_group = pygame.sprite.Group() platform_group = pygame.sprite.Group() lava_group = pygame.sprite.Group() coin_group = pygame.sprite.Group() exit_group = pygame.sprite.Group() #This creates dummy coin for showing the score score_coin = Coin(tile_size // 2, tile_size // 2) coin_group.add(score_coin) #This loads in level data and create world if path.exists(f'level{level}_data'): pickle_in = open(f'level{level}_data', 'rb') world_data = pickle.load(pickle_in) world = World(world_data) # Function to draw the title def draw_title(text, font, text_col, x, y): img = font.render(text, True, text_col) screen.blit(img, (x, y)) # Define the title font title_font = pygame.font.SysFont('Bauhaus 93', 100) # Adjust size as needed #This creates and alligns buttons center_x = screen_width // 2 center_y = screen_height // 2 start_button = Button(center_x - 140, center_y - 190, start_img) instructions_button = Button(center_x - 140, center_y - 30, instructions_img) exit_button = Button(center_x - 125, center_y + 130, exit_img) restart_button = Button(center_x - 65, center_y + 110, restart_img) #this is the instructional pop up code instructions_visible = False def draw_instructions_popup(): popup_width = 300 popup_height = 210 popup_x = (screen_width - popup_width) // 2 popup_y = (screen_height - popup_height) // 2 - 150 # Draw popup background pygame.draw.rect(screen, (47,54,153,255), (popup_x, popup_y, popup_width, popup_height)) # Black background pygame.draw.rect(screen, (84,109,142,255), (popup_x, popup_y, popup_width, popup_height), 2) # White border # Draw text instructions = [ "Instructions:", "1. Use left-right arrow keys to move.", "2. Spacebar to jump.", "3. Collect coins to score.", "4. Avoid enemies and lava.", "5. Reach the exit to progress.", "6. Beat all the levels to win.", "Press HELP again to close" ] font = pygame.font.SysFont(None, 24) for i, line in enumerate(instructions): text_surface = font.render(line, True, (199,207,204,255)) # White text screen.blit(text_surface, (popup_x + 10, popup_y + 10 + i * 25)) #this code innitiates all the other code run = True while run: clock.tick(fps) screen.blit(bg_img, (0, 0)) if main_menu: # Draw the title draw_title('Mushroom Mania ', title_font, (47,54,153,255), (screen_width // 2) - 370, center_y - 350) if exit_button.draw(): run = False if start_button.draw(): main_menu = False start_time = time.time() stopwatch_active = True if instructions_button.draw(): instructions_visible = not instructions_visible if instructions_visible: draw_instructions_popup() else: world.draw() if game_over == 0: blob_group.update() platform_group.update() # update score if pygame.sprite.spritecollide(player, coin_group, True): score += 1 coin_fx.play() draw_text('X ' + str(score), font_score, white, tile_size - 10, 10) # update stopwatch if stopwatch_active: current_time = int(time.time() - start_time) draw_text('Time: ' + str(current_time), font_stopwatch, white, screen_width - 200, 10) blob_group.draw(screen) platform_group.draw(screen) lava_group.draw(screen) coin_group.draw(screen) exit_group.draw(screen) game_over = player.update(game_over) if game_over == -1: if restart_button.draw(): world_data = [] world = reset_level(level) game_over = 0 score = 0 stopwatch_active = False #code for if the player wins if game_over == 1: level += 1 if level <= max_levels: world_data = [] world = reset_level(level) game_over = 0 else: draw_text('YOU WIN!', font, blue, (screen_width // 2) - 140, screen_height // 2) if restart_button.draw(): level = 1 world_data = [] world = reset_level(level) game_over = 0 score = 0 stopwatch_active = False for event in pygame.event.get(): if event.type == pygame.QUIT: run = False pygame.display.update() pygame.quit()