import pygame from pygame.locals import * import pickle from os import path # Initialize Pygame pygame.init() pygame.mixer.init() clock = pygame.time.Clock() fps = 60 start_ticks = pygame.time.get_ticks() # Set up display screen_width = 1000 screen_height = 1000 screen = pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption('Platformer') # Music pygame.mixer.init() #--Background Music pygame.mixer.music.load('Audio/boom.mp3') pygame.mixer.music.set_volume(0.5) # Volume 0.0 to 1.0 pygame.mixer.music.play(-1) # Loop forever # Game variables tile_size = 50 game_over = 0 main_menu = True level = 0 max_levels = 7 score = 0 font = pygame.font.SysFont(None, 36) # Button size button_width, button_height = 150, 70 # Load and scale images bg_img = pygame.image.load('img/actualbackground.png') restart_img = pygame.image.load('img/restart_btn.png') restart_img = pygame.transform.scale(restart_img, (150, 60)) start_img = pygame.image.load('img/start_btn.png') start_img = pygame.transform.scale(start_img, (150, 60)) exit_img = pygame.image.load('img/exit_btn.png') exit_img = pygame.transform.scale(exit_img, (150, 60)) # Sprite groups blob_group = pygame.sprite.Group() lava_group = pygame.sprite.Group() exit_group = pygame.sprite.Group() coin_group = pygame.sprite.Group() platform_group = pygame.sprite.Group() # Reset level function def reset_level(level): player.reset(100, screen_height - 130) blob_group.empty() lava_group.empty() exit_group.empty() coin_group.empty() platform_group.empty() if path.exists(f'level{level}_data'): pickle_in = open(f'level{level}_data', 'rb') world_data = pickle.load(pickle_in) return World(world_data) else: return None # Button class for start/restart/exit 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 pos = pygame.mouse.get_pos() 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 screen.blit(self.image, self.rect) return action # Player class class Player: def __init__(self, x, y): self.reset(x, y) def update(self, game_over): global score dx = 0 dy = 0 walk_cooldown = 5 col_thresh = 20 # Detect collision between player and coins coins_collected = pygame.sprite.spritecollide(player, coin_group, True) # True removes the coins on collision if coins_collected: score += len(coins_collected) # Add one point per coin collected if game_over == 0 : # Key Presses key = pygame.key.get_pressed() if key[pygame.K_SPACE] and self.jumped == False and self.in_air == False : self.vel_y = -15 self.jumped = True if key[pygame.K_SPACE] == False : 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 key[pygame.K_LEFT] == False and key[pygame.K_RIGHT] == False : 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] # Handle Animations 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] # Adding Gravity self.vel_y += 1 if self.vel_y > 10 : self.vel_y = 10 dy += self.vel_y # Shrink collision rect for more accurate collision, less on the left side player_rect = pygame.Rect(self.rect.x + 6, self.rect.y, self.width - 20, self.height) # Check For Collision self.in_air = True for tile in world.tile_list : if tile[1].colliderect(player_rect.x + dx, player_rect.y, player_rect.width, player_rect.height): dx = 0 if tile[1].colliderect(player_rect.x, player_rect.y + dy, player_rect.width, player_rect.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 # Check For Collision With Enemies if pygame.sprite.spritecollide(self, blob_group, False) : game_over = -1 # Check For Collision With Lava if pygame.sprite.spritecollide(self, lava_group, False) : game_over = -1 # Check For Collision With Exit if pygame.sprite.spritecollide(self, exit_group, False) : game_over = +1 # Check For Collision With Platforms for platform in platform_group : if platform.rect.colliderect(player_rect.x + dx, player_rect.y, player_rect.width, player_rect.height): dx = 0 if platform.rect.colliderect(player_rect.x, player_rect.y + dy, player_rect.width, player_rect.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) - 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_x # Update Player Coordinates self.rect.x += dx self.rect.y += dy elif game_over == -1 : self.image = self.dead_image if self.rect.y > 200 : self.rect.y -= 5 screen.blit(self.image, self.rect) return game_over 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/platformer2d/Sprites/Characters/Default/green{num}.png') img_right = pygame.transform.scale(img_right, (65, 80)) img_left = pygame.transform.flip(img_right, True, False) self.images_right.append(img_right) self.images_left.append(img_left) # Load and scale dead image to match player size dead_img = pygame.image.load('img/platformer2d/Sprites/Characters/Default/character_green_hit.png') self.dead_image = pygame.transform.scale(dead_img, (65, 80)) self.image = self.images_right[self.index] self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y self.rect.inflate_ip(-20, 0) 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 # World class to manage tiles and level layout class World(): def __init__(self, data): self.tile_list = [] dirt_img = pygame.image.load('img/dirt1.png') grass_img = pygame.image.load('img/grass1.png') coin_img = pygame.image.load('img/coin.png') platform_img = pygame.image.load('img/platform1.png') row_count = 0 for row in data: col_count = 0 for tile in row: # Create tiles and entities based on map data 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 - 5 img_rect.y = row_count * tile_size -10 img_rect.inflate_ip(-10, -10) # Shrink width and height by 10 pixels total 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 - 5 img_rect.y = row_count * tile_size - 10 img_rect.inflate_ip(-10, -10) # Shrink width and height by 10 pixels total tile = (img, img_rect) self.tile_list.append(tile) if tile == 3: blob = Enemy(col_count * tile_size, row_count * tile_size + 15) blob_group.add(blob) if tile == 7: coin = Coin(col_count * tile_size, row_count * tile_size) coin_group.add(coin) 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 == 8: exit = Exit(col_count * tile_size, row_count * tile_size - (tile_size // 2)) exit_group.add(exit) col_count += 1 row_count += 1 def draw(self): for tile in self.tile_list: screen.blit(tile[0], tile[1]) # Coin class with animation class Coin(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() self.images = [] for i in range(6): img = pygame.image.load(f'img/coins/coin_{i}.png').convert_alpha() img = pygame.transform.scale(img, (tile_size // 2, tile_size // 2)) self.images.append(img) self.index = 0 self.image = self.images[self.index] self.rect = self.image.get_rect() self.rect.center = (x + tile_size // 2, y + tile_size // 2) self.counter = 0 def update(self): animation_cooldown = 10 self.counter += 1 if self.counter > animation_cooldown: self.counter = 0 self.index += 1 if self.index >= len(self.images): self.index = 0 self.image = self.images[self.index] # Enemy class class Enemy(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() self.image = pygame.image.load('img/blob.png') 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 # Moving platform class class Platform(pygame.sprite.Sprite): def __init__(self, x, y, move_x, move_y): super().__init__() img = pygame.image.load('img/platform1.png') self.image = pygame.transform.scale(img, (tile_size * 1, tile_size // 2)) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y + 5 self.move_direction_x = move_x self.move_direction_y = move_y self.move_counter = 0 self.move_x = move_x self.move_y = move_y def update(self): self.rect.x += self.move_direction_x * self.move_x self.rect.y += self.move_direction_y * self.move_y self.move_counter += 1 if abs(self.move_counter) > 33: self.move_direction_x *= -1 self.move_direction_y *= -1 self.move_counter *= -1 # Lava obstacle class class Lava(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() 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 - 0 self.rect.y = y + - 5 # Exit door class class Exit(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() 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 - 5 # Create player and initial world player = Player(100, screen_height - 130) world = reset_level(level) 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) # Main game loop run = True while run: clock.tick(fps) screen.blit(bg_img, (0, 0)) #Main menu if main_menu: if start_button.draw(): main_menu = False if exit_button.draw(): run = False #Draw world and update classes--- else: world.draw() if game_over == 0: blob_group.update() lava_group.update() coin_group.update() platform_group.update() if pygame.sprite.spritecollide(player, coin_group, True): score += 1 #--- blob_group.draw(screen) lava_group.draw(screen) coin_group.draw(screen) platform_group.draw(screen) exit_group.draw(screen) score_text = font.render(f'Score: {score}', True, (255, 255, 255)) screen.blit(score_text, (10, 10)) seconds = (pygame.time.get_ticks() - start_ticks) // 1000 timer_text = font.render(f"Time: {seconds}", True, (255, 255, 255)) text_width = timer_text.get_width() screen.blit(timer_text, (screen_width - text_width - 10, 10)) # 10 px from right game_over = player.update(game_over) # Restart if player dies if game_over == -1: if restart_button.draw(): world = reset_level(level) game_over = 0 score = 0 start_ticks = pygame.time.get_ticks() # Advance to next level if player wins if game_over == 1: level += 1 if level <= max_levels: world = reset_level(level) game_over = 0 else: main_menu = True level = 0 for event in pygame.event.get(): if event.type == pygame.QUIT: run = False pygame.display.update() pygame.quit()