Клон Invaders, созданный с помощью Pygame

Это мой первый большой проект, который я начал после завершения руководства Pygame Shmup, составленного KidsCanCode. Я начинаю чувствовать, что это очень близко к завершению, поэтому я хотел опубликовать здесь свой код, чтобы узнать, что можно улучшить, а что не соответствует стандартам. Очки Брауни для тех, кто может понять, почему возникают ошибки анимации пришельцев после подкрепления!

Будем очень благодарны за любые комментарии и / или отзывы 🙂

Ссылка на Github: https://github.com/Dreadnought88111/Space-WIP

# Space WIP
# By Elias

# things to implement
    # boss introduction cinematic
    # announ. boss sound
    # victory sound

# have aliens jump down vertically rather than diagonally

# known issues:
    # aliens speed up when reinforcements are being dropped
    # boss and bossvessel rect can be coliided with in level 1 despite them not being generated yet
        # temporary fix introduced in the check collisions function not checking collision until level > 9

import math
import pygame
import random
import sys
from os import path

pygame.init()
pygame.mixer.init()

# asset folders
FONT_DIR = path.join(path.dirname(__file__), "fonts")
IMAGE_DIR = path.join(path.dirname(__file__), "images")
SOUND_DIR = path.join(path.dirname(__file__), "sounds")

# screen
WIDTH = 800
HEIGHT = 600
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Space WIP')
pygame.display.set_icon(pygame.image.load(path.join(IMAGE_DIR, "logo.png")).convert_alpha())
FPS = 60

# colours
BLACK = (0, 0, 0)
BLUE = (0, 255, 240)
GREEN = (0, 255, 0)
ORANGE = (255, 173, 0)
PURPLE = (255, 0, 255)
RED = (255, 0, 0)
WHITE = (255, 255, 255)

# fonts
FONT = path.join(FONT_DIR, '8-BitMadness.ttf')
LOGOFONT = path.join(FONT_DIR, "edunline.ttf")
STARTFONT = path.join(FONT_DIR, "upheavtt.ttf")

# images
alien2_1 = pygame.image.load(path.join(IMAGE_DIR, "enemy2_1.png")).convert_alpha()
alien2_2 = pygame.image.load(path.join(IMAGE_DIR, "enemy2_2.png")).convert_alpha()
alien_images = [pygame.transform.scale(alien2_1, (40, 35)), pygame.transform.scale(alien2_2, (40, 35))]

alien3_1 = pygame.image.load(path.join(IMAGE_DIR, "enemy3_1.png")).convert_alpha()
alien3_2 = pygame.image.load(path.join(IMAGE_DIR, "enemy3_2.png")).convert_alpha()
alien_backup_images = [pygame.transform.scale(alien3_1, (40, 35)), pygame.transform.scale(alien3_2, (40, 35))]

alien1_1 = pygame.image.load(path.join(IMAGE_DIR, "enemy1_1.png")).convert_alpha()
alien1_2 = pygame.image.load(path.join(IMAGE_DIR, "enemy1_2.png")).convert_alpha()
alien_elite_images = [pygame.transform.scale(alien1_1, (40, 35)), pygame.transform.scale(alien1_2, (40, 35))]

# music
MUSICVOLUME = 0.5

BACKGROUND1 = path.join(SOUND_DIR, 'Background1.ogg')
BACKGROUND2 = path.join(SOUND_DIR, 'Background2.ogg')

# sounds
SOUNDVOLUME = 0.2

ALIENAPPEAR = pygame.mixer.Sound(path.join(SOUND_DIR, 'AlienAppear.wav'))
ALIENAPPEAR.set_volume(SOUNDVOLUME)

ALIENEXPLOSIONSOUND = pygame.mixer.Sound(path.join(SOUND_DIR, 'AlienExplosion.wav'))
ALIENEXPLOSIONSOUND.set_volume(SOUNDVOLUME)

ALIENMOVESOUND = pygame.mixer.Sound(path.join(SOUND_DIR, 'AlienMove.wav'))
ALIENMOVESOUND.set_volume(SOUNDVOLUME)

GAMEOVER = pygame.mixer.Sound(path.join(SOUND_DIR, 'GameOver.wav'))
GAMEOVER.set_volume(MUSICVOLUME)  # not an error

LASERSOUND = pygame.mixer.Sound(path.join(SOUND_DIR, 'Laser.wav'))
LASERSOUND.set_volume(SOUNDVOLUME)

MYSTERYEXPLOSION = pygame.mixer.Sound(path.join(SOUND_DIR, 'MysteryExplosion.wav'))
MYSTERYEXPLOSION.set_volume(SOUNDVOLUME)

PLAYERHIT = pygame.mixer.Sound(path.join(SOUND_DIR, 'PlayerHit.wav'))
PLAYERHIT.set_volume(SOUNDVOLUME)

POWERUPGENERATED = pygame.mixer.Sound(path.join(SOUND_DIR, 'PowerupGenerated.wav'))
POWERUPGENERATED.set_volume(SOUNDVOLUME)

