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