You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

449 lines
17 KiB
Python

# 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()