# name : Platformer # purpose: DGT2 2025 # Author: Lachlan Chapman # Created: 30/04/25 # Copyright: ©Lachlan Chapman import pygame from pygame.locals import * import pickle from os import path pygame.init() clock = pygame.time.Clock() fps = 60 screen_width = 1000 screen_height = 1000 screen = pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption('Platformer') # define game variables tile_size = 50 game_over = 0 main_menu = True win_screen = False level = 1 max_levels = 7 # load images bg_img = pygame.image.load('sky.png') start_img = pygame.image.load('start_btn.png') exit_img = pygame.image.load('exit_btn.png') win_bg = pygame.image.load('Win Screen.png') restart_game_img = pygame.image.load('Start Button.png') menu_button_img = pygame.image.load('Menu Button.png') title_img = pygame.image.load('Cloudstuck.png') awoke_img = pygame.image.load('awoke.png') # new image added # function to reset level def reset_level(level): player.reset(100, screen_height - 130) blob_group.empty() lava_group.empty() exit_group.empty() world_data = [] if path.exists(f'level{level}_data'): with open(f'level{level}_data', 'rb') as pickle_in: world_data = pickle.load(pickle_in) world = World(world_data) return world 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 not self.clicked: action = True self.clicked = True if pygame.mouse.get_pressed()[0] == 0: self.clicked = False screen.blit(self.image, self.rect) return action class Player(): def __init__(self, x, y): self.reset(x, y) def update(self, game_over): dx = 0 dy = 0 walk_cooldown = 5 if game_over == 0: key = pygame.key.get_pressed() if key[pygame.K_SPACE] and not self.jumped and not self.in_air: self.vel_y = -15 self.jumped = 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] 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] self.vel_y += 1 if self.vel_y > 10: self.vel_y = 10 dy += self.vel_y self.in_air = True for tile in world.tile_list: if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height): dx = 0 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 if pygame.sprite.spritecollide(self, blob_group, False): game_over = -1 if pygame.sprite.spritecollide(self, lava_group, False): game_over = -1 if pygame.sprite.spritecollide(self, exit_group, False): game_over = 1 self.rect.x += dx self.rect.y += dy self.rect.x = max(0, min(self.rect.x, screen_width - self.width)) 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'guy{num}.png') img_right = pygame.transform.scale(img_right, (40, 80)) 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('ghost.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 class World(): def __init__(self, data): self.tile_list = [] dirt_img = pygame.image.load('dirt.png') floor_img = pygame.image.load('floor.png') for row_count, row in enumerate(data): for col_count, tile in enumerate(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(floor_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 - 10) blob_group.add(blob) if tile == 6: lava = Lava(col_count * tile_size, row_count * tile_size) lava_group.add(lava) if tile == 8: exit = Exit(col_count * tile_size, row_count * tile_size - (tile_size // 2)) exit_group.add(exit) def draw(self): for tile in self.tile_list: screen.blit(tile[0], tile[1]) class Enemy(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() self.image_right = pygame.image.load('enemy1.png') self.image_left = pygame.image.load('enemy3.png') self.image_right = pygame.transform.scale(self.image_right, (tile_size, tile_size)) self.image_left = pygame.transform.scale(self.image_left, (tile_size, tile_size)) self.image = self.image_right 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 self.image = self.image_right if self.move_direction > 0 else self.image_left class Lava(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() img = pygame.image.load('lava.png') new_width = tile_size + 10 new_height = tile_size self.image = pygame.transform.scale(img, (new_width, new_height)) self.rect = self.image.get_rect() self.rect.x = x - 5 self.rect.y = y class Exit(pygame.sprite.Sprite): def __init__(self, x, y): super().__init__() img = pygame.image.load('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 player = Player(100, screen_height - 130) blob_group = pygame.sprite.Group() lava_group = pygame.sprite.Group() exit_group = pygame.sprite.Group() world_data = [] if path.exists(f'level{level}_data'): with open(f'level{level}_data', 'rb') as pickle_in: world_data = pickle.load(pickle_in) world = World(world_data) restart_button = Button(screen_width // 2 - 50, screen_height // 2 + 100, restart_game_img) start_button = Button(screen_width // 2 - 330, screen_height // 2 + 150, start_img) exit_button = Button(screen_width // 2 + 40, screen_height // 2 + 150, exit_img) start_game_button = Button(screen_width // 2 - 207, screen_height // 2 + 200, restart_game_img) menu_button = Button(screen_width // 2 + 40, screen_height // 2 + 200, menu_button_img) run = True while run: clock.tick(fps) if main_menu: screen.blit(bg_img, (0, 0)) title_rect = title_img.get_rect(center=(screen_width // 2, 450)) screen.blit(title_img, title_rect) if exit_button.draw(): run = False if start_button.draw(): main_menu = False level = 1 game_over = 0 win_screen = False world = reset_level(level) elif win_screen: screen.blit(win_bg, (0, 0)) awoke_rect = awoke_img.get_rect(center=(screen_width // 2, 300)) screen.blit(awoke_img, awoke_rect) if start_game_button.draw(): main_menu = False level = 1 game_over = 0 win_screen = False world = reset_level(level) if menu_button.draw(): main_menu = True level = 1 game_over = 0 win_screen = False world = reset_level(level) else: screen.blit(bg_img, (0, 0)) world.draw() # Draw screen border border_color = (255, 255, 255) border_thickness = 4 pygame.draw.rect(screen, border_color, (0, 0, screen_width, screen_height), border_thickness) if game_over == 0: blob_group.update() blob_group.draw(screen) lava_group.draw(screen) exit_group.draw(screen) game_over = player.update(game_over) if game_over == -1: if restart_button.draw(): world = reset_level(level) game_over = 0 if game_over == 1: level += 1 if level <= 3: world = reset_level(level) game_over = 0 else: win_screen = True for event in pygame.event.get(): if event.type == pygame.QUIT: run = False pygame.display.update() pygame.quit()