POWERUPPICKEDUP = pygame.mixer.Sound(path.join(SOUND_DIR, 'PowerupPickedUp.wav'))
POWERUPPICKEDUP.set_volume(SOUNDVOLUME)

SATELLITEANNOUNCE = pygame.mixer.Sound(path.join(SOUND_DIR, 'Satelliteannounce.wav'))
SATELLITEANNOUNCE.set_volume(SOUNDVOLUME)

SATELLITEEXPLOSION = pygame.mixer.Sound(path.join(SOUND_DIR, 'SatelliteExplosion.wav'))
SATELLITEEXPLOSION.set_volume(SOUNDVOLUME)

# sprite groups
alien_group = pygame.sprite.Group()
alien_backup_group = pygame.sprite.Group()
alien_elite_group = pygame.sprite.Group()
alien_master_group = pygame.sprite.Group()
alien_reinforcements_group = pygame.sprite.Group()
alien_laser_group = pygame.sprite.Group()

barrier_master_group = pygame.sprite.Group()
boss_group = pygame.sprite.Group()
bossvessel_group = pygame.sprite.Group()
bossvessel_laser_group = pygame.sprite.Group()

explosion_group = pygame.sprite.Group()

laser_group = pygame.sprite.Group()

mystery_group = pygame.sprite.Group()

player_group = pygame.sprite.Group()

powerup_group = pygame.sprite.Group()

satellite_group = pygame.sprite.Group()
star_group = pygame.sprite.Group()

# miscellaneous

should_aliens_drop = False
should_aliens_move = False

ALIENBACKUPSCORE = 20
ALIENDROP = 20
ALIENELITESCORE = 30
ALIENSCORE = 10
ALIENSPEED = 10
ALIENSTARTYPOS = 65

BOSSVESSELDISTANCE = 90
BOSSVESSELMAXHEALTH = 100

LASERSPEED = 5

MYSTERYSCORE = 100
MYSTERYSPEED = 5
MYSTERYTIME = 10
MYSTERYXPOS = -75

PLAYERSPEED = 7

POWERUPSPEED = 2

SATELLITESPEED = -5
SATELLITETIME = 3
SATELLITEXPOS = WIDTH + 31

STARSPEED = 1

time_last_hit = 0


class Player(pygame.sprite.Sprite):
    # the text in between brackets above ensure my class Player inherits from
    # the pygame Sprite class
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(path.join(IMAGE_DIR, "ship.png")).convert()
        self.image = pygame.transform.scale(self.image, (45, 45))
        self.rect = self.image.get_rect(topleft=(300, 540))
        self.speed = PLAYERSPEED
        self.lives = 5
        self.score = 0
        self.last_shot = pygame.time.get_ticks() / 1000
        self.cool_down = 0.5
        self.radius = 21
        self.double_shot = False

    def update(self, keys):
        if keys[pygame.K_LEFT] and self.rect.left >= 0:
            self.rect.x -= self.speed
        if keys[pygame.K_RIGHT] and self.rect.right <= WIDTH:
            self.rect.x += self.speed


