7
\$\begingroup\$

I made a program that runs my version of Space Invaders.

I recently finished it. I just want to make it more pythonic, and streamline it so it uses less memory and performs faster.

The basic outline of the program is at this website.

import pygame, sys, random
from pygame.locals import *

# set up pygame
pygame.init()
mainClock = pygame.time.Clock()

# set up the window
width = 800
height = 700
screen = pygame.display.set_mode((width, height), 0, 32)
pygame.display.set_caption('caption')

# set up movement variables
moveLeft = False
moveRight = False
moveUp = False
moveDown = False

# set up direction variables
DOWNLEFT = 1
DOWNRIGHT = 3
UPLEFT = 7
UPRIGHT = 9
LEFT = 4
RIGHT = 6
UP = 8
DOWN = 2

# set up the colors
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BLUE = (135, 206, 250)
blue1 = (236, 237, 252)
blue2 = (195, 197, 240)
blue3 = (111, 115, 196)
blue4 = (77, 81, 167)
blue5 = (111, 115, 196)
bg = (152, 155, 221)
paddle = (195, 197, 240)

MOVESPEED = 11
MOVE = 1
SHOOT = 15

# set up counting
score = 0

# set up font
font = pygame.font.SysFont('calibri', 50)

def makeplayer():
    player = pygame.Rect(370, 635, 60, 25)
    return player

def makeinvaders(invaders):
    y = 0
    for i in invaders: 
        x = 0
        for j in range(11): 
            invader = pygame.Rect(75+x, 75+y, 50, 20)
            i.append(invader)
            x += 60
        y += 45
    return invaders

def makewalls(walls):
    wall1 = pygame.Rect(60, 520, 120, 30)
    wall2 = pygame.Rect(246, 520, 120, 30)
    wall3 = pygame.Rect(432, 520, 120, 30)
    wall4 = pygame.Rect(618, 520, 120, 30)
    walls = [wall1, wall2, wall3, wall4]
    return walls

def movepaddle(player):
    if moveLeft and player.left > 0:
        player.left -= MOVESPEED
    if moveRight and player.right < width:
        player.right += MOVESPEED
    return player

def moveinvaders(invaders, invader_dir):
    for row in invaders:
        for invader in row:
            if invader_dir == RIGHT and row[len(row)-1].right < width:
                invader.right += MOVE
            elif row[len(row)-1].right >= width:
                invader.left -= MOVE
                invader_dir = LEFT
            elif invader_dir == LEFT and row[0].left > 0:
                invader.left -= MOVE
            elif row[0].left <= 0:
                invader.right += MOVE
                invader_dir = RIGHT
    return invader_dir

def doRectsOverlap(bullet, invader):
    for a, b in [(bullet, invader), (invader, bullet)]:
        if ((isPointInsideRect(a.left, a.top, b)) or
            (isPointInsideRect(a.left, a.bottom, b)) or
            (isPointInsideRect(a.right, a.top, b)) or
            (isPointInsideRect(a.right, a.bottom, b))):
            return True
    return False

def isPointInsideRect(x, y, invader):
    if (x > invader.left) and (x < invader.right) and (y > invader.top) and (y <
        invader.bottom):
        return True
    else:
        return False

def invaderdead(bullets, invaders):
    for bullet in bullets:
        for row in invaders:
            for invader in row:
                if doRectsOverlap(bullet, invader):
                    row.remove(invader)
                    bullets.remove(bullet)
    return invaders

def wallhit(bullets, walls):
    for bullet in bullets:
        for wall in walls:
            if doRectsOverlap(bullet, wall):
                bullets.remove(bullet)
                wall.height -= 10
                if wall.height <= 0:
                    walls.remove(wall)
    return bullets,walls

def movebullets(bullets):
    for bullet in bullets:
        bullet.top -= SHOOT

def moveenemybullets(bullets):
    for bullet in bullets:
        bullet.bottom += SHOOT

def gameend(invaders):
    if invaders == [[],[],[],[],[]]:
        screen.fill(bg)
        drawText('You win.', font, screen , 300, 300, blue4)

