4
\$\begingroup\$

Ongoing development of game. The player is controlled by mouse click to move upward. The goal is to avoid meteors for as long as possible. I would be grateful if someone could critique my code.

Verison 1 can be found here. Since then I have:

  • Added intro menu screen
  • Added game loop to contain main game logic
  • Added health to game, game over screen when health == 0
  • Removed unnecessary and redundant comments
  • Implemented recommendations found in original post

Still working on:

  • Adding rotation to meteors
  • Display health with health bar
  • Buttons in intro menu
# All images found @ http://kenney.nl/assets/space-shooter-extension, http://kenney.nl/assets/space-shooter-redux, and https://www.goldstar.com/events/los-angeles-ca/the-sirens-of-titan-tickets

import pygame
import random
pygame.init()
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

def game_intro():
    intro = False
    intro_background = pygame.image.load("assets/title_screen.png")
    # Get dimensions of background
    width = background.get_width()
    height = background.get_height() 
    HW, HH = width/2, height/2
    screen = pygame.display.set_mode((width,height))
    intro_background = intro_background.convert()

    while not intro: 
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True 
            if event.type == pygame.MOUSEBUTTONDOWN:
                game_loop(background)

        screen.blit(intro_background, (0,0))        
        message_display("Click to take Constant home")
        pygame.display.update()

        clock.tick(15)


    pygame.quit()

def game_loop(background):
    done = False 
    x = 0 
    health = 5 
    while not done:
        dt = clock.tick(30)
        # Main event Loop 
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True
            if event.type == pygame.MOUSEBUTTONDOWN:
                player.ignite()

        #-----Game Logic 

        # Draw background and move to the left
        rel_x = x % width
        screen.blit(background, (rel_x - width, 0))
        if rel_x < width:
            screen.blit(background, (rel_x, 0))
        x -= 2

        # Check to see if player has collided with meteor
        meteor_hit_list = pygame.sprite.spritecollide(player, meteor_group, 
                                                      True)
        # Event if player collides with meteor 
        for item in meteor_hit_list:
            health -= 1
            print("Shuttle hit", health)
            if health == 0:
                game_over()
            create_meteor()               

        distance(screen)
        all_sprites_group.draw(screen)
        meteor_group.update()
        player.update(dt/1000)

        pygame.display.flip()


    pygame.quit()

def game_over():
    exit = False 
    screen = pygame.display.set_mode((850,526))


    while not exit: 
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                game_intro()

        screen.fill(BLACK)
        message_display("GAME OVER! Click to restart")
        pygame.display.update()

        pygame.display.flip()

        clock.tick(30)


    pygame.quit()

def create_meteor():
    meteor = Meteor(width, height)
    meteor_group.add(meteor)
    all_sprites_group.add(meteor)

def message_display(text):
    font = pygame.font.SysFont("transistor", 25, True, False)
    travel_text = font.render(text, True, WHITE)
    screen.blit(travel_text, (HW-150, HH))

def distance(screen):
    """Show how far the rocketship has travelled."""
    # Get time since init was called
    time = pygame.time.get_ticks()
    # Convert milliseconds to seconds, 1 second = 1 km
    travel_distance = round(time/1000, 2)
    message_display("You have travelled " + str(travel_distance) + "  lightyears")

class Player(pygame.sprite.Sprite):
    def __init__(self,PLAYER_SURFACE, HW, HH):
        super().__init__()
        self.image = PLAYER_SURFACE            
        self.rect = pygame.rect.Rect(((HW - (PLAYER_SURFACE.get_width())), HH), 
                                       self.image.get_size())

        # Gravity
        self.dy = 0 

    def ignite(self):
        self.dy = -400

    def update(self, dt):

        # Apply gravity
        self.dy = min(400, self.dy + 40)
        self.rect.y += self.dy * dt

        # What happens if go to border of screen
        if self.rect.top <= 0:   # Top
            self.rect.y = 0
            self.dy = -4
        elif self.rect.bottom >= height:   # Bottom
            self.rect.y = 526-self.rect.height

class Meteor(pygame.sprite.Sprite):
    def __init__(self, width, height):
        super().__init__()
        self.image = random.choice(METEOR_IMAGES)   
        self.rect = self.image.get_rect()

        # Random starting location
        self.rect.x = random.randrange(width, (width + 300))
        self.rect.y = random.randrange(0, height)

        # Random movement to the left
        self.change_x = random.randrange(-10,-5)
        self.change_y = random.randrange(-4,3)

    def reset_pos(self, screen):
        self.image = random.choice(METEOR_IMAGES)
        self.rect = self.image.get_rect()

        self.rect.x = random.randrange(width, (width + 100))
        self.rect.y = random.randrange(0, height)

        # Random movement to the left
        self.change_x = random.randrange(-10,-5)
        self.change_y = random.randrange(-4,3)


    def update(self): 
        # Move meteor
        self.rect.x += self.change_x
        self.rect.y += self.change_y

        # Reset if falls off screen
        if self.rect.right < 0:
            self.reset_pos(screen)
        if self.rect.top > height:
            self.reset_pos(screen)
        if self.rect.bottom < 0:
            self.reset_pos(screen)

clock = pygame.time.Clock()

background = pygame.image.load("assets/background.png")

# Get dimensions of background
width = background.get_width()
height = background.get_height() 
HW, HH = width/2, height/2
screen = pygame.display.set_mode((width,height))
background = background.convert()


PLAYER_SURFACE = pygame.image.load("assets/player.png").convert_alpha()
METEOR_IMAGES = []
METEOR_LIST = [
    "assets/meteors/meteor1.png"...
]
for image in METEOR_LIST:
    METEOR_IMAGES.append(pygame.image.load(image).convert_alpha())

pygame.display.set_caption("Return from Titan")

all_sprites_group = pygame.sprite.Group()
meteor_group = pygame.sprite.Group()

# Create spaceship 
player = Player(PLAYER_SURFACE, HW, HH)
all_sprites_group.add(player)

# Create meteor sprites on the screen     
for i in range(4):
    create_meteor()

game_intro()
\$\endgroup\$
2
  • \$\begingroup\$ Thanks for the recommendation. I wasn't aware of the connection between stack exchange and stack overflow, so I used a guest username not knowing it would get linked to my account anyway. \$\endgroup\$ Jul 6, 2018 at 16:41
  • \$\begingroup\$ Looks pretty good. For the scenes I'd use a finite state machine similar to this or if you want to keep your scene functions, take a look at this example. \$\endgroup\$
    – skrx
    Jul 7, 2018 at 17:45

0

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.

Browse other questions tagged or ask your own question.