import pygame from pygame.locals import * from pygame import mixer import pickle from os import path import datetime pygame.mixer.pre_init(44100, -16, 2, 512) mixer.init() pygame.init() # Set up the game clock to manage the game's frame rate clock = pygame.time.Clock() fps = 60 # Define the dimensions of the game window screen_width = 1000 screen_height = 1000 # Create the game window screen = pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption('Platformer') # define font font = pygame.font.SysFont('Bauhaus 93', 70) font_score = pygame.font.SysFont('Bauhaus 93', 30) # define game variables tile_size = 50 game_over = 0 main_menu = True level = 5 max_levels = 5 score = 0 lives = 3 # define colours white = (255, 255, 255) blue = (0, 0, 255) red = (255, 0, 0) # load images bg_img = pygame.image.load('img/background.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') # load sounds pygame.mixer.music.load('music/music.wav') pygame.mixer.music.play(-1, 0.0, 5000) coin_fx = pygame.mixer.Sound('music/coin.wav') coin_fx.set_volume(0.5) jump_fx = pygame.mixer.Sound('music/jump.wav') jump_fx.set_volume(0.5) game_over_fx = pygame.mixer.Sound('music/game_over.wav') game_over_fx.set_volume(0.5) # Function to draw text on the screen 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) #reset player postion #empty all groups: blob_group.empty() platform_group.empty() lava_group.empty() exit_group.empty() coin_group.empty() #add score coin to coin group to make it on every level: coin_group.add(score_coin) # 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) return world # Button class for creating interactive buttons class Button(): def __init__(self, x, y, image): self.image = image self.rect = self.image.get_rect() self.rect.x = x #set x postion of button self.rect.y = y #set y postion of button self.clicked = False # Flag to check if the button has been clicked 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 self.clicked == False: 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 class Player(): def __init__(self, x, y): self.reset(x, y) def update(self, game_over, lives): dx = 0 dy = 0 walk_cooldown = 5 idle_cooldown = 10 # Cooldown for idle animation fall_cooldown = 10 jump_cooldown = 10 landing_cooldown = 10 col_thresh = 20 attack_cooldown = 5 if game_over == 0: # get key presses key = pygame.key.get_pressed() mouse = pygame.mouse.get_pressed() if mouse[0] and not self.attacking and not self.in_air: self.attacking = True self.attack_counter = 0 # If the player is attacking, handle attack animation if self.attacking: self.counter += 1 # Increment the animation counter if self.counter >= attack_cooldown: self.counter = 0 self.attack_counter += 1 # Move to the next attack frame if self.attack_counter >= len(self.attack_frames): self.attacking = False # End the attack if all frames have been shown self.attack_counter = 0 # Reset the attack counter else: # Display the current attack frame self.image = pygame.transform.flip(self.attack_frames[self.attack_counter], self.direction, False) else: # Handle jumping if key[pygame.K_SPACE] and self.jumped == False and self.in_air == False: jump_fx.play() self.vel_y = -15 self.jumped = True if key[pygame.K_SPACE] == False: self.jumped = False # Reset jumped flag when space key is released # Handle left movement if key[pygame.K_LEFT]: dx -= 5 self.direction = True # Handle right movement if key[pygame.K_RIGHT]: dx += 5 self.direction = False self.counter += 1 # Handle in-air animations if self.in_air: if self.vel_y < 0: # Player is moving upwards if self.index >= len(self.jump_frames): self.index = len(self.jump_frames) - 1 # Hold the last jump frame self.image = pygame.transform.flip(self.jump_frames[self.index], self.direction, False) # Display jump frame if self.counter > jump_cooldown: if self.counter > jump_cooldown: self.counter = 0 #reset counter self.index += 1 #move to next jump frame else: if self.index >= len(self.falling_frames): self.index = len(self.falling_frames) - 1 # Hold the last falling frame self.image = pygame.transform.flip(self.falling_frames[self.index], self.direction, False) if self.counter > fall_cooldown: self.counter = 0 self.index += 1 # Handle landing animations else: if self.landing: if self.index >= len(self.landing_frames): self.index = len(self.landing_frames) - 1 # Hold the last landing frame self.image = pygame.transform.flip(self.landing_frames[self.index], self.direction, False) # Flip based on direction if self.counter > landing_cooldown: self.counter = 0 #reset counter self.index += 1 #move to next landing frame if self.index >= len(self.landing_frames): self.landing = False # End landing animation if all frames have been shown self.index = 0 #reset frame index # Handle idle animations else: if not key[pygame.K_LEFT] and not key[pygame.K_RIGHT]: if self.counter > idle_cooldown: self.counter = 0 #reset counter self.index += 1 #move to next idle frame if self.index >= len(self.idle_right): # Both idle_right and idle_left should have the same length self.index = 0 # Reset idle frame index if self.direction == False: self.image = self.idle_right[self.index] # Display idle frame facing right if self.direction == True: self.image = self.idle_left[self.index] # Display idle frame facing left # Handle walking animations else: if self.counter > walk_cooldown: self.counter = 0 #reset counter self.index += 1 #move to next walking frame if self.index >= len(self.images_right): # Both images_right and images_left should have the same length self.index = 0 if self.direction == False: self.image = self.images_right[self.index] # Display walk frame facing right if self.direction == True: self.image = self.images_left[self.index] # Display walk frame facing left # add gravity self.vel_y += 1 # Increase vertical velocity to simulate gravity if self.vel_y > 10: self.vel_y = 10 # Cap the vertical velocity to prevent falling too fast dy += self.vel_y # Apply vertical velocity to the change in y position (dy) # check player collision old_air = self.in_air self.in_air = True # Assume the player is in the air # Check collision with tiles for tile in world.tile_list: # Check for collision in the x direction if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height): dx = 0 # Stop horizontal movement on collision # Check for collision in the y direction if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height): if self.vel_y < 0: # Collision while moving upwards dy = tile[1].bottom - self.rect.top # Adjust dy to stop at the top of the tile self.vel_y = 0 # Reset vertical velocity # Collision while moving downwards: elif self.vel_y >= 0: dy = tile[1].top - self.rect.bottom # Adjust dy to stop at the bottom of the tile self.vel_y = 0 # Reset vertical velocity self.in_air = False # Player is no longer in the air # check for collision with enemies if pygame.sprite.spritecollide(self, blob_group, False): #if player collides with blob: lives -= 1 for blob in pygame.sprite.spritecollide(self, blob_group, False): if self.direction and self.rect.x > blob.rect.x: # if you are facing a blob on the right side and attacking, remove enemy and add 1 score while giving your life back if self.attacking: blob_group.remove(blob) lives += 1 score +1 if (not self.direction) and self.rect.x < blob.rect.x: # if you are left the blob for thr right side and attacking, remove enemy and add 1 score while giving your life back if self.attacking: blob_group.remove(blob) lives += 1 score +1 #when hit by blob get knocked back else: if self.rect.x < blob.rect.x: dx = -25 # Push player left else: dx = 25 # Push player right if self.rect.y < blob.rect.y: dy = -10 # Push player up slightly else: dy = 10 # Push player down slightly if lives == 0: # Check if lives are depleted #calculate time sinse timer started and formatt to mm:ss minutes, seconds = divmod((datetime.datetime.now() - timer).seconds, 60) self.finshed_time = '{:02}:{:02}'.format(int(minutes), int(seconds)) game_over = -1 game_over_fx.play() # check for collision with lava if pygame.sprite.spritecollide(self, lava_group, False): #if player collide with lava game_over = -1 lives = 0 #calculate time sinse timer started and formatt to mm:ss minutes, seconds = divmod((datetime.datetime.now() - timer).seconds, 60) self.finshed_time = '{:02}:{:02}'.format(int(minutes), int(seconds)) print(game_over) game_over_fx.play() # check for collision with exit if pygame.sprite.spritecollide(self, exit_group, False): game_over = 1 print(game_over) # check for collision with platforms for platform in platform_group: # collision in the x direction if platform.rect.colliderect(self.rect.x + dx, self.rect.y, self.width, self.height): dx = 0 # Stop horizontal movement on collision # check collision in the y direction if platform.rect.colliderect(self.rect.x, self.rect.y + dy, self.width, self.height): # check if below platform if abs((self.rect.top + dy) - platform.rect.bottom) < col_thresh: self.vel_y = 0 # Reset vertical velocity dy = platform.rect.bottom - self.rect.top # Adjust dy to stop at the bottom of the platform # check if above platform elif abs((self.rect.bottom + dy) - platform.rect.top) < col_thresh: self.rect.bottom = platform.rect.top - 1 # Adjust position to stand on top of the platform self.in_air = False # Player is no longer in the air dy = 0 # move sideways with the platform if platform.move_x != 0: self.rect.x += platform.move_direction #player x is same as platform x if old_air and not self.in_air: self.landing = True # Trigger landing animation self.index = 0 self.counter = 0 #update player coordinates self.rect.x += dx self.rect.y += dy elif game_over == -1: self.image = self.dead_image pygame.draw.rect(screen, (255,255,255),pygame.Rect((screen_width // 2) - 210, (screen_height // 2) -50, 400, 200) ) draw_text('GAME OVER!', font, red, (screen_width // 2) - 200, screen_height // 2 - 50) draw_text('final time: ' + self.finshed_time, font_score, red, (screen_width // 2) - 200, screen_height // 2 +10) draw_text('Your Coins: ' + str(score), font_score, red, (screen_width // 2) - 200, screen_height // 2 + 40) if self.rect.y > 200: self.rect.y -= 5 # Move player up after game over #draw player onto screen screen.blit(self.image, self.rect) return game_over, lives # Return game over state and lives def reset(self, x, y): self.images_right = [] #right movement frames self.images_left = [] #left movement frames self.idle_right = [] # Right idle animation frames self.idle_left = [] # Left idle animation frames self.falling_frames = [] # Falling animation frames self.jump_frames = [] # Jumping animation frames self.landing_frames = [] # Landing animation frames self.attack_frames = [] # attacking frames self.index = 0 # Animation frame index self.counter = 0 # Animation counter # Load run images for num in range(1, 9): img_right = pygame.image.load(f'img/run{num}.png') # Load right movement image img_right = pygame.transform.scale(img_right, (45, 70)) img_left = pygame.transform.flip(img_right, True, False) # Flip image for left movement self.images_right.append(img_right) self.images_left.append(img_left) # Load falling images for num in range(1, 7): # Assuming there are 6 falling frames img_falling_right = pygame.image.load(f'img/fall ({num}).png') # Load falling image img_falling_right = pygame.transform.scale(img_falling_right, (45, 70)) self.falling_frames.append(img_falling_right) # Load jumping images for num in range(1, 9): # Assuming there are 8 jump frames img_jump_right = pygame.image.load(f'img/jump{num}.png') # Load jump image img_jump_right = pygame.transform.scale(img_jump_right, (45, 70)) self.jump_frames.append(img_jump_right) # Load landing images for num in range(7, 9): # Assuming you have 2 landing frames img_landing_right = pygame.image.load(f'img/fall ({num}).png') # Load landing image img_landing_right = pygame.transform.scale(img_landing_right, (45, 70)) self.landing_frames.append(img_landing_right) # Load idle images for num in range(1, 7): # Assuming there are 6 idle frames img_idle_right = pygame.image.load(f'img/idle{num}.png') # Load idle image img_idle_right = pygame.transform.scale(img_idle_right, (45, 70)) img_idle_left = pygame.transform.flip(img_idle_right, True, False) # Flip image for left idle self.idle_right.append(img_idle_right) self.idle_left.append(img_idle_left) #load attack frames for num in range(1, 7): # Assuming there are 6 idle frames img_attack_right = pygame.image.load(f'img/attack{num}.png') # Load attack image img_attack_right = pygame.transform.scale(img_attack_right, (45, 70)) self.attack_frames.append(img_attack_right) self.dead_image = pygame.image.load('img/ghost.png') self.image = self.idle_right[self.index] # Set initial image to the first idle right frame 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 = False #false = right, true = left self.in_air = True self.landing = False self.attacking = False self.attack_counter = 0 class World(): def __init__(self, data): self.tile_list = [] # Load images for different types of tiles dirt_img = pygame.image.load('img/tile6.png') grass_img = pygame.image.load('img/tile5.png') left_wall_img = pygame.image.load('img/tile10.png') right_wall_img = pygame.image.load('img/tile11.png') full_plat_img = pygame.image.load('img/tile1.png') left_top_img = pygame.image.load('img/tile16.png') right_top_img = pygame.image.load('img/tile17.png') top_3_img = pygame.image.load('img/tile2.png') left_3_img = pygame.image.load('img/tile3.png') right_3_img = pygame.image.load('img/tile4.png') left_corner_img = pygame.image.load('img/tile12.png') right_corner_img = pygame.image.load('img/tile13.png') double_ho_img = pygame.image.load('img/tile7.png') roof_silver_img = pygame.image.load('img/tile9.png') dirt_2_img = pygame.image.load('img/tile14.png') # Process each tile in the provided data grid row_count = 0 for row in data: col_count = 0 for tile in row: if tile == 1: # Dirt tile 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: # Grass tile 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: # Enemy blob blob = Enemy(col_count * tile_size, row_count * tile_size + 15) blob_group.add(blob) if tile == 4: #creating new platform 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 = Lava(col_count * tile_size, row_count * tile_size +(tile_size // 2) ) lava_group.add(lava) if tile == 7: # Coin 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 = Exit(col_count * tile_size, row_count * tile_size - (tile_size // 2)) exit_group.add(exit) if tile == 9: # Left wall tile img = pygame.transform.scale(left_wall_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: # Right wall tile img = pygame.transform.scale(right_wall_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: # Full platform tile img = pygame.transform.scale(full_plat_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: # Left top corner tile img = pygame.transform.scale(left_top_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 == 13: # Right top corner tile img = pygame.transform.scale(right_top_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 == 14: # Top 3-tile block img = pygame.transform.scale(top_3_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 == 15: # Left 3-tile block img = pygame.transform.scale(left_3_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 == 16: # Right 3-tile block img = pygame.transform.scale(right_3_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 == 17: # Left corner tile img = pygame.transform.scale(left_corner_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 == 18: # Right corner tile img = pygame.transform.scale(right_corner_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 == 19: # Double horizontal tile img = pygame.transform.scale(double_ho_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 == 20: # Roof silver tile img = pygame.transform.scale(roof_silver_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 == 21: # Alternate dirt tile img = pygame.transform.scale(dirt_2_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) col_count += 1 row_count += 1 def draw(self): # Draw all tiles in the tile list onto the screen for tile in self.tile_list: screen.blit(tile[0], tile[1]) class Enemy(pygame.sprite.Sprite): def __init__(self, x, y): self.index = 0 self.move_direction = 1 # Initial movement direction self.direction = False # Initialize direction for right movement (False for right, True for left) self.move_counter = 0 self.counter = 0 self.images_right = [] # List to store right blob animation frames self.images_left = [] # List to store left blob animation frames pygame.sprite.Sprite.__init__(self) # Load multiple images for enemy animation for num in range(1, 9): # Assuming you have 8 blob frames img = pygame.image.load(f'img/blob{num}.png') self.image = pygame.transform.scale(img, (46, 35)) img_left = pygame.transform.flip(self.image, True, False) # Flip image for left movement self.images_right.append(self.image) self.images_left.append(img_left) self.image = self.images_right[0] # Initialize with the first frame of the right images self.rect = self.image.get_rect() self.rect.topleft = (x, y) # Place the top-left corner of the image at the specified coordinates try: #if we aren't the first Enemy #set our direction to be the opposite of the last Enemy self.move_direction = Enemy.direction_g * -1 #flip it for the next Enemy Enemy.direction_g = Enemy.direction_g * -1 except: #if we are the first Enemy #set class direction_g and set our direction to be the same Enemy.direction_g = 1 self.move_direction = Enemy.direction_g def update(self): # Move enemy horizontally self.move_counter += 1 move_cooldown = 5 if (self.move_counter % 2) == 0 or (self.move_counter % 3) == 0: self.rect.x += self.move_direction # Reverse direction after certain distance if abs(self.move_counter) > 75: self.move_direction *= -1 self.move_counter *= -1 if self.counter > move_cooldown: self.counter = 0 #reset counter self.index += 1 #move to next moving frame if self.index >= len(self.images_right): # Both images_right and images_left should have the same length self.index = 0 # Set the correct image based on the direction if self.move_direction > 0: self.image = self.images_right[self.index] # Display walk frame facing right else: self.image = self.images_left[self.index] # Display walk frame facing left self.counter += 1 # Increment counter for animation timing class Platform(pygame.sprite.Sprite): def __init__(self, x, y, move_x, move_y): pygame.sprite.Sprite.__init__(self) img = pygame.image.load('img/platform2.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_x = move_x self.move_y = move_y try: #if we aren't the first platform #set our direction to be the opposite of the last platforms self.move_direction = Platform.direction_g * -1 #flip it for the next platform Platform.direction_g = Platform.direction_g * -1 except: #if we are the first platform #set class direction_g and set our direction to be the same Platform.direction_g = 1 self.move_direction = Platform.direction_g def update(self): # Move platform horizontally or vertically self.rect.x += self.move_direction * self.move_x self.rect.y += self.move_direction * self.move_y self.move_counter += 1 # Reverse direction after certain distance if abs(self.move_counter) > 50: self.move_direction *= -1 self.move_counter *= -1 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 class Coin(pygame.sprite.Sprite): def __init__(self, x, y): self.index = 0 self.images = [] # List to store coin animation frames self.counter = 0 pygame.sprite.Sprite.__init__(self) # Load multiple images for coin animation for num in range(1, 10): # Assuming you have 9 coin frames img = pygame.image.load(f'img/Coin ({num}).png') self.image = pygame.transform.scale(img, (tile_size // 2, tile_size // 2)) self.images.append(self.image) self.rect = self.image.get_rect() self.rect.center = (x, y) def update(self): # Animate the coin by cycling through images self.counter += 1 if self.counter == 6: self.index += 1 if self.index == len(self.images): self.index = 0 self.image = self.images[self.index] self.counter = 0 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 # Initialize the player at a specific position player = Player(100, screen_height - 130) # Create groups for different types of sprites 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() #create dummy coin for showing score score_coin = Coin(tile_size // 2, tile_size // 2) coin_group.add(score_coin) #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 buttons for restarting, starting, and exiting the game restart_button = Button(screen_width // 2 - 50, screen_height //2 + 100, restart_img) start_button = Button(screen_width // 2 - 350, screen_height // 2, start_img) exit_button = Button(screen_width // 2 + 150, screen_height // 2, exit_img) # Timer variable to track the game duration timer = datetime.datetime.now() finshed_time = False run = True #game loop while run: # Control the game frame rate clock.tick(fps) # Draw the background image screen.blit(bg_img, (0, 0)) if main_menu == True: # If in the main menu, draw buttons and check for button clicks if exit_button.draw(): run = False if start_button.draw(): main_menu = False timer = datetime.datetime.now() else: # Draw the game world world.draw() if game_over == 0: # Update groups and check for collisions blob_group.update() platform_group.update() coin_group.update() #update score #check if coin has been collected and update score if pygame.sprite.spritecollide(player, coin_group, True): score += 1 coin_fx.play() # Draw the score, lives, and timer on the screen draw_text('X ' + str(score), font_score, white, tile_size - 10, 10) draw_text('Lives: ' + str(lives), font_score, white, tile_size +100, 10) current_timer = datetime.datetime.now() - timer minutes, seconds = divmod(current_timer.seconds, 60) draw_text('timer: ' + '{:02}:{:02}'.format(int(minutes), int(seconds)), font_score, white, tile_size +250, 10) # Draw groups on the screen blob_group.draw(screen) platform_group.draw(screen) lava_group.draw(screen) coin_group.draw(screen) exit_group.draw(screen) # Update the player's status and check for game over game_over, lives = player.update(game_over, lives) #if player has died if game_over == -1: #if player died show reset button if restart_button.draw(): # Reset game state level = 1 world_data = [] world = reset_level(level) game_over = 0 score = 0 lives = 3 timer = datetime.datetime.now() coin_group.add(score_coin) #if player has completed level if game_over == 1: #reset game and go to next level level += 1 if level <= max_levels: #if level is smaller than max level, move net level #reset level world_data = [] world = reset_level(level) game_over = 0 lives = lives else: # if final level is complete # Display the win screen with final stats if not finshed_time: minutes, seconds = divmod((datetime.datetime.now() - timer).seconds, 60) finshed_time = '{:02}:{:02}'.format(int(minutes), int(seconds)) #draw game complete text and rectangle pygame.draw.rect(screen, (255,255,255),pygame.Rect((screen_width // 2) -190 , (screen_height // 2) -50, 400, 200) ) draw_text('YOU WIN!', font, blue, (screen_width // 2) - 140, screen_height // 2 - 50) draw_text('final time: ' + finshed_time, font_score, red, (screen_width // 2) - 140, screen_height // 2 +10) draw_text('Your Coins: ' + str(score), font_score, red, (screen_width // 2) - 140, screen_height // 2 + 40) draw_text('Lives remaining: ' + str(lives), font_score, red, (screen_width // 2) - 140, screen_height // 2 + 60) #restart game from win screen if restart_button.draw(): level = 1 #reset level world_data = [] world = reset_level(level) game_over = 0 score = 0 lives = 3 # Handle events such as quitting the game for event in pygame.event.get(): if event.type == pygame.QUIT: run = False pygame.display.update() pygame.quit()