Apr-24-2017, 04:41 PM
A simple little breakout program I wrote using PyGame.
############################################################################################################# # ________ ___ ___ ________ ________ _______ ________ ___ __ ________ ___ ___ __________ # # |\ __ \|\ \ / /|\ __ \|\ __ \|\ ___ \ |\ __ \|\ \|\ \ |\ __ \|\ \|\ \|\___ ___\ # # \ \ \|\ \ \ \/ / | \ \|\ /\ \ \|\ \ \ __/|\ \ \|\ \ \ \/ /|\ \ \|\ \ \ \\\ \|___ \ \_| # # \ \ ____\ \ / / \ \ __ \ \ _ _\ \ \_|/_\ \ __ \ \ ___ \ \ \\\ \ \ \\\ \ \ \ \ # # \ \ \___|\/ / / \ \ \|\ \ \ \\ \\ \ \_|\ \ \ \ \ \ \ \\ \ \ \ \\\ \ \ \\\ \ \ \ \ # # \ \__\ __/ / / \ \_______\ \__\\ _\\ \_______\ \__\ \__\ \__\\ \__\ \_______\ \_______\ \ \__\ # # \|__||\___/ / \|_______|\|__|\|__|\|_______|\|__|\|__|\|__| \|__|\|_______|\|_______| \|__| # # \|___|/ # # v1.0 # ############################################################################################################# # PyBreakout 1.0 # Terry Ritchie # 04/24/17 # ----------------------------------------------------------------------------------------------------------- # - IMPORT LIBRARIES ---------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------------------- import pygame # pygame graphics engine import random # random number library import os # operating system library import winsound # windows sound library import sys # system functions from pygame.locals import * # pygame constants # ----------------------------------------------------------------------------------------------------------- # - DEFINE CONSTANTS ---------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------------------- FPS = 240 # frames per second of game play BLACK = ( 0, 0, 0) # define bright colors BLUE = ( 0, 0, 255) GREEN = ( 0, 255, 0) CYAN = ( 0, 255, 255) RED = (255, 0, 0) PURPLE = (255, 0, 255) YELLOW = (255, 255, 0) WHITE = (255, 255, 255) DBLUE = ( 0, 0, 127) # define dark colors DGREEN = ( 0, 127, 0) DCYAN = ( 0, 127, 127) DRED = (127, 0, 0) DPURPLE = (127, 0, 127) DYELLOW = (127, 127, 0) GRAY = (127, 127, 127) SILVER = (191, 191, 191) COLOR = (BLUE, GREEN, CYAN, RED, PURPLE, YELLOW, DBLUE, DGREEN, DCYAN, DRED, DPURPLE, DYELLOW) STARS = 100 # number of stars in starfield STARX = 0 # star x index within star list STARY = 1 # star y index within star list STARSPEED = 2 # star speed index within star list STARCOLOR = 3 # star color index within star list STARCLDIR = 4 # star color direction index within star list INPLAY = 4 # brick in play index within brick list BRICKHIT = 5 # number of times brick hit index within brick list # ----------------------------------------------------------------------------------------------------------- # - DEFINE VARIABLES ---------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------------------- brick = [] # master brick list star = [] # master star list saying = [] # rendered font surface images of each level text scoretext = [] # custom number font launch = False # ball has been launched newgame = False # new game in progress levelshown = False # has level saying been shown extra = False # extra paddle awarded spacebar = 0 # rendered font surface image p1txt = 0 # rendered font surface image hitxt = 0 # rendered font surface image welcome = 0 # rendered font surface image screen = 0 # window surface px = 0 # player paddle x coordinate py = 516 # player paddle y coordinate prect = 0 # paddle collision rectangle paddles = 3 # number of player paddles bx = 0.0 # ball x coordinate by = 0.0 # ball y coordinate brect = 0 # ball collision rectangle bxdir = 0.0 # ball x direction bydir = 0.0 # ball y direction bspeed = 0.0 # ball speed maxbspeed = 0.0 # ball maximum speed minxspeed = 0.0 # ball minimum horizontal speed bspeedinc = 0.0 # ball speed increment trajectory = 0.0 # ball trajectory when hit paddle score = 0 # player score hiscore = 0 # high score level = 0 # current level of play bhit = 0 # number of times brick must be hit bricks = 0 # total number of bricks clock = 0 # FPS timer countdown = 0 # count down timer frame = 0 # frame counter # ----------------------------------------------------------------------------------------------------------- # - DEFINE FUNCTIONS ---------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------------------- def Setup(): # creates the assets needed to play the game Setup() # ----------------------------------------------------------------------------------------------------------- global screen, clock, star, brick, spacebar, p1txt, hitxt, saying, welcome os.environ["SDL_VIDEO_CENTERED"] = "1" # center the surface on desktop pygame.init() # start pygame engine screen = pygame.display.set_mode((768, 576)) # create the surface window pygame.display.set_caption("PyBreakout!") # give window a caption pygame.mouse.set_visible(False) # hide mouse pointer clock = pygame.time.Clock() # start clock routines font = pygame.font.SysFont("Calibri", 40, True, False) # create font and rendered surfaces spacebar = font.render("PRESS SPACEBAR TO LAUNCH", True, WHITE) p1txt = font.render("PLAYER 1", True, YELLOW) hitxt = font.render("HIGH", True, YELLOW) welcome = font.render("WELCOME TO PYBREAKOUT!", True, WHITE) saying.append(font.render("Try Again", True, CYAN)) saying.append(font.render("Level 1 - Easy Peasy", True, CYAN)) saying.append(font.render("Level 2 - Here We Go!", True, CYAN)) saying.append(font.render("Level 3 - Twice As Fun", True, CYAN)) saying.append(font.render("Level 4 - Even Faster", True, CYAN)) saying.append(font.render("Level 5 - Outstanding!", True, CYAN)) saying.append(font.render("Level 6 - Double Whammy", True, CYAN)) saying.append(font.render("Level 7 - Super Human", True, CYAN)) saying.append(font.render("Level 8 - Unstoppable!", True, CYAN)) saying.append(font.render("Level 9 - Here Be Dragons", True, CYAN)) saying.append(font.render("Breakout Master!", True, CYAN)) scoretext.append(["0000 00 00 0000"]) # create custom number strings list scoretext.append([" 1 1 1 1 1"]) scoretext.append(["222 22222 222"]) scoretext.append(["333 3333 3333"]) scoretext.append(["4 44 4444 4 4"]) scoretext.append(["5555 555 5555"]) scoretext.append(["6666 6666 6666"]) scoretext.append(["777 7 7 7 7"]) scoretext.append(["8888 88888 8888"]) scoretext.append(["9999 9999 9999"]) for i in range(STARS): # create starfield sx = random.randrange(0, 767) sy = random.randrange(0, 575) cd = 0 while not(cd): cd = random.randrange(-1, 2) ss = 0 while ss < .25: ss = random.random() star.append([sx, sy, ss, random.randrange(1, 255), cd]) for i in range(6): # create bricks b = [] for j in range(16): b.append([j * 48 + 1, 96 + (i * 24) + 1, 47, 23, True, 0]) brick.append(b) # ----------------------------------------------------------------------------------------------------------- def Draw_Digit(dx, dy, d, c, s): # draw a large digit to the screen Draw_Digit() # ----------------------------------------------------------------------------------------------------------- # dx = digit top left x coordinate # dy = digit top left y coordinate # d = digit (0 - 9) # c = digit color # s = size of digit squares # The large digits are drawn as follows: # # x # --------- # 0 1 2 # +---+---+---+ +---+---+---+ If there is a character (non-space) in the text a # | 0 | * | * | * | | * | * | * | square is drawn in that position. As the nested for # | +---+---+---+ +---+---+---+ statements progress a number is drawn from the text # | 1 | * | | * | | | | * | that describes where a square should be placed in # | +---+---+---+ +---+---+---+ each row. # y | 2 | * | | * | | * | * | * | # | +---+---+---+ +---+---+---+ # | 3 | * | | * | | | | * | # | +---+---+---+ +---+---+---+ # | 4 | * | * | * | | * | * | * | # | +---+---+---+ +---+---+---+ # # "0000 00 00 0000" "333 3333 3333" # |||---|||---||| |||---|||---||| # Row-> 0 1 2 3 4 0 1 2 3 4 p = -1 # current position in text string for y in range(5): for x in range(3): p += 1 # increment text position if scoretext[d][0][p] != " ": # if character in position draw square pygame.draw.rect(screen, c, [dx + x * s, dy + y * s, s, s], 0) # ----------------------------------------------------------------------------------------------------------- def New_Game(): # starts a new game of pybreakout New_Game() # ----------------------------------------------------------------------------------------------------------- global level, launch, newgame, levelshown, score, paddles, extra launch = False # reset booleans newgame = True levelshown = False while newgame: # loop while in new game mode Play_Round() score = 0 # reset player score level = 0 # reset level of play paddles = 3 # reset number of player paddles extra = False # reset extra paddle # ----------------------------------------------------------------------------------------------------------- def Next_Level(): # sets up the next level of the game Next_Level() # ----------------------------------------------------------------------------------------------------------- global level, bspeed, bxdir, bydir, brick, bhit, maxbspeed, bspeedinc, bricks global launch, trajectory, levelshown, countdown, minxspeed, frame level += 1 # increment level of play bspeed = 1 # reset ball characteristics bxdir = .5 bydir = -1 if not(level % 3): # bricks hit twice every third level bhit = 2 else: bhit = 1 for i in range(6): # reset brick characteristics for j in range(16): brick[i][j][INPLAY] = True brick[i][j][BRICKHIT] = 0 bricks = 96 maxbspeed = 2 + (level / 8) # calculate maximum ball speed if maxbspeed > 4: maxbspeed = 4 minxspeed = maxbspeed / 4 * (1 + (maxbspeed / 4)) # calculate minimum ball horizontal speed bspeedinc = level / 96 # calculate ball speed increments trajectory = (100 / (level * 100)) * 200 # calculate level trajectory launch = True # reset booleans levelshown = False countdown = 9 # reset countdown frame = 0 # ----------------------------------------------------------------------------------------------------------- def Draw_Frame(): # draws a frame of the game Draw_Frame() # ----------------------------------------------------------------------------------------------------------- global countdown, frame, launch screen.fill(BLACK) Draw_Stars() # draw starfield Draw_Bricks() # draw bricks pygame.draw.circle(screen, RED, [px - 40, 526], 10, 0) # draw paddle pygame.draw.circle(screen, RED, [px + 40, 526], 10, 0) pygame.draw.rect(screen, WHITE, [px - 40, 516, 80 , 20], 0) for i in range(paddles): # draw paddles remaining x = (i + 1) * 60 pygame.draw.circle(screen, RED, [x - 20, 560], 5, 0) pygame.draw.circle(screen, RED, [x + 20, 560], 5, 0) pygame.draw.rect(screen, WHITE, [x - 19, 555, 38, 10], 0) screen.blit(hitxt, [525, 0]) # display text screen.blit(p1txt, [155, 0]) scoretxt = ((6 - len(str(score))) * "0") + str(score) # format scores hiscoretxt = ((6 - len(str(hiscore))) * "0") + str(hiscore) for i in range(6): # draw scores Draw_Digit(326 + (i * 20), 5, int(scoretxt[i]), WHITE, 5) Draw_Digit(628 + (i * 20), 5, int(hiscoretxt[i]), WHITE, 5) leveltxt = ((2 - len(str(level))) * "0") + str(level) for i in range(2): Draw_Digit(740 + (i * 8), 555, int(leveltxt[i]), WHITE, 2) if launch: # display level text lev = 0 if not(levelshown): lev = level if lev > 10: lev = 10 if paddles > 0: screen.blit(saying[lev], [(768 - pygame.Surface.get_width(saying[lev])) // 2, 265]) screen.blit(spacebar, [140, 400]) if countdown > 6: # display count down timer clr = GREEN elif countdown > 3: clr = YELLOW else: clr = RED Draw_Digit(369, 325, countdown, clr, 10) frame += 1 if frame == FPS: frame = 0 countdown -= 1 winsound.Beep(2200, 5) if countdown == 0: launch = False if newgame: screen.blit(welcome, [145,300]) else: pygame.draw.circle(screen, CYAN, [int(bx), int(by)], 7, 0) # draw ball pygame.display.flip() # ----------------------------------------------------------------------------------------------------------- def Draw_Stars(): # draws the moving starfield Draw_Stars() # ----------------------------------------------------------------------------------------------------------- global star for i in range(STARS): # cycle through all stars star[i][STARY] += star[i][STARSPEED] # update speed star[i][STARCOLOR] += star[i][STARCLDIR] # update color if star[i][STARCOLOR] == 0 or star[i][STARCOLOR] == 255: # keep color in limits star[i][STARCLDIR] *= -1 if star[i][STARY] >= 767: # star went off bottom of screen star[i][STARY] = random.randrange(-30, -10) star[i][STARX] = random.randrange(0, 768) c = star[i][STARCOLOR] pygame.draw.circle(screen, [c, c, c], [star[i][STARX], int(star[i][STARY])], 0, 0) # ----------------------------------------------------------------------------------------------------------- def Draw_Bricks(): # check for ball/brick collisions while bricks being drawn Draw_Bricks() # ----------------------------------------------------------------------------------------------------------- global bxdir, bydir, score, hiscore, bspeed, bricks, brick, extra, paddles alreadyhit = False for i in range(6): # cycle through all bricks for j in range(16): if brick[i][j][INPLAY]: # draw brick if in play brick_rect = pygame.Rect(brick[i][j][0:4]) pygame.draw.rect(screen, COLOR[i + brick[i][j][BRICKHIT] * 6], brick_rect, 0) if not(newgame): if brect.colliderect(brick_rect) and not(alreadyhit): # first brick hit? brick[i][j][BRICKHIT] += 1 # update brick hits if brick[i][j][BRICKHIT] == bhit: # max number of hits? brick[i][j][INPLAY] = False # brick out of play bricks -= 1 score += (6 - i) * 10 winsound.Beep((6 - i) * 200, 10) else: # brick still in play score += (6 - i) * 5 winsound.Beep(2200, 10) if score >= 10000 and not(extra): # award extra ship paddles += 1 extra = True for i in range(5): winsound.Beep((i + 1) * 1000, 5) alreadyhit = True # no more collision checks this loop bspeed += bspeedinc # increase ball speed if bspeed > maxbspeed: # keep ball speed in limits bspeed = maxbspeed if score > hiscore: # update high score hiscore = score if sgn(bxdir) == 1: # ball traveling right bdx = int(brick_rect[0] - bx) # ball distance from left side of brick else: # ball traveling left bdx = int(bx - brick_rect[0]) - 46 # ball distance from right side of brick if sgn(bydir) == 1: # ball traveling down bdy = int(brick_rect[1] - by) # ball distance from top of brick else: # ball traveling up bdy = int(by - brick_rect[1]) - 22 # ball distance from bottom of brick if bdx == bdy: # hit corner of brick bxdir = -bxdir bydir = -bydir elif bdx > bdy: # hit left/right side of brick bxdir = -bxdir else: # hit top/bottom of brick bydir = -bydir # ----------------------------------------------------------------------------------------------------------- def Get_Input(): # gets user input and processes Get_Input() # ----------------------------------------------------------------------------------------------------------- global px, launch, levelshown, newgame pygame.event.pump() # update keyboard buffer key = pygame.key.get_pressed() # get all keys pressed if key[K_SPACE] and launch: # launch ball with space bar? launch = False levelshown = True for event in pygame.event.get(): # cycle through events if event.type == QUIT or key[K_ESCAPE]: # leave game if closed or ESC pressed pygame.quit() sys.exit() elif (event.type == KEYUP or event.type == MOUSEBUTTONUP) and newgame: # start a new game? newgame = False launch = True elif event.type == MOUSEBUTTONUP and launch: # launch ball with mouse button? launch = False levelshown = True elif event.type == MOUSEMOTION: # mouse moved? px = event.pos[0] # set player paddle x to mouse x if px < 50: # keep paddle on screen px = 50 elif px > 718: px = 718 pygame.mouse.set_pos(px, py) # bind mouse to paddle # ----------------------------------------------------------------------------------------------------------- def Play_Round(): # plays a round of pybreakout Play_Round() # ----------------------------------------------------------------------------------------------------------- global bx, by, bxdir, bydir, px, brect, launch, paddles, bspeed, countdown Get_Input() # get user input and process if launch or newgame: # keep ball on paddle bx = px by = 511 else: # update ball position bx += bxdir by += bydir * bspeed if bx <= 7: # hit left side of screen? bx = 7 bxdir = -bxdir elif bx >= 760: # hit right side of screen? bx = 760 bxdir = -bxdir if by <= 7: # hit top of screen? bydir = -bydir elif by >= 568: # player missed ball? paddles -= 1 launch = True bspeed = 1 bxdir = .5 bydir = -1 countdown = 9 brect = pygame.Rect(bx - 5, by - 5, 10, 10) # create ball rectangle object prect = pygame.Rect(px - 50, 516, 100, 1) # create paddle rectangle object if brect.colliderect(prect): # did the objects collide? bydir = -bydir by = 511 bxdir += (bx - px) / trajectory # add some trajectory if abs(bxdir) > maxbspeed: # keep horizontal ball speed in limits bxdir = sgn(bxdir) * maxbspeed elif abs(bxdir) < minxspeed: bxdir = sgn(bxdir) * minxspeed winsound.Beep(440, 10) Draw_Frame() # draw the next frame of game clock.tick(FPS) # limit FPS # ----------------------------------------------------------------------------------------------------------- def sgn(n): # returns the sign of a number (-1, 0, or 1) sgn() # ----------------------------------------------------------------------------------------------------------- # n = any numeric value if n > 0: # positive return 1 elif n < 0: # negative return -1 else: # must be zero return 0 # ----------------------------------------------------------------------------------------------------------- # - MAIN PROGRAM LOOP --------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------------------- Setup() # generate game assets while True: # main loop New_Game() # initiate a new game while paddles > 0: # loop until player loses all paddles Next_Level() # set up next level of play while paddles > 0 and bricks: # loop until no paddles or bricks cleared Play_Round() # play the round