def drawplayerinvaderbullet(player, invaders, bullets):
    pygame.draw.rect(screen, blue4, player)
    for i in invaders:
        for invader in i:
            if invader in invaders[0]:
                pygame.draw.rect(screen, blue1, invader)
            elif invader in invaders[1]:
                pygame.draw.rect(screen, blue2, invader)
            elif invader in invaders[2]:
                pygame.draw.rect(screen, blue3, invader)
            elif invader in invaders[3]:
                pygame.draw.rect(screen, blue4, invader)
            elif invader in invaders[4]:
                pygame.draw.rect(screen, blue5, invader)
    for w in walls:
        pygame.draw.rect(screen, blue3, w)
    for b in bullets:
        pygame.draw.rect(screen, blue2, b)

def drawText(text, font, surface, x, y, color):
    text = font.render(text, 1, color)
    textrect = text.get_rect()
    textrect.topleft = (x, y)
    surface.blit(text, textrect)

timer = mainClock.tick()
time = 0
invaders = [[],[],[],[],[]]
invader_dir = RIGHT
bullets = []
walls = []

player = makeplayer()
invaders = makeinvaders(invaders)
walls = makewalls(walls)

# run the game loop
while True:
    # check for the QUIT event
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        if event.type == KEYDOWN:
            if event.key == K_LEFT or event.key == ord('a'):
                moveRight = False
                moveLeft = True
            if event.key == K_RIGHT or event.key == ord('d'):
                moveLeft = False
                moveRight = True
            if event.key == K_SPACE:
                bullet = pygame.Rect(player.left+28, player.top-8, 5, 8)
                bullets.append(bullet)
        if event.type == KEYUP:
            if event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()
            if event.key == K_LEFT or event.key == ord('a'):
                moveLeft = False
            if event.key == K_RIGHT or event.key == ord('d'):
                moveRight = False
    time += timer

    screen.fill(bg)
    drawplayerinvaderbullet(player, invaders, bullets)
    invader_dir = moveinvaders(invaders, invader_dir)
    movebullets(bullets)
    if time % 5000 == 0:
        x = random.choice([1,2,3,4,5])
        list1 = invaders[x-1]
        y = random.choice([1,2,3,4,5,6,7,8,9,10,11])
        invader = list1[y-1]
        bullet = pygame.Rect(invader.right+28, invader.bottom-8, 5, 8)
        bullets.append(bullet)
        moveenemybullets(bullets)
    gameend(invaders)
    invaders = invaderdead(bullets, invaders)
    bullets, walls = wallhit(bullets, walls)
    player = movepaddle(player)
    pygame.display.update()
    mainClock.tick(60)
\$\endgroup\$

1 Answer 1

5
\$\begingroup\$

I have a few suggestions for improvement regarding PEP8 and design improvements.

  • You have about 40 PEP8 violations. Many of them are naming issues, or issues with your spacing. For reference, here are a few things that you can improve/change:
    • There should be two blank lanes between functions and classes.
    • Functions and variables should be in camel_case, and classes should be in PascalCase.
    • Variables with values (constants) that don't change should be in UPPER_CAMEL_CASE.
    • You should have spaces after commas, like this [a, b, c].
    • There should be spaces between operators, e.g, 1 + 2, or 5 ** 6.
  • Your design pattern, is... odd to say the least. I'd go for a more object-oriented design. For example, have an Enemy class that contains methods and attributes that an enemy would have. You could also have an EnemyGroup class which manages groups of enemies. In the current state, the functional design isn't very reusable, and it's hard to maintain.

If there's anything else you'd specifically like me to cover, let me know and I will.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I did some research and noticed that there is a pep8 fixer that automatically brings your code up to the standard. Thanks! \$\endgroup\$ Jun 9, 2015 at 2:07
  • 1
    \$\begingroup\$ @RegisteredUser No problem! :) \$\endgroup\$ Jun 9, 2015 at 2:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.