Team Aperture Science's Game: Portal 2D
'''
2D Portal Game
'''
import time
import sys
import random
import pygame
import math
# Constants
FPS = 60
SCREEN_WIDTH = 1200
SCREEN_HEIGHT = 615
BTN_PADDING = 10 # How much padding are we going to put around a button?
BTN_MARGIN = 10 # How much space do we want around button text?
# Colors
GREEN = [10, 230, 20]
WHITE = [255, 255, 255]
GREY = [175, 175, 175]
BLACK = [0, 0, 5]
YELLOW = [255, 229, 153]
DARKER_YELLOW = [255, 217, 102]
ORANGE = [255, 165, 0]
ASCREEN = pygame.image.load("title.png")
pygame.init() # As always, initialize pygame
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
clock = pygame.time.Clock()
menu_font = pygame.font.SysFont('impact', 32) # Here's our button font
print("Loaded the font!")
screen_mode = 'title' # Modes: title, menu
menu_btn_color = WHITE
menu_btn_hover_color = GREY
################################################################################
# Title screen components
################################################################################
title_screen_bg = pygame.image.load("title.png")
##############################################################################
# Level Menu
##############################################################################
Levels_screen_bg = pygame.image.load("Levels.png")
Levels_screen_buttons = ['Level One', 'Level Two', 'Level Three', 'back'] # Available buttons
cur_menu_btn_id = 0 # What button are we currently on?
btn_color = YELLOW
# === Title text ===
title_font = pygame.font.SysFont('impact', 128)
title_surface = title_font.render('PORTAL', True, WHITE)
title_rect = title_surface.get_rect()
title_rect.x = 50
title_rect.y = 300
# === Open menu button ===
Levels_btn_txt_surface = menu_font.render('back', True, BLACK)
menu_btn_txt_surface = menu_font.render('Start', True, BLACK)
Levels_btn_bg_rect = Levels_btn_txt_surface.get_rect()
menu_btn_bg_rect = menu_btn_txt_surface.get_rect()
#size correctly
menu_btn_bg_rect.width += (2*BTN_MARGIN)
menu_btn_bg_rect.height += (2*BTN_MARGIN)
#position it
menu_btn_bg_rect.x = title_rect.midbottom[0] - (menu_btn_bg_rect.width / 2)
menu_btn_bg_rect.y = title_rect.midbottom[1] + BTN_PADDING
menu_btn_txt_rect = menu_btn_txt_surface.get_rect()
menu_btn_txt_rect.x = title_rect.midbottom[0] - (menu_btn_txt_rect.width / 2)
menu_btn_txt_rect.y = title_rect.midbottom[1] + BTN_PADDING + BTN_MARGIN
# === Level One button ===
# Render Level_One btn text onto surface
Level_One_btn_txt_surface = menu_font.render('Level One', True, BLACK)
# Setup Level_One button background
Level_One_btn_bg_rect = Level_One_btn_txt_surface.get_rect()
Level_One_btn_bg_rect.width += 2 * BTN_MARGIN
Level_One_btn_bg_rect.height += 2 * BTN_MARGIN
Level_One_btn_bg_rect.x = (SCREEN_WIDTH / 2) - (0.5 * Level_One_btn_bg_rect.width)
Level_One_btn_bg_rect.y = 50
# Setup the Level_One button text
Level_One_btn_txt_rect = Level_One_btn_txt_surface.get_rect()
Level_One_btn_txt_rect.x = Level_One_btn_bg_rect.x + BTN_MARGIN
Level_One_btn_txt_rect.y = Level_One_btn_bg_rect.y + BTN_MARGIN
# === Level_Two button ===
# Render Level_Two btn text onto surface
Level_Two_btn_txt_surface = menu_font.render('Level Two (not done)', True, BLACK)
# Setup Level_Two button background
Level_Two_btn_bg_rect = Level_Two_btn_txt_surface.get_rect()
Level_Two_btn_bg_rect.width += 2 * BTN_MARGIN
Level_Two_btn_bg_rect.height += 2 * BTN_MARGIN
Level_Two_btn_bg_rect.x = (SCREEN_WIDTH / 2) - (0.5 * Level_Two_btn_bg_rect.width)
Level_Two_btn_bg_rect.y = Level_One_btn_bg_rect.y + (Level_One_btn_bg_rect.height + BTN_PADDING)
# Setup the Level_Two button text
Level_Two_btn_txt_rect = Level_Two_btn_txt_surface.get_rect()
Level_Two_btn_txt_rect.x = Level_Two_btn_bg_rect.x + BTN_MARGIN
Level_Two_btn_txt_rect.y = Level_Two_btn_bg_rect.y + BTN_MARGIN
# === Level Three button ===
# Render quit btn text onto surface
Level_Three_btn_txt_surface = menu_font.render('Level Three (in progress)', True, BLACK)
# Setup quit button background
Level_Three_btn_bg_rect = Level_Three_btn_txt_surface.get_rect()
Level_Three_btn_bg_rect.width += 2 * BTN_MARGIN
Level_Three_btn_bg_rect.height += 2 * BTN_MARGIN
Level_Three_btn_bg_rect.x = (SCREEN_WIDTH / 2) - (0.5 * Level_Three_btn_bg_rect.width)
Level_Three_btn_bg_rect.y = Level_Two_btn_bg_rect.y + (Level_One_btn_bg_rect.height + BTN_PADDING)
# Setup the quit button text
Level_Three_btn_txt_rect = Level_Three_btn_txt_surface.get_rect()
Level_Three_btn_txt_rect.x = Level_Three_btn_bg_rect.x + BTN_MARGIN
Level_Three_btn_txt_rect.y = Level_Three_btn_bg_rect.y + BTN_MARGIN
# === Back Button =======
# Render back btn text onto surface
back_btn_txt_surface = menu_font.render('back', True, BLACK)
# Setup back button background
back_btn_bg_rect = back_btn_txt_surface.get_rect()
back_btn_bg_rect.width += 2 * BTN_MARGIN
back_btn_bg_rect.height += 2 * BTN_MARGIN
back_btn_bg_rect.x = (SCREEN_WIDTH) - (back_btn_bg_rect.width)
back_btn_bg_rect.y = 615 - 50
# Setup the back button text
back_btn_txt_rect = back_btn_txt_surface.get_rect()
back_btn_txt_rect.x = back_btn_bg_rect.x + BTN_MARGIN
back_btn_txt_rect.y = back_btn_bg_rect.y + BTN_MARGIN
#LEVEL ONE INFO
platform_height = 10
screen_rectangle = screen.get_rect()
bottom_platform = pygame.Rect(
screen_rectangle.left,
screen_rectangle.bottom - platform_height,
screen_rectangle.right - screen_rectangle.left,
platform_height)
level_one_walls = [
bottom_platform,
pygame.Rect([100, 520], [400, 10]),
pygame.Rect([1, 425], [400, 10]),
pygame.Rect([800, 425], [400, 10]),
pygame.Rect([800, 425], [10, 190]),
pygame.Rect([1, 1], [10, 615]),
pygame.Rect([1190, 1], [10, 613]),
pygame.Rect([700, 340], [200, 10]),
pygame.Rect([800, 255], [400, 10]),
pygame.Rect([1, 255], [500, 10]),
pygame.Rect([250, 180], [10, 75])]
level_one_exit_rectangle = pygame.Rect([70, 280], [39, 75])
level_one_exit_img = pygame.image.load("exit_redone.png")
level_one_exit_rectangle = level_one_exit_img.get_rect()
target_img = pygame.image.load("portaltarget.png")
target_x = 0
target_y = 0
chell_location_x = 10
chell_location_y = 500
platform_height = 10
platform_color = WHITE
chell_velocity_x = 0 # Larger means moving faster rightwards
chell_velocity_y = 0 # Larger means moving faster downwards
GRAVITATIONAL_CONSTANT = 0.1
is_standing = False
chell_left = pygame.image.load("chell_blue_standingleft.png")
chell_right = pygame.image.load("chell_blue_standing.png")
chell_img = chell_right
chell_rectangle = chell_img.get_rect()
mouse_pos = [0,0]
proj_rect = pygame.rect.Rect(0, 0, 10, 10)
proj_x = 0
proj_y = 0
proj_speed = 8
direction = [0, 0]
blue_portal_rect = pygame.rect.Rect(0, 0, 5, 75)
orange_portal_rect = pygame.rect.Rect(0, 0, 5, 75)
pygame.mixer.music.load("background_music.ogg")
pygame.mixer.music.play(-1, 0.0)
blue_on = False
orange_on = False
portal_timeout = 0.5
last_tele = 0
pygame.mouse.set_visible(True)
##############################################################################
##############################################################################
# Main Game Loop
##############################################################################
##############################################################################
# Game loop
while True:
screen.blit(ASCREEN, [0,0])
# We need to show different things depending on whether or not we're in 'title'
# or 'menu' mode
if screen_mode == 'title':
# ==== TITLE SCREEN MODE ====
# Draw the title screen
# Render the title text in the middle of the screen
screen.blit(title_surface, title_rect)
# Draw the menu button, first: the text
pygame.draw.rect(screen, menu_btn_color, menu_btn_bg_rect)
screen.blit(menu_btn_txt_surface, menu_btn_txt_rect)
elif screen_mode == 'Levels':
# === MENU SCREEN MODE ===
screen.blit(Levels_screen_bg, [0,0])
# Draw button rectangles!
# - If button is active, color background with hover color and an outline
# - otherwise, draw with normal color and no outline
if Levels_screen_buttons[cur_menu_btn_id] == 'back':
pygame.draw.rect(screen, menu_btn_hover_color, back_btn_bg_rect)
pygame.draw.rect(screen, BLACK, back_btn_bg_rect, 5)
else:
pygame.draw.rect(screen, menu_btn_color, back_btn_bg_rect)
if Levels_screen_buttons[cur_menu_btn_id] == 'Level_One':
pygame.draw.rect(screen, menu_btn_hover_color, Level_One_btn_bg_rect)
pygame.draw.rect(screen, BLACK, Level_One_btn_bg_rect, 5)
else:
pygame.draw.rect(screen, menu_btn_color, Level_One_btn_bg_rect)
if Levels_screen_buttons[cur_menu_btn_id] == 'Level_Two':
pygame.draw.rect(screen, menu_btn_hover_color, Level_Two_btn_bg_rect)
pygame.draw.rect(screen, BLACK, Level_Two_btn_bg_rect, 5)
else:
pygame.draw.rect(screen, menu_btn_color, Level_Two_btn_bg_rect)
if Levels_screen_buttons[cur_menu_btn_id] == 'Level_Three':
pygame.draw.rect(screen, menu_btn_hover_color, Level_Three_btn_bg_rect)
pygame.draw.rect(screen, BLACK, Level_Three_btn_bg_rect, 5)
else:
pygame.draw.rect(screen, menu_btn_color, Level_Three_btn_bg_rect)
# Layer button text over button backgrounds
screen.blit(Level_One_btn_txt_surface, Level_One_btn_txt_rect)
screen.blit(Level_Two_btn_txt_surface, Level_Two_btn_txt_rect)
screen.blit(Level_Three_btn_txt_surface, Level_Three_btn_txt_rect)
screen.blit(back_btn_txt_surface, back_btn_txt_rect)
########################################################################################################
# PHYSICAL OUTLOOK OF EACH LEVEL. INSERT CODE BELOW.
#########################################################################################################
elif screen_mode == "Level_One":
screen.fill(BLACK)
screen.blit(target_img, [target_x, target_y])
for wall in level_one_walls:
pygame.draw.rect(screen, WHITE ,wall)
if blue_on == True:
pygame.draw.rect(screen, [100, 100, 255], blue_portal_rect)
if orange_on == True:
pygame.draw.rect(screen, [255, 165, 0], orange_portal_rect)
if time.time() - last_tele > portal_timeout and blue_on == True and orange_on == True:
if chell_rectangle.colliderect(blue_portal_rect):
chell_rectangle.center = orange_portal_rect.center
last_tele = time.time()
elif chell_rectangle.colliderect(orange_portal_rect):
chell_rectangle.center = blue_portal_rect.center
last_tele = time.time()
#Shooting
if is_shooting == 'Blue'or is_shooting == 'Orange':
direction = [mouse_pos[0] - chell_rectangle.left, mouse_pos[1] - chell_rectangle.top]
normal = math.sqrt(direction[0] **2 + direction[1] **2)
direction[0] /= normal
direction[1] /= normal
direction[0] *= proj_speed
direction[1] *= proj_speed
proj_x += direction[0]
proj_y += direction[1]
proj_rect.x = proj_x
proj_rect.y = proj_y
if is_shooting == 'Blue':
pygame.draw.rect(screen, [100, 100, 255], proj_rect)
elif is_shooting == 'Orange':
pygame.draw.rect(screen, [255, 165, 0], proj_rect)
if proj_rect.collidelist(level_one_walls) != -1:
if is_shooting == 'Blue':
blue_on = True
blue_portal_rect.center = proj_rect.center
else:
orange_on = True
orange_portal_rect.center = proj_rect.center
is_shooting = ""
############################################################################################################
# Player Shooting and Movement
############################################################################################################
if screen_mode == "Level_One" or screen_mode == "Level_Two" or screen_mode == "Level_Three":
exit_img = pygame.image.load("exit_redone.png")
exit_rectangle = exit_img.get_rect()
screen_rectangle = screen.get_rect()
bottom_platform = pygame.Rect(
screen_rectangle.left,
screen_rectangle.bottom - platform_height,
screen_rectangle.right - screen_rectangle.left,
platform_height)
platforms = [bottom_platform]
is_standing = False
index = chell_rectangle.collidelist(level_one_walls)
if index != -1:
touching_platform = level_one_walls[index]
is_just_touching_down = chell_rectangle.bottom - touching_platform.top < platform_height
is_descending = chell_velocity_y > 0
# is_descending = True
if is_just_touching_down and is_descending:
chell_location_y = touching_platform.top - chell_rectangle.height
is_standing = True
chell_velocity_y = 0
# Draw chell (this is the hardest because we need to use chell's
# x and y location to determine where to place them).
if chell_rectangle.colliderect(level_one_exit_rectangle):
screen_mode = "Levels"
pygame.mouse.set_visible(True)
if chell_velocity_x >0:
chell_img = chell_right
if chell_velocity_x <0:
chell_img = chell_left
chell_rectangle.left += chell_velocity_x
if chell_rectangle.left <= 0:
chell_rectangle.left = 0
elif chell_rectangle.right >= SCREEN_WIDTH:
chell_rectangle.right = SCREEN_WIDTH
chell_velocity_y += GRAVITATIONAL_CONSTANT
chell_rectangle.top += chell_velocity_y
print(chell_rectangle.top, GRAVITATIONAL_CONSTANT)
if chell_rectangle.top <= 0:
chell_rectangle.top = 0
elif chell_rectangle.bottom >= SCREEN_HEIGHT:
chell_rectangle.bottom = SCREEN_HEIGHT
screen.blit(chell_img, chell_rectangle)
screen.blit(level_one_exit_img, level_one_exit_rectangle)
else:
# ==== ???? MODE ====
print("UNRECOGNIZED SCREEN MODE! Exiting.")
pygame.quit()
sys.exit()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# ===== TITLE MODE EVENTS =====
if screen_mode == 'title' and event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = pygame.mouse.get_pos()
if menu_btn_bg_rect.collidepoint(mouse_pos):
screen_mode = 'Levels'
cur_menu_btn_id = 0
# ===== LEVELS MODE EVENTS =====
if screen_mode == 'Levels' and event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = pygame.mouse.get_pos()
if back_btn_bg_rect.collidepoint(mouse_pos):
screen_mode = 'title'
cur_menu_btn_id = 0
print("test")
if screen_mode == 'Levels' and event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = pygame.mouse.get_pos()
if Level_One_btn_bg_rect.collidepoint(mouse_pos):
screen_mode = 'Level_One'
chell_rectangle.top = 500
cur_menu_btn_id = 0
print("test")
if screen_mode == 'Level_One':
if event.type == pygame.MOUSEBUTTONDOWN:
pygame.mouse.set_visible(False)
mouse_pos = pygame.mouse.get_pos()
pressed = pygame.mouse.get_pressed()
if pressed[0] == True:
is_shooting = 'Blue'
elif pressed[2] == True:
is_shooting = 'Orange'
proj_x, proj_y = chell_rectangle.center
elif event.type == pygame.MOUSEMOTION:
x, y = event.pos
target_x = x
target_y = y
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP and is_standing:
# if event.key == pygame.K_UP
# changing them to make chell jump or run faster.
chell_velocity_y = -3.9
if event.key == pygame.K_RIGHT:
chell_velocity_x = 4
if event.key == pygame.K_LEFT:
chell_velocity_x = -4
# This code ensures that when you release the left or right arrow keys
# chell stops moving.
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
chell_velocity_x = 0
if event.key == pygame.K_LEFT:
chell_velocity_x = 0
clock.tick(FPS)
pygame.display.update()
|>> download student-games/aperture-science/game.py