class Alien(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.index = 0
        self.image = alien_images[self.index]
        self.rect = self.image.get_rect()
        self.alien_last_moved = 0
        self.speed = ALIENSPEED

    def update(self, now):

        global should_aliens_drop
        global should_aliens_move

        if now - self.alien_last_moved >= 0.5:
            self.alien_last_moved = now

            if self.rect.right + self.speed >= (WIDTH - 10) or self.rect.left + self.speed <= 10:
                should_aliens_drop = True
            else:
                should_aliens_move = True


class AlienBackup(Alien):
    def __init__(self):
        super().__init__()
        self.image = alien_backup_images[Alien().index]


class AlienElite(Alien):
    def __init__(self):
        super().__init__()
        self.image = alien_elite_images[Alien().index]


class Barrier(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((5, 5))
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

    def update(self, keys, *args):
        pass


class Boss(Alien):
    def __init__(self):
        super().__init__()
        self.index = 0
        self.image = alien_images[self.index]
        self.rect = self.image.get_rect()
        self.alien_last_moved = 0
        self.speed = ALIENSPEED

    def update(self, now, *args):

        global should_aliens_drop
        global should_aliens_move

        if now - self.alien_last_moved >= 0.5:
            self.alien_last_moved = now

            if self.rect.right + (bossvessel.width / 2) + self.speed >= (WIDTH - 10) 
                    or self.rect.left - (bossvessel.width / 2) + self.speed <= 10:
                should_aliens_drop = True
            else:
                should_aliens_move = True


class Bossvessel(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.width = 220
        self.height = 200
        self.image = pygame.image.load(path.join(IMAGE_DIR, "boss.png")).convert_alpha()
        self.image = pygame.transform.scale(self.image, (self.width, self.height))  # 11, 10
        self.rect = self.image.get_rect()
        self.health = BOSSVESSELMAXHEALTH

    def update(self):
        self.rect.centerx = boss.rect.centerx
        self.rect.centery = boss.rect.centery + BOSSVESSELDISTANCE


class ExplosionBlue(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(path.join(IMAGE_DIR, "explosionblue.png")).convert_alpha()
        self.image = pygame.transform.scale(self.image, (45, 45))
        self.rect = self.image.get_rect()
        self.rect.x = x - 5
        self.rect.y = y - 7

        self.timer = pygame.time.get_ticks()

    def update(self, current_time):
        passed = (current_time * 1000) - self.timer
        if passed >= 200:
            self.kill()


class ExplosionGreen(ExplosionBlue):
    def __init__(self, x, y):
        super().__init__(x, y)
        self.image = pygame.image.load(path.join(IMAGE_DIR, "explosiongreen.png")).convert_alpha()
        self.image = pygame.transform.scale(self.image, (45, 45))


class ExplosionPurple(ExplosionBlue):
    def __init__(self, x, y):
        super().__init__(x, y)
        self.image = pygame.image.load(path.join(IMAGE_DIR, "explosionpurple.png")).convert_alpha()
        self.image = pygame.transform.scale(self.image, (45, 45))


class ExplosionRed(ExplosionBlue):
    def __init__(self, x, y):
        super().__init__(x, y)
        self.image = pygame.image.load(path.join(IMAGE_DIR, "explosionred.png")).convert_alpha()
        self.image = pygame.transform.scale(self.image, (45, 45))


class Laser(pygame.sprite.Sprite):
    def __init__(self, x, y, speed, colour):
        pygame.sprite.Sprite.__init__(self)
        self.width = 2
        self.height = 4
        self.image = pygame.Surface((self.width, self.height))
        self.colour = colour
        self.image.fill(self.colour)
        self.rect = self.image.get_rect()
        self.speed = speed
        self.rect.centerx = x
        self.rect.centery = y

    def update(self):
        self.rect.y -= self.speed
        if self.rect.y + (self.height / 2) <= 0 or self.rect.y - (self.height / 2) >= HEIGHT:
            self.kill()


class Mystery(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.width = 75
        self.height = 35
        self.image = pygame.image.load(path.join(IMAGE_DIR, "mystery.png")).convert_alpha()
        self.image = pygame.transform.scale(self.image, (self.width, self.height))
        self.rect = self.image.get_rect()
        self.speed = MYSTERYSPEED
        self.last_appeared = 0
        self.last_stopped = 0
        self.rect.x = MYSTERYXPOS
        self.rect.y = 25

    def update(self, level, levelstarttime, now):
        if len(mystery_group) == 1:
            self.rect.x += self.speed
            # Past lvl 3 when hit after it never returns due to speed never being reset to 5
            if not ((WIDTH / 2) - 2 <= self.rect.centerx <= (WIDTH / 2) + 2):
                self.speed = MYSTERYSPEED

        if self.rect.x >= WIDTH:
            self.last_stopped = 0
            self.kill()

        if 11 > level >= 6 and 60 >= (now - levelstarttime) >= 30:
            if self.speed == 0 and (now - self.last_stopped) >= 3 and len(mystery_group) == 1 
                    and (WIDTH / 2) - 2 <= self.rect.centerx <= (WIDTH / 2) + 2:
                generate_alien_reinforcements()
                ALIENAPPEAR.play()
                self.rect.centerx = (WIDTH / 2) + 3
                self.speed = MYSTERYSPEED
                self.last_appeared = now
                self.rect.x = (WIDTH / 2) + 6
            if self.speed != 0 and (WIDTH / 2) - 2 <= self.rect.centerx <= (WIDTH / 2) + 2:
                self.speed = 0
                self.last_stopped = now


class Powerup(pygame.sprite.Sprite):
    def __init__(self, x, y, colour):
        pygame.sprite.Sprite.__init__(self)
        self.width = 4
        self.height = 20
        self.image = pygame.Surface((self.width, self.height))
        self.colour = colour
        self.image.fill(self.colour)
        self.rect = self.image.get_rect()
        self.speed = POWERUPSPEED
        self.generated_this_level = False
        self.rect.centerx = x
        self.rect.y = y

    def update(self):
        self.rect.y += self.speed

        if self.rect.top >= HEIGHT:
            self.kill()


class Satellite(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(path.join(IMAGE_DIR, "satellite.png")).convert_alpha()
        self.image = pygame.transform.scale(self.image, (106, 40))
        self.rect = self.image.get_rect()
        self.speed = SATELLITESPEED
        self.rect.x = SATELLITEXPOS
        self.rect.y = 25
        self.powerup_generated = False
        self.last_stopped = 0
        self.stopped_this_level = False

    def update(self, now):
        self.rect.x += self.speed

        if self.rect.right <= 0:
            self.kill()

        if len(satellite_group) > 0 and self.rect.right <= WIDTH and self.rect.left >= 0 
                and not self.stopped_this_level:
            if random.randint(1, 200) == 1:
                self.last_stopped = pygame.time.get_ticks() / 1000
                self.speed = 0
                self.stopped_this_level = True

        if 2 > now - self.last_stopped > 1 and len(powerup_group) == 0:
            generate_powerup()
            POWERUPGENERATED.play()
            self.powerup_generated = True

        if now - self.last_stopped >= 3:
            self.speed = SATELLITESPEED


class Star(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface([1, 1])
        self.image.fill(WHITE)
        self.rect = self.image.get_rect()
        self.speed = STARSPEED

    def update(self):
        self.rect.y += self.speed
        if self.rect.y >= HEIGHT:
            self.rect.y = 0


# functions
def alien_drop():
    for alien in alien_master_group:
        alien.rect.y += ALIENDROP
        alien.speed *= -1


def alien_move():
    if len(boss_group) == 0:
        for alien in alien_master_group:
            alien.rect.x += alien.speed
        for alien in alien_group:
            alien.index += 1
            if alien.index >= 2:
                alien.index = 0
            alien.image = alien_images[alien.index]
        for alien in alien_backup_group:
            alien.index += 1
            if alien.index >= 2:
                alien.index = 0
            alien.image = alien_backup_images[alien.index]
        for alien in alien_elite_group:
            alien.index += 1
            if alien.index >= 2:
                alien.index = 0
            alien.image = alien_elite_images[alien.index]
    else:
        for alien in alien_master_group:
            alien.rect.x += alien.speed
        for alien in alien_group:
            alien.index += 1
            if alien.index >= 2:
                alien.index = 0
            alien.image = alien_images[alien.index]


def alien_shoot():
    if len(alien_laser_group) <= math.trunc(len(alien_group) / 10) and len(alien_group) > 0:
        alien = random.choice(list(alien_group))
        laser = Laser(alien.rect.centerx, alien.rect.centery, -LASERSPEED, BLUE)
        alien_laser_group.add(laser)

    if len(alien_laser_group) <= math.trunc(len(alien_backup_group) / 5) and len(alien_backup_group) > 0:
        alien = random.choice(list(alien_backup_group))
        laser = Laser(alien.rect.centerx, alien.rect.centery, -LASERSPEED, GREEN)
        alien_laser_group.add(laser)

    if len(alien_laser_group) <= math.trunc(len(alien_elite_group) / 2) and len(alien_elite_group) > 0:
        alien = random.choice(list(alien_elite_group))
        laser = Laser(alien.rect.centerx, alien.rect.centery, -LASERSPEED, PURPLE)
        alien_laser_group.add(laser)

    if len(alien_laser_group) <= math.trunc(len(alien_reinforcements_group) / 2) and len(
            alien_reinforcements_group) > 0:
        alien = random.choice(list(alien_reinforcements_group))
        laser = Laser(alien.rect.centerx, alien.rect.centery, -LASERSPEED, PURPLE)
        alien_laser_group.add(laser)


def bossvessel_shoot():
    if len(bossvessel_group) > 0 and bossvessel.health > 0 and len(bossvessel_laser_group) < random.randint(0, 9):
        laser = Laser(bossvessel.rect.left + (random.randint(0, 6) * 35), bossvessel.rect.y + bossvessel.height,
                      -LASERSPEED, RED)
        bossvessel_laser_group.add(laser)


def check_collisions(now, bossgrouplen):
    global time_last_hit

    for alien in alien_master_group:
        for barrier in barrier_master_group:
            if alien.rect.colliderect(barrier.rect):
                barrier.kill()

        if alien.rect.colliderect(player.rect):
            explosion_group.add(ExplosionGreen(alien.rect.x, alien.rect.y))
            explosion_group.add(ExplosionGreen(player.rect.x, player.rect.y))
            player.lives = 0
            alien.kill()
            ALIENEXPLOSIONSOUND.play()
            player.kill()

    pygame.sprite.groupcollide(alien_laser_group, barrier_master_group, True, True)
    pygame.sprite.groupcollide(bossvessel_laser_group, barrier_master_group, True, True)
    pygame.sprite.groupcollide(laser_group, barrier_master_group, True, True)

    for laser in laser_group:
        for alien in alien_group:
            if laser.rect.colliderect(alien.rect):
                explosion_group.add(ExplosionBlue(alien.rect.x, alien.rect.y))
                player.score += ALIENSCORE
                laser.kill()
                alien.kill()
                ALIENEXPLOSIONSOUND.play()
                time_last_hit = now

        for alien in alien_backup_group:
            if laser.rect.colliderect(alien.rect):
                explosion_group.add(ExplosionGreen(alien.rect.x, alien.rect.y))
                player.score += ALIENBACKUPSCORE
                laser.kill()
                alien.kill()
                ALIENEXPLOSIONSOUND.play()
                time_last_hit = now

        for alien in alien_elite_group:
            if laser.rect.colliderect(alien.rect):
                explosion_group.add(ExplosionPurple(alien.rect.x, alien.rect.y))
                player.score += ALIENELITESCORE
                laser.kill()
                alien.kill()
                ALIENEXPLOSIONSOUND.play()
                time_last_hit = now

        for alien in alien_reinforcements_group:
            if laser.rect.colliderect(alien.rect):
                explosion_group.add(ExplosionPurple(alien.rect.x, alien.rect.y))
                player.score += ALIENELITESCORE
                laser.kill()
                alien.kill()
                ALIENEXPLOSIONSOUND.play()
                time_last_hit = now

        if bossgrouplen > 0:
            if laser.rect.colliderect(boss.rect):
                laser.kill()
                time_last_hit = now

            if laser.rect.colliderect(bossvessel.rect):
                bossvessel.health -= 1
                if bossvessel.health <= 0:
                    explosion_group.add(ExplosionGreen(boss.rect.centerx, boss.rect.y))
                    boss.kill()
                    explosion_group.add(ExplosionRed(bossvessel.rect.centerx, bossvessel.rect.y))
                    bossvessel.kill()
                laser.kill()
                time_last_hit = now

        if laser.rect.colliderect(mystery.rect):
            explosion_group.add(ExplosionRed(mystery.rect.centerx, mystery.rect.y))
            player.score += MYSTERYSCORE
            mystery.rect.x = MYSTERYXPOS
            laser.kill()
            mystery.kill()
            MYSTERYEXPLOSION.play()
            time_last_hit = now

        if laser.rect.colliderect(satellite.rect):
            explosion_group.add(ExplosionBlue(satellite.rect.centerx, satellite.rect.y))
            satellite.rect.x = SATELLITEXPOS
            laser.kill()
            satellite.kill()
            SATELLITEEXPLOSION.play()
            time_last_hit = now

    for laser in alien_laser_group:
        hits = pygame.sprite.spritecollide(laser, player_group, False, pygame.sprite.collide_circle)
        for hit in hits:
            player_hit()
            laser.kill()
            time_last_hit = now
            if player.lives == 0:
                explosion_group.add(ExplosionGreen(player.rect.x, player.rect.y))
                player.kill()

    for laser in bossvessel_laser_group:
        hits = pygame.sprite.spritecollide(laser, player_group, False, pygame.sprite.collide_circle)
        for hit in hits:
            player_hit()
            laser.kill()
            time_last_hit = now
            if player.lives == 0:
                explosion_group.add(ExplosionGreen(player.rect.x, player.rect.y))
                player.kill()

    for powerup in powerup_group:
        if powerup.rect.colliderect(player.rect):
            powerup.kill()
            POWERUPPICKEDUP.play()
            if player.lives < 5:
                randnumber = random.randint(1, 3)
                if randnumber == 1:
                    player.double_shot = True
                elif randnumber == 2:
                    num = random.randint(0, 3)
                    generate_barrier(num, num + 1)
                else:
                    player.lives += 1
            elif player.lives == 5:
                randnumber = random.randint(1, 2)
                if randnumber == 1:
                    player.double_shot = True
                else:
                    num = random.randint(0, 3)
                    generate_barrier(num, num + 1)


def draw_boss_health_bar(screen):
    pygame.draw.rect(screen, RED, pygame.Rect(5, HEIGHT - 10, WIDTH - 10, 10), 2)

    pygame.draw.rect(screen, RED,
                     pygame.Rect(5, HEIGHT - 10, (WIDTH - 10) * (bossvessel.health / BOSSVESSELMAXHEALTH), 10))


def draw_lives(surf, x, y, lives, img):
    for i in range(lives):
        img_rect = img.get_rect()
        img_rect.x = x + 30 * i
        img_rect.y = y
        surf.blit(img, img_rect)


def draw_text(surf, font, size, text, colour, x, y, location):
    font = pygame.font.Font(font, size)
    text_surface = font.render(text, True, colour)
    text_rect = text_surface.get_rect()
    if location == 'center':
        text_rect.center = (x, y)
    elif location == 'left':
        text_rect.midleft = (x, y)
    surf.blit(text_surface, text_rect)


def generate_barrier(num1, num2):
    for i in range(num1, num2):
        for x in range(20):
            for y in range(10):
                barrier = Barrier(50 + (x * 5) + (200 * i), 525 - (y * 5))
                barrier_master_group.add(barrier)


def generate_aliens_lvl1():
    for x in range(10):
        for y in range(2):
            alien = Alien()
            alien.rect.x = 50 + (x * 50)
            alien.rect.y = ALIENSTARTYPOS + (y * 45)
            alien_group.add(alien)
            alien_master_group.add(alien)


def generate_aliens_lvl2():
    for x in range(10):
        for y in range(4):
            if y in (0, 1):
                alien = AlienBackup()
                alien.rect.x = 50 + (x * 50)
                alien.rect.y = ALIENSTARTYPOS + (y * 45)
                alien_backup_group.add(alien)
                alien_master_group.add(alien)
            elif y in (2, 3):
                alien = Alien()
                alien.rect.x = 50 + (x * 50)
                alien.rect.y = ALIENSTARTYPOS + (y * 45)
                alien_group.add(alien)
                alien_master_group.add(alien)


def generate_aliens_lvl3():
    for x in range(10):
        for y in range(5):
            if y == 0:
                alien = AlienElite()
                alien.rect.x = 50 + (x * 50)
                alien.rect.y = ALIENSTARTYPOS + (y * 45)
                alien_elite_group.add(alien)
                alien_master_group.add(alien)
            elif y in (1, 2):
                alien = AlienBackup()
                alien.rect.x = 50 + (x * 50)
                alien.rect.y = ALIENSTARTYPOS + (y * 45)
                alien_backup_group.add(alien)
                alien_master_group.add(alien)
            elif y in (3, 4):
                alien = Alien()
                alien.rect.x = 50 + (x * 50)
                alien.rect.y = ALIENSTARTYPOS + (y * 45)
                alien_group.add(alien)
                alien_master_group.add(alien)


def generate_alien_reinforcements():
    for x in range(5):
        alien = AlienElite()
        alien.rect.x = ((WIDTH / 2) - 120) + (x * 50)
        alien.rect.y = ALIENSTARTYPOS
        alien_reinforcements_group.add(alien)
        alien_master_group.add(alien)


def generate_boss():
    boss.rect.centerx = WIDTH / 2
    boss.rect.y = ALIENSTARTYPOS
    alien_group.add(boss)
    alien_master_group.add(boss)
    boss_group.add(boss)


def generate_boss_vessel():
    bossvessel.rect.centerx = boss.rect.centerx
    bossvessel.rect.centery = boss.rect.centery + BOSSVESSELDISTANCE
    bossvessel_group.add(bossvessel)


def generate_mystery():
    mystery.rect.x = MYSTERYXPOS
    mystery_group.add(mystery)
    mystery.last_appeared = pygame.time.get_ticks() / 1000


def generate_powerup():
    powerup = Powerup(satellite.rect.centerx, satellite.rect.centery, ORANGE)
    if powerup.generated_this_level is False:
        powerup.generated_this_level = True
        powerup_group.add(powerup)


def generate_satellite():
    satellite.rect.x = SATELLITEXPOS
    satellite_group.add(satellite)


def generate_stars():
    for i in range(random.randint(80, 120)):
        x = random.randint(1, WIDTH - 1)
        y = random.randint(1, HEIGHT - 1)
        star = Star()
        star.rect.x = x
        star.rect.y = y

        star_group.add(star)


def intermission_screen(screen, image_name, image_scale_x, image_scale_y, screen_pos_x, screen_pos_y,
                        text, text_pos_x, text_pos_y, text_loc):
    load_screen_image = pygame.image.load(path.join(IMAGE_DIR, image_name)).convert_alpha()
    image = pygame.transform.scale(load_screen_image, (image_scale_x, image_scale_y))
    screen.blit(image, (screen_pos_x, screen_pos_y))
    draw_text(screen, FONT, 52, text, WHITE, text_pos_x, text_pos_y, text_loc)


def pauze_background_music():
    pygame.mixer.music.pause()


def play_background_music():
    if random.randint(1, 2) == 1:
        pygame.mixer.music.load(BACKGROUND1)
    else:
        pygame.mixer.music.load(BACKGROUND2)
    pygame.mixer.music.set_volume(MUSICVOLUME)
    pygame.mixer.music.play(-1)


def player_hit():
    player.lives -= 1
    PLAYERHIT.play()


def unpauze_background_music():
    pygame.mixer.music.unpause()


# miscellaneous
player = Player()
player_group.add(player)

boss = Boss()
bossvessel = Bossvessel()
mystery = Mystery()
satellite = Satellite()


class SpaceInvaders(object):
    def __init__(self):
        pygame.init()
        self.clock = pygame.time.Clock()
        self.fps = self.clock.get_fps()
        self.screen = SCREEN
        self.now = pygame.time.get_ticks() / 1000
        self.levelstarttime = 0
        self.level = 1

        self.menu()

    def game_over(self, endgame):
        pygame.mixer.music.stop()
        if endgame == 0:
            endgametext = "GAME OVER"
            endgamecolour = RED
        else:
            endgametext = "VICTORY"
            endgamecolour = GREEN

        pygame.time.wait(2000)
        draw_text(self.screen, FONT, 64, endgametext, endgamecolour, WIDTH / 2, HEIGHT / 2, 'center')
        GAMEOVER.play()
        pygame.display.update()

        pygame.time.wait(2000)
        draw_text(self.screen, FONT, 32, "Press space bar to restart", WHITE, WIDTH / 2, (HEIGHT / 2) + 50, 'center')
        draw_text(self.screen, FONT, 32, "or press escape to quit", WHITE, WIDTH / 2, (HEIGHT / 2) + 100, 'center')
        pygame.display.update()

        pygame.time.wait(2000)
        SCREEN.fill(BLACK)
        draw_text(self.screen, FONT, 64, endgametext, endgamecolour, WIDTH / 2, HEIGHT / 2, 'center')
        draw_text(self.screen, FONT, 32, "Press space bar to restart", WHITE, WIDTH / 2, (HEIGHT / 2) + 50, 'center')
        draw_text(self.screen, FONT, 32, "or press escape to quit", WHITE, WIDTH / 2, (HEIGHT / 2) + 100, 'center')
        pygame.display.update()

        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_SPACE:
                        self.level = 1
                        self.new_game()
                    if event.key == pygame.K_ESCAPE:
                        pygame.quit()
                        sys.exit()

    def intermission(self):
        pauze_background_music()
        pygame.time.wait(2000)
        self.screen.fill(BLACK)

        if 11 > self.level >= 1:
            intermission_screen(self.screen, "ship.png", 45, 45, 50, (HEIGHT * 0.25) + 50,
                                '= Player', 100, (HEIGHT * 0.25) + 75, 'left')

            intermission_screen(self.screen, "enemy2_1.png", 45, 45, (WIDTH / 2) + 50, (HEIGHT * 0.25) + 50,
                                '= ' + str(ALIENSCORE) + ' points', (WIDTH / 2) + 100, (HEIGHT * 0.25) + 75, 'left')

        if 11 > self.level >= 2:
            intermission_screen(self.screen, "enemy3_2.png", 45, 45, 50, (HEIGHT * 0.25) + 150,
                                '= ' + str(ALIENBACKUPSCORE) + ' points', 100, (HEIGHT * 0.25) + 175, 'left')

        if 11 > self.level >= 3:
            intermission_screen(self.screen, "enemy1_1.png", 45, 45, (WIDTH / 2) + 50, (HEIGHT * 0.25) + 150
                                , '= ' + str(ALIENELITESCORE) + ' points', (WIDTH / 2) + 100, (HEIGHT * 0.25) + 175, 'left')

        if 11 > self.level >= 4:
            intermission_screen(self.screen, "mystery.png", 75, 35, 35, (HEIGHT * 0.25) + 250,
                                '= ' + str(MYSTERYSCORE) + ' points', 110, (HEIGHT * 0.25) + 275, 'left')

        if 11 > self.level >= 5:
            intermission_screen(self.screen, "satellite.png", 106, 40, (WIDTH / 2) + 20, (HEIGHT * 0.25) + 250
                                , "= don't shoot", (WIDTH / 2) + 125, (HEIGHT * 0.25) + 275, 'left')

            intermission_screen(self.screen, "powerup.png", 8, 40, (WIDTH / 2) + 75, (HEIGHT * 0.25) + 350
                                , "= powerup", (WIDTH / 2) + 100, (HEIGHT * 0.25) + 375, 'left')

        if self.level == 6:
            draw_text(self.screen, FONT, 52, 'Watch out for reinforcements', RED, WIDTH / 2, 50, 'center')

        if self.level <= 10:
            draw_text(self.screen, FONT, 52, 'level ' + str(int(self.level)), GREEN, WIDTH / 2, (HEIGHT * 0.25), 'center')
        elif self.level == 11:
            draw_text(self.screen, FONT, 52, 'FINAL BOSS', RED, WIDTH / 2, (HEIGHT / 2), 'center')

        pygame.display.update()
        pygame.time.wait(3000)
        unpauze_background_music()

    def menu(self):

        generate_stars()

        while True:

            button = pygame.Rect((WIDTH / 2) - 100, (HEIGHT / 2), 200, 100)

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                if event.type == pygame.MOUSEBUTTONDOWN:
                    if event.button == 1:
                        if button.collidepoint(event.pos):
                            pygame.time.wait(2000)
                            self.intermission()
                            self.new_game()
                if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                    self.intermission()
                    self.new_game()

            keys = pygame.key.get_pressed()

            self.screen.fill(BLACK)

            pygame.draw.rect(self.screen, BLACK, button)

            star_group.update()
            star_group.draw(self.screen)

            draw_text(self.screen, STARTFONT, 64, 'START', WHITE, button.centerx, button.centery, 'center')

            draw_text(self.screen, LOGOFONT, 80, 'SPACE INVADERS', GREEN, WIDTH / 2, (HEIGHT / 2) - 100, 'center')

            draw_text(self.screen, FONT, 25, 'Or press SPACE to start the game', WHITE, WIDTH / 2,
                      (HEIGHT - 100), 'center')

            draw_text(self.screen, FONT, 25, 'Use arrow keys to move and space bar to shoot', WHITE, WIDTH / 2,
                      (HEIGHT - 50), 'center')

            pygame.display.flip()
            self.clock.tick(FPS)

    def new_game(self):
        global alien_group
        alien_group = pygame.sprite.Group()
        global alien_backup_group
        alien_backup_group = pygame.sprite.Group()
        global alien_elite_group
        alien_elite_group = pygame.sprite.Group()
        global alien_master_group
        alien_master_group = pygame.sprite.Group()
        global alien_reinforcements_group
        alien_reinforcements_group = pygame.sprite.Group()
        global alien_laser_group
        alien_laser_group = pygame.sprite.Group()
        global boss_group
        boss_group = pygame.sprite.Group()
        global bossvessel_group
        bossvessel_group = pygame.sprite.Group()
        global explosion_group
        explosion_group = pygame.sprite.Group()
        global laser_group
        laser_group = pygame.sprite.Group()
        global mystery_group
        mystery_group = pygame.sprite.Group()
        global powerup_group
        powerup_group = pygame.sprite.Group()
        global satellite_group
        satellite_group = pygame.sprite.Group()

        if self.level == 1:
            global barrier_master_group
            barrier_master_group = pygame.sprite.Group()
            global player_group
            player_group = pygame.sprite.Group()
            global star_group
            star_group = pygame.sprite.Group()
            global player
            player = Player()
            player_group.add(player)
            player.lives = 5
            player.score = 0

            generate_aliens_lvl1()

        elif self.level == 2:
            generate_aliens_lvl2()
        elif 11 > self.level >= 3:
            generate_aliens_lvl3()

        if self.level <= 3:
            generate_barrier(0, 4)

        if self.level == 11:
            generate_boss()
            generate_boss_vessel()

        generate_stars()

        play_background_music()

        mystery.last_appeared = pygame.time.get_ticks() / 1000
        satellite.appeared_this_level = False

        self.game_loop()

    def game_start(self):
        self.menu()

    def game_loop(self):
        while True:

            self.now = (pygame.time.get_ticks() / 1000)

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.K_SPACE and player.lives == 0:
                    SpaceInvaders()

            global should_aliens_drop
            should_aliens_drop = False

            global should_aliens_move
            should_aliens_move = False

            keys = pygame.key.get_pressed()

            if keys[pygame.K_SPACE]:
                if player.lives > 0:
                    if self.now - player.last_shot >= player.cool_down and not player.double_shot:
                        player.last_shot = self.now
                        laser = Laser(player.rect.centerx, player.rect.y, LASERSPEED, GREEN)
                        laser_group.add(laser)
                        LASERSOUND.play()
                    if self.now - player.last_shot >= player.cool_down and player.double_shot:
                        player.last_shot = self.now
                        laser = Laser(player.rect.centerx - 15, player.rect.y + 20, LASERSPEED, GREEN)
                        laser_group.add(laser)
                        laser = Laser(player.rect.centerx + 15, player.rect.y + 20, LASERSPEED, GREEN)
                        laser_group.add(laser)
                        LASERSOUND.play(1)

            self.screen.fill(BLACK)

            star_group.update()
            star_group.draw(self.screen)

            alien_master_group.update(self.now)
            alien_master_group.draw(self.screen)

            if should_aliens_drop:
                alien_drop()
                should_aliens_drop = False

            if should_aliens_move:
                alien_move()
                should_aliens_move = False

            alien_laser_group.update()
            alien_laser_group.draw(self.screen)

            barrier_master_group.update(keys)
            barrier_master_group.draw(self.screen)

            bossvessel_group.update(keys)
            bossvessel_group.draw(self.screen)

            bossvessel_laser_group.update(keys)
            bossvessel_laser_group.draw(self.screen)

            if self.level >= 10 and len(boss_group) == 1:
                draw_boss_health_bar(self.screen)

            explosion_group.update(self.now)
            explosion_group.draw(self.screen)

            laser_group.update()
            laser_group.draw(self.screen)

            mystery_group.update(self.level, self.levelstarttime, self.now)
            mystery_group.draw(self.screen)

            if self.level >= 4 and len(mystery_group) == 0 and (self.now - mystery.last_appeared) >= MYSTERYTIME:
                generate_mystery()

            player_group.update(keys)
            player_group.draw(self.screen)

            powerup_group.update(keys)
            powerup_group.draw(self.screen)

            satellite_group.update(self.now)
            satellite_group.draw(self.screen)

            if self.level >= 5 and len(satellite_group) == 0 and random.randint(1, 750) == 1 
                    and not satellite.powerup_generated:
                generate_satellite()
                SATELLITEANNOUNCE.play()

            check_collisions(self.now, len(boss_group))

            # print(len(bossvessel_group))

            draw_text(self.screen, FONT, 32, 'FPS ' + str(int(self.clock.get_fps())), WHITE, WIDTH - 60, 14, 'center')

            draw_text(self.screen, FONT, 32, 'SCORE ' + str(int(player.score)), WHITE, WIDTH / 2, 14, 'center')

            draw_lives(self.screen, 10, 5, player.lives, pygame.transform.scale(player.image, (18, 18)))

            if player.lives == 0 and self.now - time_last_hit >= 2:
                self.game_over(len(player_group))
            if len(alien_master_group) == 0 and self.now - time_last_hit >= 2:
                satellite.stopped_this_level = False
                self.level += 1
                self.levelstarttime = self.now
                player.double_shot = False
                self.intermission()
                self.new_game()

            if len(boss_group) == 0:
                alien_shoot()
            else:
                bossvessel_shoot()

            pygame.display.flip()
            self.clock.tick(FPS)


if __name__ == '__main__':
    # Make a game instance, and run the game.
    game = SpaceInvaders()
    # game.game_loop()
    game.menu()

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *