# Is this Pygame projectile code efficient?

Just wanted a few opinions on whether this game's code is efficient, from looking at it, it does look a bit all over the place but I just don't know how to 'tidy' it up to say so. Would love to hear your opinions and even better if you could show me how it's done.

#Here i am importing all necessary modules
import math,random,pygame,sys

#This class's purpose is to keep track of the current score
class Game():
def __init__(self): #This is the class constructor
self.score=0
self.goalNumbers=0

#This is the gun's class
class Gun(pygame.sprite.Sprite): #Sprite class from the Pygame module
def __init__(self): #This is the class constructor
pygame.sprite.Sprite.__init__(self)
self.rect = self.image.get_rect() #Getting the image's Rect
self.rect.x = 240 #Setting the rect's X position
self.rect.y = 630 #Setting the rect's Y position

#This function allows the gun to move
def moveGun(self,orientation):
if orientation=="left" and self.rect.x>5:
self.rect.x-=5
if orientation=="right" and self.rect.x<(480-self.rect.width):
self.rect.x+=5

# Set up class for bullets

class Projectile(pygame.sprite.Sprite):
def __init__(self,gun):
pygame.sprite.Sprite.__init__(self)
self.rect=self.image.get_rect()
self.rect.x=gun.rect.x+(gun.rect.width/2)-(self.rect.width/2)
self.rect.y=gun.rect.y-gun.rect.height

# Set up method to move bullets up the screen

def updateProjectile(self):
if self.rect.y>0-self.rect.height:
self.rect.y-=5
else:
self.kill()

# Set up class for fruit

class Objects(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.obj=random.randint(1,3)
if self.obj==1: imagefile="raspberry"
if self.obj==2: imagefile="strawberry"
if self.obj==3: imagefile="cherry"
self.image=pygame.transform.rotate(self.image,-15+random.randint(0,20))
self.rect=self.image.get_rect()
self.rect.y=-0-self.rect.height
self.rect.x=(random.randint(2,44)*10)

# Set up method to enable fruit to fall down the screen

def updateProjectile(self,game):
if self.rect.y<640:
self.rect.y+=3
else:
if self.obj==1:
game.score+=10
game.goalNumbers+=1
else:
game.score-=50
self.kill()

# Set up method to update score and remove fruit when shot

def shot(self,game):
if self.obj == 1:
game.score-=50
else:
game.score+=10
self.kill()

# Initialise the game

pygame.init()
pygame.key.set_repeat(1, 20)
countFont = pygame.font.Font(None,18)
statusFont = pygame.font.Font(None,18)
bColour = (52, 152, 219)
screen = pygame.display.set_mode([480, 640])
pygame.display.set_caption(' Game')

# Create initial object instances

game=Game()
gun=Gun()
sprites=pygame.sprite.Group()
obstacles=pygame.sprite.Group()
projectiles=pygame.sprite.Group()

# Initialise game over flag and timer

end_game=False
clock=pygame.time.Clock()
tick=0

# Main loop starts here

while end_game!=True:
clock.tick(30)
tick+=1
screen.fill(bColour)

# Process events

for event in pygame.event.get():
if event.type==pygame.QUIT:
sys.exit
if event.type==pygame.KEYDOWN:
if event.key==pygame.K_LEFT:
gun.moveGun("left")
if event.key==pygame.K_RIGHT:
gun.moveGun("right")
if event.key==pygame.K_SPACE:
projectile=Projectile(gun)

# Move objects

for projectile in projectiles:
projectile.updateProjectile()

for obstacle in obstacles:
obstacle.updateProjectile(game)

# Add new fruit if 2 seconds has elapsed

if tick>60:
if len(obstacles)<10:
obstacle=Objects()
tick=0

# Check for collisions

collisions=pygame.sprite.groupcollide(obstacles,projectiles,False,True)
if collisions:
for obstacle in collisions:
obstacle.shot(game)

# Update player score

scoreText=countFont.render('Score:'+str(game.score),True,(255,255,255),(52, 152, 219))
screen.blit(scoreText,(0,620))
statusText=statusFont.render('Raspberries:'+str(10-game.goalNumbers),True,(255,210,210),(52, 152, 219))
screen.blit(statusText,(0,10))

# Update the screen and check for game over

sprites.draw(screen); projectiles.draw(screen); obstacles.draw(screen)
pygame.display.flip()
if game.goalNumbers>=10:
end_game=True

# Game over: display the player's final score

scoreCountHolder.convert_alpha()
left=90;top=250
screen.blit(scoreCountHolder,(left,top))
countFont=pygame.font.Font(None,52)
statusText=countFont.render('Your Score:'+str(game.score),True,(52, 152, 219),(231,230,33))
screen.blit(statusText,(105,300))
pygame.display.flip()

# Wait for the player to close the game window

while True:
for event in pygame.event.get():
if event.type==pygame.QUIT:
sys.exit()


I can't really comment on the performance since I found it difficult to read, especially the spaces around the operators throughout the code.

As you mention though, I would focus first on cleanup and applying PEP 8. There are many issues with spacing around operations, spacing between/after definitions, line length, etc. That would help with the readability.

The other part that seems difficult is the "main" logic near the bottom. It is good convention to place that in a "main" function and then use the "if main" at the bottom. So you would have somethning like this:

def main():
pygame.init()
pygame.key.set_repeat(1, 20)
countFont = pygame.font.Font(None, 18)
statusFont = pygame.font.Font(None, 18)
bColour = (52, 152, 219)
...

if __name__ == '__main__':
main()


Once you have that you can look to see if any of the parts in "main" need to be broken out into functions.

On the PEP 8 side, here is an example of some of your code with Pep 8 type formatting applied so you can see the difference in how it visually looks.

""" Pygame - Shooting fruit game. """
import random
import sys
import pygame

class Game():
""" The Game class's purpose is to keep track of the current score. """
def __init__(self):
self.score = 0
self.goalNumbers = 0

class Gun(pygame.sprite.Sprite):
""" This is the gun that the user moves to shoot the fruit. """
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.rect = self.image.get_rect()
self.rect.x = 240
self.rect.y = 630

def moveGun(self, orientation):
""" Move the gun on the screen. """
if orientation == "left" and self.rect.x > 5:
self.rect.x -= 5
if orientation == "right" and self.rect.x < (480 - self.rect.width):
self.rect.x += 5

class Projectile(pygame.sprite.Sprite):
""" This is for the bullets. """
def __init__(self, gun):
pygame.sprite.Sprite.__init__(self)