# Imports import pygame import pygame.locals import pygame_textbox import os from os import path from threading import Thread import pickle import time import random # Set Up pygame.init() tile_size = 50 screen_width = tile_size * 35 screen_height = (900) screen = pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption("Unexpected Adventure") fps = 60 clock = pygame.time.Clock() level = 1 main_menu = True game_over = False white = (255, 255, 255) font = pygame.font.SysFont('Futura', 24) doesnt_exist = False scroll = [0,0] # Load Images background1 = pygame.image.load("images/background4.png").convert_alpha() background2 = pygame.image.load("images/background3.png").convert_alpha() background3 = pygame.image.load("images/background2.png").convert_alpha() background4 = pygame.image.load("images/background1.png").convert_alpha() left = pygame.image.load("images/left.png").convert_alpha() middle = pygame.image.load("images/middle.png").convert() right = pygame.image.load("images/right.png").convert_alpha() door = pygame.image.load("images/door.png").convert_alpha() button_edit = pygame.image.load("images/button_edit.png").convert() button_custom = pygame.image.load("images/button_custom.png").convert() button_start = pygame.image.load("images/button_start.png").convert() button_exit = pygame.image.load("images/button_exit.png").convert() button_music = pygame.image.load("images/button_music.png").convert() button_restart = pygame.image.load("images/button_restart.png").convert() # Sprite Groups water_group = pygame.sprite.Group() enemy_group = pygame.sprite.Group() door_group = pygame.sprite.Group() # World Class class World(): # Init def __init__(self, data): self.tile_list = [] row_count = 0 for row in data: column_count = 0 for tile in row: if tile == 1: tile = pygame.transform.scale(left, (tile_size, tile_size)) tile_rect = tile.get_rect() tile_rect.x = column_count * tile_size tile_rect.y = row_count * tile_size tile = (tile, tile_rect) self.tile_list.append(tile) elif tile == 2: tile = pygame.transform.scale(middle, (tile_size, tile_size)) tile_rect = tile.get_rect() tile_rect.x = column_count * tile_size tile_rect.y = row_count * tile_size tile = (tile, tile_rect) self.tile_list.append(tile) elif tile == 3: tile = pygame.transform.scale(right, (tile_size, tile_size)) tile_rect = tile.get_rect() tile_rect.x = column_count * tile_size tile_rect.y = row_count * tile_size tile = (tile, tile_rect) self.tile_list.append(tile) elif tile == 4: water = Water(column_count * tile_size, row_count * tile_size + (tile_size // 2)) water_group.add(water) elif tile == 5: enemy = Enemy(column_count * tile_size, row_count * tile_size + 15, row_count, column_count, data) enemy_group.add(enemy) elif tile == 6: door = Door(column_count * tile_size, row_count * tile_size - (tile_size // 2)) door_group.add(door) column_count += 1 row_count +=1 # Draw World def draw(self): for tile in self.tile_list: screen.blit(tile[0], (tile[1].x - scroll[0] + screen_width // 2, tile[1].y - scroll[1] + screen_height // 2)) # Water class Water(pygame.sprite.Sprite): # Init def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) image = pygame.image.load("images/water1.png").convert_alpha() self.image = pygame.transform.scale(image, (tile_size, tile_size)) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y -25 self.images = [] self.image_index = 1 for number in range(1, 17): img = pygame.image.load(f"images/water{number}.png").convert_alpha() img = pygame.transform.scale(img, (tile_size, tile_size)) self.images.append(img) self.image = self.images[self.image_index] self.counter = 0 # Update def update(self): self.image_index += 1 if self.image_index < len(self.images): self.image = self.images[self.image_index] else: self.image_index = 0 self.image = self.images[self.image_index] def render(self, screen): screen.blit(self.image, (self.rect.x - scroll[0] + screen_width // 2, self.rect.y - scroll[1] + screen_height // 2)) # Enemy Class class Enemy(pygame.sprite.Sprite): # Init def __init__(self, x, y, row_count, column_count, data): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load("images/enemy.png").convert_alpha() self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y self.move_direction = 5 self.move_counter = 0 self.row_count = row_count self.column_count = column_count self.data = data # Update def update(self): if self.data[self.row_count + 1][self.column_count] == 2: self.rect.x += self.move_direction self.move_counter += 1 if self.move_counter > 10: self.move_direction *= - 1 self.move_counter*= -1 def render(self, screen): screen.blit(self.image, (self.rect.x - scroll[0] + screen_width // 2, self.rect.y - scroll[1] + screen_height // 2)) # Door class Door(pygame.sprite.Sprite): # Init def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) image = pygame.image.load("images/door.png").convert_alpha() self.image = pygame.transform.scale(image, (tile_size, tile_size + 26)) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y def render(self, screen): screen.blit(self.image, (self.rect.x - scroll[0] + screen_width // 2, self.rect.y - scroll[1] + screen_height // 2)) # Button Class class Button(): # Init def __init__(self, x, y, image): self.image = image self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y # Draw Button def draw(self): mouse_position = pygame.mouse.get_pos() clicked = False if self.rect.collidepoint(mouse_position): if pygame.mouse.get_pressed()[0] == 1: clicked = True time.sleep(0.2) screen.blit(self.image, self.rect) return clicked # Player Class class Player(): # Init def __init__(self, x, y): self.reset(x, y) self.game_over = False self.image_index = 0 # Move Player def update(self, game_over , main_menu): # Frame Rate clock.tick(fps) # Move Player dx = 0 dy = 0 if game_over == False: key = pygame.key.get_pressed() # Jump if key[pygame.K_w] and self.jumped == False and self.in_air == False: self.vel_y = -15 self.jumped = True elif key[pygame.K_w] == False: self.jumped = False # Left if key[pygame.K_a]: dx -= 7 self.direction = "left" # Right elif key[pygame.K_d]: dx += 7 self.direction = "right" # Animations if key[pygame.K_a] == False and key[pygame.K_d] == False: if self.direction == "left": self.image = self.images_left[0] elif self.direction == "right": self.image = self.images_right[0] else: self.index += 1 if self.index >= len(self.images_right) or self.index >= len(self.images_left): self.index = 0 if self.direction == "left": self.image = self.images_left[self.index] elif self.direction == "right": self.image = self.images_right[self.index] # Gravity self.vel_y += 1 if self.vel_y > 10: self.vel_y = 15 dy += self.vel_y # Collisions self.in_air = True for tile in world.tile_list: # Animations if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height): if dx < 0: self.image = self.images_left[0] else: self.image = self.images_right[0] # X and Y if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height): dx = 0 # Vertical if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height): if self.vel_y >= 0: dy = tile[1].top - self.rect.bottom self.in_air = False elif self.vel_y < 0: dy = tile[1].bottom - self.rect.top self.vel_y = 0 # Collision With Door if pygame.sprite.spritecollide(self, door_group, False): main_menu = True # Game Over Conditions if self.rect.bottom > screen_height: game_over = True elif pygame.sprite.spritecollide(self, water_group, False): game_over = True elif pygame.sprite.spritecollide(self, enemy_group, False): game_over = True # Game Over if game_over == True: self.image = self.dead_image self.rect.y -= 5 # Update Coordinates self.rect.x += dx self.rect.y += dy # Draw Player screen.blit(self.image, (self.rect.x - scroll[0] + screen_width // 2, self.rect.y - scroll[1] + screen_height // 2)) return game_over, main_menu # Reset Player def reset(self, x, y): # Set Up self.images_right = [] self.images_left = [] self.index = 0 # Load Images for num in range(1, 5): img_right = pygame.image.load(f"images/guy{num}.png").convert_alpha() 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("images/ghost.png").convert_alpha() self.image = self.images_right[0] # Rect 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() # Other Variables self.direction = 0 self.vel_y = 0 self.jumped = False self.in_air = True # Level Editor def level_editor(): print(os.path.join(os.getcwd(), "venv", "bin", "python3.9")) os.system(os.path.join(os.getcwd(), "venv", "bin", "python3.9") + " " + os.path.join(os.getcwd(), "level_editor.py")) # Draw Text def draw_text(text, font, text_col, x, y): img = font.render(text, True, text_col) screen.blit(img, (x, y)) # Scale and Initialise Classes background1 = pygame.transform.scale(background1, (2000, 1000)) background2 = pygame.transform.scale(background2, (2000, 1000)) background3 = pygame.transform.scale(background3, (2000, 1000)) background4 = pygame.transform.scale(background4, (2000, 1000)) start_button = pygame.transform.scale(button_start, (200, 100)) exit_button = pygame.transform.scale(button_exit, (80, 35)) player = Player(100, screen_height - 180) start_button = Button(screen_width // 2 -100 , screen_height // 2 - 100, start_button) exit_button = Button(screen_width // 2 - 40, screen_height // 2 + 50, exit_button) edit_button = Button(screen_width // 2 -250, screen_height // 2 + 30, button_edit) custom_button = Button(screen_width // 2 + 150 , screen_height // 2 + 30 , button_custom) music_button = Button(screen_width // 2 + 700 , screen_height // 2 - 400 , button_music) menu_button = Button(screen_width //2 + 700 , screen_height //2 - 300, button_exit) restart_button = Button(screen_width // 2 - 50, screen_height // 2 , button_restart) # Background Music pygame.mixer.music.load("sounds/music.mp3") pygame.mixer.music.play(-1) paused = False # Game Loop run = True while run: # FPS clock.tick(fps) screen.fill((0,0,0)) # QUIT events = pygame.event.get() for event in events: if event.type == pygame.QUIT: run = False # Draw Background screen.blit(background4, (0 - scroll[0]* 0.2, 0)) screen.blit(background3, (0 - scroll[0]* 0.4, 0)) screen.blit(background2, (0 - scroll[0]* 0.5, 0)) screen.blit(background1, (0 - scroll[0]* 0.6, 0)) screen.blit(background4, (2000 - scroll[0]* 0.2, 0)) screen.blit(background3, (2000 - scroll[0]* 0.4, 0)) screen.blit(background2, (2000 - scroll[0]* 0.5, 0)) screen.blit(background1, (2000 - scroll[0]* 0.6, 0)) screen.blit(background4, (-2000 - scroll[0]* 0.2, 0)) screen.blit(background3, (-2000 - scroll[0]* 0.4, 0)) screen.blit(background2, (-2000 - scroll[0]* 0.5, 0)) screen.blit(background1, (-2000 - scroll[0]* 0.6, 0)) # Menu if main_menu: game_over = False # Start if start_button.draw(): enemy_group.empty() water_group.empty() door_group.empty() if path.exists(f"levels/storymode/level_{level}"): pickle_in = open(f"levels/storymode/level_{level}", "rb") level_data = pickle.load(pickle_in) world = World(level_data) main_menu = False player.reset(100, screen_height - 130) doesnt_exist = False # Level Editor elif edit_button.draw() == True: thread = Thread(target = level_editor) thread.start() doesnt_exist = False # Custom Maps if custom_button.draw(): enemy_group.empty() water_group.empty() door_group.empty() selected_level = pygame_textbox.textinput() if path.exists(f"levels/custom/level_{selected_level}"): pickle_in = open(f"levels/custom/level_{selected_level}", "rb") level_data = pickle.load(pickle_in) world = World(level_data) main_menu = False screen = pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption("Unexpected Adventure") player.reset(100, screen_height - 130) doesnt_exist = False else: doesnt_exist = True screen = pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption("Unexpected Adventure") player.reset(100, screen_height - 130) if doesnt_exist: draw_text("Level Doesn't Exist", font, white, screen_width // 2 - 75, screen_height // 2 + 17) # Exit if exit_button.draw(): run = False # Music if music_button.draw(): if paused == False: pygame.mixer.music.pause() paused = True else: pygame.mixer.music.unpause() paused = False # Game if main_menu == False: # Draw World world.draw() water_group.update() for water in water_group: water.render(screen) enemy_group.update() for enemy in enemy_group: enemy.render(screen) door_group.update() for door in door_group: door.render(screen) # Update Player game_over, main_menu = player.update(game_over , main_menu) scroll[0] += (player.rect.x - scroll[0])*0.02 scroll[1] = 450 # Music Button if music_button.draw(): if paused == False: pygame.mixer.music.pause() paused = True else: pygame.mixer.music.unpause() paused = False # Menu Button if menu_button.draw(): player.reset(100, screen_height - 130) enemy_group.empty() water_group.empty() door_group.empty() main_menu = True game_over = False # Restart Button if game_over == True: if restart_button.draw(): player.reset(100, screen_height - 130) game_over = False # Update Display pygame.display.update() # Quit Pygame pygame.quit()