Python Forum
Pygmae big problems with gamescore and fps
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Pygmae big problems with gamescore and fps
#1
Hey im very new to python and programming at this moment space invaders(my first project)

I have made it in star wars theme with little death stars that shoot a long laser beam. My problem is that my game runs sooooo super slow. I think its bcause this laserbeam. Because i dont have one sprizte for that i just start the timer and let him 3 sec shoot (looks perfectly like a laserbeam). And if i put in just a long lder pic that looks ugly af. Did anybody have a idea how i can make this better? I post you the code in the bottom. Thanks for answers.


Ah and the second problem is that if i shoot the NormalEnemy-Sprites the game_score equivalent like before. I dont know why. The other code in the function is running perfectly just the game_score stays the same. The same problem comes out when im in level_three_window(level two at this moment)
when the Score is at 450 and the tie-fighter pop up the counter stays the same and continue running just when the tie fighters flght away...



I will mak you some Videos so you can understand it better. ( If you want me to send you athe images and sounds then tell me)




Here is the Full Code:




#MotherClasses
import math
import random

import pygame
from pygame import mixer


class Window(pygame.sprite.Sprite):
    def __init__(self, caption, image, window_open):
        super().__init__()
        self.width = 800
        self.height = 600
        self.change_y_screen_image = 0
        self.caption = caption
        pygame.display.set_caption(caption)
        self.screen = pygame.display.set_mode((self.width, self.height))

        self.window_open = window_open

        self.image = pygame.image.load(image).convert()
        self.image = pygame.transform.scale(self.image, (self.width, self.height))

        self.group = pygame.sprite.Group()
        self.back_button = BackButton()
        self.spaceship_group = pygame.sprite.Group()

        self.xwing = XWing()
        self.tiefighter = TFighterBG()

        self.spaceship_group.add(self.xwing)
        self.spaceship_group.add(self.tiefighter)

    def print_headline(self, pos):
        orange = (255, 165, 0)
        menu_font = pygame.font.Font("Starjedi.ttf", 55)
        menu_font = menu_font.render(self.caption, True, orange)
        self.screen.blit(menu_font, pos)

    def draw(self, m_pos):
        self.screen.blit(self.image, (0, 0))
        for sprite in self.group.sprites():
            sprite.draw(m_pos, self.screen)
        self.group.draw(self.screen)
        self.spaceship_group.draw(self.screen)

    def update(self, m_pos, current_time, lvl_window, hs_window, menu_window, game_window, level_three_window, setting_window):
        for sprite in self.spaceship_group.sprites():
            sprite.update(current_time)
        self.back_button.update(m_pos, menu_window, game_window, level_three_window)
        if self.back_button.action:
            menu_window.window_open = True
            self.window_open = False
            self.back_button.action = False

    def change_screen_boolians(self, clicked_window, clicked_button):
        clicked_window.window_open = True
        clicked_button.action = False
        return False


class BackGroundSpaceships(pygame.sprite.Sprite):
    def __init__(self, x, y, image, spaceship_size_x, spaceship_size_y, flight_count, speedx, speedy):
        super().__init__()
        self.x = x
        self.y = y
        self.image = pygame.image.load(image)
        self.spaceship_size_x = spaceship_size_x
        self.spaceship_size_y = spaceship_size_y
        self.image = pygame.transform.scale(self.image, (spaceship_size_x, spaceship_size_y))
        self.rect = self.image.get_rect(center=[self.x, self.y])
        self.last_count = pygame.time.get_ticks()
        self.flight_count = flight_count
        self.speedx = speedx
        self.speedy = speedy

    def move(self):
        self.rect.x += self.speedx
        self.rect.y += self.speedy

    def update(self, current_time):
        if current_time - self.last_count > self.flight_count and self.rect.x <= 1000:
            self.move()
        if self.rect.x <= -200:
            self.last_count = current_time
            self.rect.x = 950

    def draw(self, m_pos, surface):
        pass


class TFighterBG(BackGroundSpaceships):
    def __init__(self):
        x = 1000
        y = 200
        image = "t_fighter_menu.png"
        spaceship_size_x = 64
        spaceship_size_y = 64
        flight_count = 6000
        speedx = -5
        speedy = 2
        super().__init__(x, y, image, spaceship_size_x, spaceship_size_y, flight_count, speedx, speedy)


class XWing(BackGroundSpaceships):
    def __init__(self):
        x = 600
        y = 800
        image = "battleship.png"
        spaceship_size_x = 64
        spaceship_size_y = 64
        flight_count = 3000
        speedx = -2
        speedy = -5
        super().__init__(x, y, image, spaceship_size_x, spaceship_size_y, flight_count, speedx, speedy)
        self.image = pygame.transform.rotate(self.image, 15)


class Buttons(pygame.sprite.Sprite):
    def __init__(self, x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey, text, plus_vecx, plus_vecy):
        super().__init__()
        self.x = x
        self.y = y
        self.image = pygame.image.load(image)
        self.image = pygame.transform.scale(self.image, (extra_image_sizex, extra_image_sizey))
        self.rect = self.image.get_rect()
        self.rect.center = [x, y]
        self.bg_image = pygame.image.load(bg_image)
        self.bg_image = pygame.transform.scale(self.bg_image, (bgimage_sizex, bgimage_sizey))
        self.star_wars_color = (255, 165, 1)
        self.clicked = False
        self.action = False
        self.text = text
        self.plus_vecx = plus_vecx
        self.plus_vecy = plus_vecy

    def draw(self, m_pos, surface):
        if self.rect.collidepoint(m_pos):
            surface.blit(self.bg_image, (self.rect.x + self.plus_vecx, self.rect.y + self.plus_vecy))

    def update(self, m_pos, menu_window, game_window, level_three_window, empty_groups=None,
               group_l=None, explosion_group=None, extra_posx=0, extra_posy=0):
        sound = mixer.Sound('sounds/button_click_ogg.ogg')
        if self.rect.collidepoint(m_pos) and pygame.mouse.get_pressed()[0] == 1 and not self.clicked:
            sound.play()
            self.clicked = True
            self.action = True
        if pygame.mouse.get_pressed()[0] == 0:
            self.clicked = False
        return self.action

    def draw_text(self, surface, size, x, y, text):
        grey = (105, 105, 105)
        font = pygame.font.Font("Starjedi.ttf", size)
        text = font.render(str(text), True, grey)
        surface.blit(text, (x, y))


########################################################################################################################
# Game Mother Classes
class StaticObjects(pygame.sprite.Sprite):
    def __init__(self, image, x, y):
        super().__init__()
        self.x = x
        self.y = y
        self.image = pygame.image.load(image)
        self.rect = self.image.get_rect()
        self.rect.center = [x, y]
        self.show_shield = False

    def update(self, player):
        pass

    def check_click(self):
        pass

    def draw(self, current_time, player, print_counter, surface):
        pass


class PowerUp(pygame.sprite.Sprite):
    def __init__(self, image, x, y):
        super().__init__()
        self.x = x
        self.y = y
        self.speed = 5
        self.image = pygame.image.load(image)
        self.rect = self.image.get_rect()
        self.rect.center = [x, y]
        self.last_powerup = pygame.time.get_ticks()

    def check_collision(self, player, heart_g):
        if self.rect.colliderect(player.rect):
            self.apply(player, heart_g)
            self.kill()

    def apply(self, player, heart_gr):
        pass

    def move(self):
        self.rect.y += self.speed
        if self.rect.y >= 600:
            self.kill()

    def update(self, player, heart_g, current_time, powerup_group):
        self.move()
        self.check_collision(player, heart_g)





class Spaceships(pygame.sprite.Sprite):
    def __init__(self, image, speed, lives, shoot_count, x, y, cooldown, direction, sound, speed_y, image_size_x=64, image_size_y=64):
        super().__init__()
        self.x = x
        self.y = y
        self.speed = speed
        self.speed_y = speed_y
        self.image = pygame.image.load(image)
        self.image = pygame.transform.scale(self.image, (image_size_x, image_size_y))
        self.rect = self.image.get_rect(center=[x, y])
        self.lives = lives
        self.last_shot = pygame.time.get_ticks()
        self.shoot_count = shoot_count
        self.cooldown = cooldown
        self.mask = pygame.mask.from_surface(self.image)
        self.direction = direction
        self.sound = sound
        self.lives_index = 0

    def draw(self, surface, print_counter):
        pass

    def shoot(self, current_time, h_group, bullet_group, volume):
        if current_time - self.last_shot > self.shoot_count and len(h_group) > 0:
            shooting_sound = mixer.Sound(f'sounds/{self.sound}').play()
            shooting_sound.set_volume(volume)
            bullet = Bullet(self.rect.centerx, self.rect.bottom, "death_star_laser1.png", math.pi/2, 10, 0)
            bullet_group.add(bullet)
            if current_time - self.last_shot > self.cooldown:
                self.last_shot = current_time

    def move_y(self, speed):
        self.rect.y = min(max(self.rect.y, 0), 536)
        self.rect.y += speed

    def move_x(self, speed):
        self.rect.x = min(max(self.rect.x, 0), 736)
        self.rect.x += speed

    def move(self, func, spaceship, surface, explosion_group, group):
        self.move_x(self.speed)
        if self.rect.x >= 736 or self.rect.x <= 0:
            self.speed = -self.speed
            self.rect.y += self.speed_y
        if self.rect.y >= 600:
            func()
            spaceship.dead = True

    def update(self, surface, volume, current_time, func, h_group, game_score, explosion_group, group, bullet_group, enemy_bullet_group, spaceship):
        game_score = self.check_collision(h_group, game_score, spaceship, explosion_group, enemy_bullet_group, group)
        self.shoot(current_time, h_group, bullet_group, volume)
        self.move(func, spaceship, surface, explosion_group, group)
        return game_score

    def check_collision(self, h_group, game_score, player, explosion_group, enemy_bullet_group, group):
        game_score = game_score
        explosion = Explosion(self.rect.centerx, self.rect.centery, 1)
        if pygame.sprite.collide_mask(self, player):
            explosion_group.add(explosion)
            if not player.shield_bool and len(h_group) > 0:
                h_group.sprites()[-1].kill()
                player.lives -= 1
            self.kill()
        for bullet in enemy_bullet_group.sprites():
            if pygame.sprite.collide_mask(self, bullet):
                self.lives_index += 1
                explosion_small = Explosion(bullet.rect.centerx, bullet.rect.centery, 1)
                explosion_group.add(explosion_small)
                bullet.kill()
                game_score += 1
                self.lives -= 1
                if self.lives == 0:
                    self.check_live()
        return game_score

    def check_live(self):
        self.rect.x = random.randint(0, 736)
        self.rect.y = random.randint(-130, -60)
        self.lives += self.lives_index
        self.lives_index = 0


class BackButton(Buttons):
    def __init__(self):
        x = 40
        y = 40
        image = "previous.png"
        extra_image_sizex = 32
        extra_image_sizey = 32
        bg_image = "previou_green.png"
        bgimage_sizex = 32
        bgimage_sizey = 32
        text = ''
        plus_vecx = 0
        plus_vecy = 0
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class Bullet(pygame.sprite.Sprite):  # 13
    def __init__(self, x, y, image, direction, speed=-10, angle=60):
        super().__init__()
        self.x = x
        self.y = y
        self.speed = speed
        self.image = pygame.image.load(image)

        self.rect = self.image.get_rect()
        self.rect.center = [x, y]

        self.mask = pygame.mask.from_surface(self.image)
        self.angle = angle
        self.direction = direction
        self.image = pygame.transform.rotate(self.image, self.angle)

        self.bullet_transform = 7
        self.beam_lengh = 0
        self.beam = False

    def update(self):  # 14
        new_x = self.rect.x + (self.speed * math.cos(self.direction))
        new_y = self.rect.y + (self.speed * math.sin(self.direction))
        self.rect.x = new_x
        self.rect.y = new_y
        if self.rect.bottom < 0 or self.rect.bottom > 1000 or self.rect.x > 800 or self.rect.x < -30:
            self.kill()

    def update_laser_beam(self, enemy, x_transform, extry_x, extra_y):
        if self.rect.bottom < 600:
            self.beam_lengh += self.bullet_transform
            self.image = pygame.transform.scale(self.image, (x_transform, self.beam_lengh))
            self.rect = self.image.get_rect()
            self.rect.y = enemy.rect.bottom + extra_y
        if self.rect.bottom >= 600:
            self.rect.y += 30
            self.bullet_transform = -1
            if self.rect.top > 600:
                self.beam = False
        self.rect.x = enemy.rect.centerx + extry_x


class Explosion(pygame.sprite.Sprite):
    def __init__(self, x, y, size):
        pygame.sprite.Sprite.__init__(self)
        self.x = x
        self.y = y
        self.images = []
        for i in range(1, 6):
            self.img = pygame.image.load(f"exp/exp{i}.png")
            if size == 1:
                self.img = pygame.transform.scale(self.img, (50, 50))  # alle Bilder auf die gleihe Größe skallieren
            elif size == 2:
                self.img = pygame.transform.scale(self.img, (100, 100))
            elif size == 3:
                self.img = pygame.transform.scale(self.img, (1000, 1000))
            self.images.append(self.img)
        self.index = 0  # zeigt das momentane Bild
        self.image = self.images[self.index]
        self.rect = self.image.get_rect()
        self.rect.center = [x, y]
        self.counter = 0
        self.sound = ''

    def update(self):
        explosion_speed = 4  # wird für die länge des anzeigens eines Bildes verwendet
        self.counter += 1
        if self.counter >= explosion_speed and self.index < len(self.images) - 1:
            self.counter = 0
            self.index += 1
            self.image = self.images[self.index]
        if self.index >= len(self.images) - 1 and self.counter >= explosion_speed:
            self.kill()
# Gmae(level1) Classes


import math
import random
import pygame
from pygame import mixer

from MotherClasses import Window, Spaceships, PowerUp, Buttons, StaticObjects, Bullet, Explosion


class GameWindow(Window):
    def __init__(self, caption, image):
        window_open = False
        super().__init__(caption, image, window_open)

        self.score = 0

        self.player_spaceship = PlayerSpaceship(400, 515)
        self.name_field = Name()
        self.pause = Pause()

        self.group_names = ['enemy_group',
                            'heart_group',
                            'powerup_group',
                            'explosion_group',
                            'player_bullet_group',
                            'enemy_bullet_group',
                            'player_group']

        for name in self.group_names:
            setattr(self, name, pygame.sprite.Group())

        self.volume = 100

        self.button_group = pygame.sprite.Group(self.pause)
        self.name_group = pygame.sprite.Group(self.name_field)

        self.last_powerup = pygame.time.get_ticks()
        self.change_y_screen_image = 0

        self.index = 1
        self.more_enemies = True
        self.more_enemies_at_score_points = 50

        # pause Attributes
        self.back_to_meu_button = BackToMenu()
        self.continue_button = Continue()
        self.back_group = pygame.sprite.Group(self.back_to_meu_button)
        self.pause_button_group = pygame.sprite.Group(self.back_to_meu_button,
                                                      self.continue_button)

        # lists
        self.bullet_group_list = [self.player_bullet_group,
                                  self.enemy_bullet_group]

        self.button_group_list = [self.button_group,
                                  self.name_group]

        self.group_list = [self.enemy_group,
                           self.heart_group,
                           self.powerup_group,
                           self.explosion_group,
                           self.player_bullet_group,
                           self.enemy_bullet_group,
                           self.player_group]

        with (open('high_score', 'r')) as file:
            self.high_score = int(file.readline(4))

    def update(self, m_pos, current_time, lvl_window, hs_window, menu_window, game_window, level_three_window,
               setting_window):
        self.spaceship_params = [self.screen,
                                 setting_window.volume_button.volume,
                                 current_time,
                                 self.empty_all_groups,
                                 self.heart_group,
                                 self.score,
                                 self.explosion_group,
                                 self.enemy_group]

        if not self.name_field.action:
            for group in self.button_group_list:  # update name-field before start game
                for sprite in group:
                    sprite.update(m_pos, menu_window, self, level_three_window, self.empty_all_groups, self.group_list,
                                  self.explosion_group)
        elif self.pause.action:
            self.pause_button_group.update(m_pos, menu_window, game_window, level_three_window, self.empty_all_groups,
                                           self.group_list,
                                           self.explosion_group)

        else:
            if not self.player_spaceship.dead:
                self.pause.update(m_pos, menu_window, self, level_three_window)
            else:
                self.back_group.update(m_pos, menu_window, game_window, level_three_window, self.empty_all_groups,
                                       self.group_list,
                                       self.explosion_group)

            for sprite in self.enemy_group.sprites():
                self.score = sprite.update(*self.spaceship_params,
                                           self.enemy_bullet_group,
                                           self.player_bullet_group,
                                           self.player_spaceship)


            self.player_spaceship.update(*self.spaceship_params,
                                         self.player_bullet_group,
                                         self.enemy_bullet_group,
                                         self.enemy_group)

            for bullet_group in self.bullet_group_list:
                bullet_group.update()

            if len(self.explosion_group) > 0:
                self.explosion_group.update()

            if len(self.powerup_group) > 0:
                self.powerup_group.update(self.player_spaceship,
                                      self.heart_group,
                                      current_time,
                                      self.powerup_group)
            if self.player_spaceship.lives <= 1:
                self.check_lives_and_enemy_position(self.score,
                                                    self.player_spaceship,
                                                    self.enemy_group,
                                                    self.group_list,
                                                    self.screen,
                                                    self.empty_all_groups,
                                                    self.print_game_over,
                                                    self.explosion_group,
                                                    self.group,
                                                    self.back_group,
                                                    m_pos)

            self.initialize_powerup(current_time,
                                    self.heart_group,
                                    self.powerup_group)

        #    if self.score >= self.more_enemies_at_score_points:
        #        self.add_enemies(self.enemy_group)
        #        self.more_enemies_at_score_points += 50

    def draw(self, m_pos):
        super().draw(m_pos)

        self.change_y_screen_image = self.seamless_background(self.change_y_screen_image,
                                                              self.image,
                                                              self.height,
                                                              self.screen)
        if not self.name_field.action:
            self.name_group.draw(self.screen)
            self.name_field.draw(m_pos, self.screen)

        elif self.pause.action:
            self.pause_button_group.draw(self.screen)

            for sprite in self.pause_button_group.sprites():
                sprite.draw(m_pos, self.screen)
        else:
            for group in self.group_list:
                group.draw(self.screen)

            if not self.player_spaceship.dead:
                self.pause.draw(m_pos, self.screen)
                self.button_group.draw(self.screen)
            else:
                self.back_group.draw(self.screen)
                for sprite in self.back_group.sprites():
                    sprite.draw(m_pos, self.screen)

            for sprite in self.enemy_group.sprites():
                sprite.draw(self.screen,
                            self.print_newhs_score_counter)

            for bullet_group in self.bullet_group_list:
                bullet_group.draw(self.screen)

            self.player_group.draw(self.screen)

            self.player_spaceship.draw(self.screen,
                                       self.print_newhs_score_counter)

            self.print_newhs_score_counter(
                "freesansbold.ttf",
                16,
                f"Punkte: {str(self.score)}",
                (155, 200, 255),
                (8, 8),
                self.screen,
            )

            if self.score > int(self.high_score):
                self.print_newhs_score_counter('Starjedi.ttf',
                                               10,
                                               'New Record!',
                                               (255, 134, 31),
                                               (8, 20),
                                               self.screen)

    def empty_all_groups(self, group_l, explosion_group):
        for group in group_l:
            if group != explosion_group:
                group.empty()

    def seamless_background(self, change_screen, image, screen_height, surface):
        change_screen += 1
        surface.blit(image, (0, change_screen))
        if change_screen >= screen_height:
            return 0
        if change_screen > 0:
            surface.blit(image, (0, 0 - screen_height + change_screen))
            return change_screen

    def initialize_powerup(self, current_time, heart_g, powerup_group):
        power_up_counter = 3000
        if current_time - self.last_powerup > power_up_counter and len(heart_g) <= 2:
            powerup = random.choice(PowerUp.__subclasses__())
            powerup_group.add(powerup(random.randint(0, 736), random.randint(-130, -60)))
            self.last_powerup = current_time

    def add_enemies(self, group):
        if len(group) == 2 and self.more_enemies:
            # add more enemies
            self.index += 1
            for _ in range(9 + self.index):
                group.add(NormalEnemy(random.randint(0, 736), random.randint(-130, -60)))
            for _ in range(0 + self.index):
                group.add(SpeedEnemy(random.randint(0, 736), random.randint(-130, -60)))

    # print methods
    def print_newhs_score_counter(self, font, font_size, text, color, pos, surface):
        score_font = pygame.font.Font(font, font_size)
        score_text = score_font.render(text, True, color)
        surface.blit(score_text, pos)

    def check_lives_and_enemy_position(self, game_score, player, enemies_g, group_l,
                                       surface, empty_groups, print_game_over, explosion_group, my_group, back_group,
                                       m_pos):

        if player.lives == 0:
            empty_groups(group_l, explosion_group)
            print_game_over(game_score, surface)
            player.dead = True
            back_group.draw(surface)

        elif len(enemies_g) == 0 and len(my_group) == 0:
            self.print_mission_complete(surface)
            empty_groups(group_l, explosion_group)
            back_group.draw(surface)
            for sprite in back_group.sprites():
                sprite.draw(m_pos, surface)

    def print_mission_complete(self, surface):
        win_font = pygame.font.Font("freesansbold.ttf", 64)
        win_font2 = pygame.font.Font("freesansbold.ttf", 48)
        win_text = win_font.render("Mission Complete", True, (153, 204, 0))
        win_text2 = win_font2.render("Möchtest du noch eine Runde spielen?", True, (204, 204, 255))
        surface.blit(win_text, (350, 250))
        surface.blit(win_text2, (350, 350))

    def print_game_over(self, game_score, surface):
        go_font = pygame.font.Font("freesansbold.ttf", 64)
        go_text = go_font.render("GAME OVER", True, (255, 255, 255))
        score_font1 = pygame.font.Font("freesansbold.ttf", 16)
        go_text_score = score_font1.render(
            f"Dein Punktestand: {str(game_score)}", True, (100, 200, 10)
        )
        surface.blit(go_text, (200, 150))
        surface.blit(go_text_score, (325, 250))

    def save_high_score_data(self, score, name_field, high_score):
        if score > high_score:
            with open('high_score', 'r+') as file:
                lines = file.readlines()
                lines.append(f"{score}\n")
                lines.sort(key=int, reverse=True)
                lines = lines[:3]
            with open('high_score', 'w') as f:
                f.writelines(lines)

            with open('names', 'r+') as file:
                hs_names = file.readlines()
                index = lines.index(f"{score}\n")
                hs_names.insert(index, name_field.name + '\n')
                hs_names = hs_names[:3]
            with open('names', 'w') as f:
                f.writelines(hs_names)


class ShieldSymbol(StaticObjects):
    def __init__(self):
        x = 20
        y = 65
        image = "shield_pu.png"
        super().__init__(image, x, y)

    def draw(self, current_time, player, print_counter, surface):
        pass


class PowerUpShieldSpaceship(StaticObjects):
    def __init__(self, x, y):
        image = "shield.png"
        super().__init__(image, x, y)

    def update(self, player):
        self.rect.x = player.rect.x
        self.rect.y = player.rect.y


class Hearts(StaticObjects):
    def __init__(self, x, y):
        image = "heart.png"
        super().__init__(image, x, y)


class HealthPowerUp(PowerUp):
    def __init__(self, x, y):
        image = "passion.png"
        super().__init__(image, x, y)

    def apply(self, player, heart_gr):
        if player.lives < 3:
            player.lives += 1
            heart = Hearts(16 * len(heart_gr) + 16, 45)
            heart_gr.add(heart)


class ShieldPowerUp(PowerUp):
    def __init__(self, x, y):
        image = "shield_pu.png"
        super().__init__(image, x, y)

    def apply(self, player, heart_gr):
        player.add_shield()


class DoubleShootPowerUp(PowerUp):
    def __init__(self, x, y):
        image = "fire.png"
        super().__init__(image, x, y)

    def apply(self, player, heart_gr):
        player.add_shoot_bar()


class NormalEnemy(Spaceships):
    def __init__(self, x, y):
        image = "ufo.png"
        speed = 5
        lives = 1
        shoot_count = 0
        cooldown = 0
        speed_y = 60
        sound = None
        super().__init__(image, speed, lives, shoot_count, x, y, cooldown, 2, sound, speed_y)

    def shoot(self, current_time, group, bullet_group, volume):
        pass


class SpeedEnemy(Spaceships):
    def __init__(self, x, y):
        image = "aircraft.png"
        speed = 10
        lives = 2
        shoot_count = 1000
        cooldown = 0
        speed_y = 60
        sound = 'tie_shoot_better.mp3'
        super().__init__(image, speed, lives, shoot_count, x, y, cooldown, 2, sound, speed_y)


class BossSpaceship(Spaceships):
    def __init__(self, x, y):
        image = "death-star.png"
        speed = 1
        lives = 3
        shoot_count = 2000
        cooldown = 500
        speed_y = 100
        sound = 'death-star_shoot_sound.mp3'
        super().__init__(image, speed, lives, shoot_count, x, y, cooldown, 2, sound, speed_y)

    def shoot(self, current_time, h_group, bullet_group, volume):
        bullet = Bullet(self.rect.centerx, self.rect.bottom, "death_star_laser1.png", math.pi / 2, 0, 0)
        if current_time - self.last_shot > self.shoot_count and len(h_group) > 0 and not bullet.beam:
            shooting_sound = mixer.Sound(f'sounds/{self.sound}').play()
            shooting_sound.set_volume(volume)
            bullet_group.add(bullet)
            bullet.beam = True
        for sprite in bullet_group.sprites():
            if sprite.beam:
                sprite.update_laser_beam(self, 30, -10, -10)
                if current_time - self.last_shot > self.cooldown:
                    self.last_shot = current_time


class PlayerSpaceship(Spaceships):
    def __init__(self, x, y):
        image = "battleship.png"
        speed = 0
        lives = 3
        shoot_count = 200
        cooldown = 200
        sound = 'player-shoot-sound_ogg.ogg'
        super().__init__(image, speed, lives, shoot_count, x, y, cooldown, 3, sound, speed_y=None)
        self.amo = 0
        self.double_shoot = False
        self.shield_bool = False
        self.dead = False
        self.z = True
        self.move_choice = random.choice([-5, 5])
        self.angle = 0
        self.shield_group = pygame.sprite.Group()
        self.total_seconds = 7
        self.last_up = pygame.time.get_ticks()

    def draw(self, surface, print_counter):
        super().draw(surface, print_counter)
        self.shield_group.draw(surface)
        if self.double_shoot:
            self.draw_double_shoot_bar(surface)
        if self.shield_bool:
            self.draw_shield_timer(surface, print_counter)

    def draw_shield_timer(self, surface, print_counter):
        shield_symbol = ShieldSymbol()
        surface.blit(shield_symbol.image, (20, 40))
        print_counter("mainmenufont.ttf", 27, str(self.total_seconds), (255, 165, 0),
                      (30, 40), surface)

    def update(self, surface, volume, current_time, func, h_group, game_score, explosion_group, group, bullet_group,
               enemy_bullet_group, spaceship):

        super().update(surface, volume, current_time, func, h_group, game_score, explosion_group, group, bullet_group,
                       enemy_bullet_group, spaceship)

        if self.shield_bool:
            self.shield_counter_update(current_time)
            self.shield_group.update(self)

    def shield_counter_update(self, current_time):
        if current_time - self.last_up > 1000:
            self.total_seconds -= 1
            self.last_up = current_time
        if self.total_seconds <= 0:
            self.shield_bool = False
            self.shield_group.empty()
            self.total_seconds = 7

    def shoot(self, current_time, heart_g, bullet_group, volume):
        key = pygame.key.get_pressed()
        if key[pygame.K_SPACE] and current_time - self.last_shot > self.shoot_count and len(heart_g) > 0:

            shooting_sound = mixer.Sound(f'sounds/{self.sound}')
            shooting_sound.play()
            shooting_sound.set_volume(volume)

            if not self.double_shoot:
                bullet = Bullet(self.rect.centerx,
                                self.rect.top,
                                "laser.png",
                                math.pi / 2,
                                -10,
                                0)
                bullet_group.add(bullet)
            else:
                bullet_double_shoot = Bullet(self.rect.left,
                                             self.rect.top,
                                             "laser.png",
                                             math.pi / 2,
                                             -10,
                                             0)
                bullet_double_shoot2 = Bullet(self.rect.right,
                                              self.rect.top,
                                              "laser.png",
                                              math.pi / 2,
                                              -10,
                                              0)

                bullet_group.add(bullet_double_shoot)
                bullet_group.add(bullet_double_shoot2)

                self.amo -= 2

            self.last_shot = current_time

    def check_collision(self, h_group, game_score, spaceship, explosion_group, enemy_bullet_group, group):
        for bullet in enemy_bullet_group.sprites():
            if self.rect.colliderect(bullet) and not self.shield_bool and len(h_group) > 0:
                bullet.kill()
                h_group.sprites()[-1].kill()
                self.lives -= 1
                explosion_group.add(Explosion(self.rect.x, self.rect.y, 1))

    def add_shield(self):
        powerup_shield = PowerUpShieldSpaceship(self.rect.centerx, self.rect.centery)
        self.shield_group.add(powerup_shield)
        self.shield_bool = True
        self.total_seconds = 7

    def move(self, func, spaceship, surface, explosion_group, group=None):
        if not self.dead:
            key = pygame.key.get_pressed()
            if key[pygame.K_LEFT] or key[pygame.K_a]:
                self.move_x(-10)
            if key[pygame.K_RIGHT] or key[pygame.K_d]:
                self.move_x(10)
            if key[pygame.K_UP] or key[pygame.K_w]:
                self.move_y(-10)
            if key[pygame.K_DOWN] or key[pygame.K_s]:
                self.move_y(10)
        else:
            self.shield_bool = False
            self.double_shoot = False
            self.create_rotate_img(explosion_group, surface)

    def create_rotate_img(self, explosion_group, surface):
        self.angle += 4
        self.rotated_image = pygame.transform.rotate(self.image, self.angle)
        explosion = Explosion(self.rect.centerx, self.rect.centery, 2)
        huge_explosion = Explosion(400, 250, 3)
        if 736 >= self.rect.x > 10 and 10 < self.rect.y < 536:
            self.kill()
            surface.blit(self.rotated_image, (self.rect.x, self.rect.y))
            self.move_x(self.move_choice)
            self.move_y(self.move_choice)
        elif len(explosion_group) == 0 and self.z:
            explosion_group.add(explosion)
            explosion_group.add(huge_explosion)
            self.z = False

    def add_shoot_bar(self):
        self.amo = 200
        self.double_shoot = True

    def draw_double_shoot_bar(self, surface):
        if self.double_shoot:
            blue = (0, 0, 255)
            orange = (255, 165, 0)
            pygame.draw.rect(surface, orange, (self.rect.x, (self.rect.bottom + 10), self.rect.width, 10))
            pygame.draw.rect(surface, blue,
                             (self.rect.x, (self.rect.bottom + 10), int(self.rect.width * (self.amo / 200)), 10))
            if self.amo <= 0:
                self.double_shoot = False


class Pause(Buttons):
    def __init__(self):
        x = 740
        y = 40
        image = "pause.png"
        extra_image_sizex = 32
        extra_image_sizey = 32
        bg_image = "pause-button.png"
        bgimage_sizex = 32
        bgimage_sizey = 32
        text = ''
        plus_vecx = 0
        plus_vecy = 0
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class Name(Buttons):
    def __init__(self):
        x = 680
        y = 500
        image = "check.png"
        extra_image_sizex = 42
        extra_image_sizey = 42
        bg_image = "check_green.png"
        bgimage_sizex = 42
        bgimage_sizey = 42
        text = ''
        plus_vecx = 0
        plus_vecy = 0
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)
        self.name = ''

        self.yoda_img = pygame.image.load('yoda.png')
        self.yoda_img = pygame.transform.scale(self.yoda_img, (100, 200))

        self.field = pygame.image.load('frame.png')
        self.field = pygame.transform.scale(self.field, (600, 500))

        self.bubble = pygame.image.load('speech-bubble.png')
        self.bubble = pygame.transform.scale(self.bubble, (400, 200))

        self.text_field = pygame.image.load('cell.png')
        self.text_field = pygame.transform.scale(self.text_field, (300, 200))

    def update(self, m_pos, menu_window, game_window, level_three_window, empty_groups, group_l, explosion_group):
        super().update(m_pos, menu_window, game_window, level_three_window, empty_groups, group_l, explosion_group)
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN and len(self.name) <= 13:
                if event.key == pygame.K_BACKSPACE:
                    self.name = self.name[:-1]
                else:
                    self.name += event.unicode

    def draw(self, m_pos, surface):
        super().draw(m_pos, surface)
        surface.blit(self.field, (100, 50))
        surface.blit(self.bubble, (200, 150))
        surface.blit(self.yoda_img, (125, 270))
        self.draw_text(surface, 16, 224, 210, 'Deinen Namen eingeben, du solltest')
        surface.blit(self.text_field, (280, 240))
        self.draw_text(surface, 18, 340, 325, self.name)
        return self.name


class BackMainMenu(Buttons):
    def __init__(self):
        x = 680
        y = 460
        image = "rounded-recktangle.png"
        extra_image_sizex = 64
        extra_image_sizey = 64
        bg_image = "check_green.png"
        bgimage_sizex = 64
        bgimage_sizey = 64
        text = ''
        plus_vecx = 0
        plus_vecy = 0
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class BackToMenu(Buttons):
    def __init__(self):
        x = 400
        y = 350
        image = "rounded-rectangle.png"
        extra_image_sizex = 250
        extra_image_sizey = 128
        bg_image = "ray_shield.png"
        bgimage_sizex = 250
        bgimage_sizey = 70
        text = 'Back to Menu'
        plus_vecx = 3
        plus_vecy = 30
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)

    def update(self, m_pos, menu_window, game_window, level_three_window, empty_groups, group_l, explosion_group):
        super().update(m_pos, menu_window, game_window, level_three_window, empty_groups, group_l, explosion_group)
        if self.action:
            empty_groups(group_l, explosion_group)
            # Save the game states
            game_window.save_high_score_data(game_window.score, game_window.name_field, game_window.high_score)
            level_three_window.save_high_score_data(level_three_window.score, level_three_window.name_field,
                                                    level_three_window.high_score)
            # Reset the scores
            game_window.score = 0
            level_three_window.score = 0
            # Reset the player spaceship's shield and double shoot abilities
            game_window.player_spaceship.shield_bool = False
            game_window.player_spaceship.double_shoot = False
            # Set the window booleans
            menu_window.window_open = True
            game_window.window_open = False
            level_three_window.window_open = False
            # Empty the enemy group in level three window
            level_three_window.enemy_group.empty()
            # Set the action to False
            self.action = False

    def draw(self, m_pos, surface):
        super().draw(m_pos, surface)
        self.draw_text(surface, 27, self.rect.x + 10, self.rect.y + 40, str(self.text))


class Continue(Buttons):
    def __init__(self):
        x = 400
        y = 250
        image = "rounded-rectangle.png"
        extra_image_sizex = 160
        extra_image_sizey = 128
        bg_image = "ray_shield.png"
        bgimage_sizex = 160
        bgimage_sizey = 70
        text = 'Continue'
        plus_vecx = 3
        plus_vecy = 30
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)

    def update(self, m_pos, menu_window, game_window, level_three_window, empty_groups, group_l, explosion_group):
        super().update(m_pos, menu_window, game_window, level_three_window, empty_groups, group_l, explosion_group)
        if self.action:
            self.action = False
            game_window.pause.action = False
            level_three_window.pause.action = False

    def draw(self, m_pos, surface):
        super().draw(m_pos, surface)
        self.draw_text(surface, 27, self.rect.x + 10, self.rect.y + 40, str(self.text))


class Settings(Buttons):
    def __init__(self):
        x = 400
        y = 250
        image = "rounded-rectangle.png"
        extra_image_sizex = 160
        extra_image_sizey = 128
        bg_image = "ray_shield.png"
        bgimage_sizex = 160
        bgimage_sizey = 70
        text = 'Continue'
        plus_vecx = 3
        plus_vecy = 30
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)
'main- loop

import pygame
from pygame import mixer
from GameClasses import GameWindow
from MenuClasses import MenuWindow, LevelWindow, HighScoreWindow, SettingsWindow
from Level3 import LevelThreeWindow

# Todo morgen
# - score reaparieren
# level 1 mit play verlinken
# sound button schöner
# exe
level_window = LevelWindow()
high_score_window = HighScoreWindow()
main_menu_window = MenuWindow()
game_window = GameWindow('Space Invaders', 'vortex.png')
level_three_game_window = LevelThreeWindow('ENDLEVEL', 'blue_nebula.png')
setting_window = SettingsWindow()

window_group = pygame.sprite.Group(main_menu_window,
                                   high_score_window,
                                   level_window,
                                   game_window,
                                   level_three_game_window,
                                   setting_window)


pygame.init()
mixer.init(44100, -16, 2, 2048)
clock = pygame.time.Clock()
menu = True
while menu:
    clock.tick(60)
    mouse_pos = pygame.mouse.get_pos()
    time_now = pygame.time.get_ticks()
    for event in pygame.event.get():
        if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
            menu = False
        elif event.type == pygame.mouse.get_pressed(5):
            menu = False

    for window in window_group.sprites():
        if window.window_open:
            window.draw(mouse_pos)
            window.update(mouse_pos,
                          time_now,
                          level_window,
                          high_score_window,
                          main_menu_window,
                          game_window,
                          level_three_game_window,
                          setting_window)

    pygame.display.update()
# Level2

import pygame
from pygame import mixer
from GameClasses import GameWindow, Explosion
from MotherClasses import Spaceships, Bullet
import math


class LevelThreeWindow(GameWindow):
    def __init__(self, caption, image):
        super().__init__(caption, image)

    def add_enemies(self, group):
        pass


class Endboss(Spaceships):
    def __init__(self, x, y):
        image = "endboss_final3.png"
        speed = 1
        lives = 500
        shoot_count = 2000
        cooldown = 3000
        speed_y = 1
        image_size_x = 450
        image_size_y = 450
        sound = 'death-star_shoot_sound.mp3'
        super().__init__(image, speed, lives, shoot_count, x, y, cooldown, 4, sound, speed_y, image_size_x, image_size_y)
        self.get_aliens = True

    def draw(self, surface, print_counter):
        super().draw(surface, print_counter)
        if self.lives != 0:
            self.draw_health_bar(surface)

    def move_x(self, speed):
        self.rect.x = min(max(self.rect.x, -100), 601)
        self.rect.x += self.speed

    def move_y(self, speed):
        self.rect.y = min(max(self.rect.y, -500), -100)
        self.rect.y += self.speed_y

    def move(self, func, spaceship, surface, explosion_group, group):
        self.move_y(self.speed_y)
        if len(group) == 1 and self.rect.y > -109:
            self.move_x(self.speed)
            if self.rect.x >= 550:
                self.speed = -self.speed
            if self.rect.x <= -100:
                self.speed = 1
        elif len(group) < 1:
            self.move_x(self.speed)
            self.speed_y = -1
            if self.rect.x > 300:
                self.speed = 0

    def shoot(self, current_time, h_group, bullet_group, volume):
        bullet = Bullet(self.rect.centerx, self.rect.bottom, "death-star_laser_final1.png", math.pi / 2, 0, 0)
        if current_time - self.last_shot > self.shoot_count and len(h_group) > 0 and not bullet.beam:
            shooting_sound = mixer.Sound(f'sounds/{self.sound}').play()
            shooting_sound.set_volume(volume)
            bullet_group.add(bullet)
            bullet.beam = True
        for sprite in bullet_group.sprites():
            if sprite.beam:
                sprite.update_laser_beam(self, 120, -40, -50)
                if current_time - self.last_shot > 1000:
                    self.last_shot = current_time

    def draw_health_bar(self, surface):
        red = (255, 0, 0)
        green = (0, 255, 0)
        pygame.draw.rect(surface, red, (self.rect.x + 125, self.rect.centery, 200, 10))
        pygame.draw.rect(surface, green, (self.rect.x + 125, self.rect.centery, int(200 * (self.lives / 500)), 10))

    def check_collision(self, h_group, game_score, spaceship, explosion_group, enemy_bullet_group, group):
        self.check_live(group, explosion_group)
        for bullet in enemy_bullet_group:
            explosion_small = Explosion(bullet.rect.centerx, bullet.rect.centery, 1)
            if pygame.sprite.collide_mask(self, bullet):
                explosion_group.add(explosion_small)
                bullet.kill()
                game_score += 1
                self.lives -= 1
        explosion_normal_size = Explosion(spaceship.rect.centerx, spaceship.rect.centery, 2)
        if pygame.sprite.collide_mask(self, spaceship):
            if not spaceship.shield_bool and len(h_group) > 0:
                h_group.sprites()[-1].kill()
                spaceship.lives -= 1
                explosion_group.add(explosion_normal_size)
        return game_score

    def check_live(self, group, explosion_group):
        explosion = Explosion(self.rect.centerx, self.rect.centery, 3)
        live_check_list = [450, 400, 350, 300, 250, 200, 150, 100, 50]
        for live in live_check_list:
            if self.lives == live and self.get_aliens:
                for enemy in range(2):
                    group.add(TieFighterLeft(-100, 0 + enemy * 200))
                for enemy in range(2):
                    group.add(TieFighterRight(900, 50 + enemy * 200))
                self.get_aliens = False
            if self.lives == live + 1:
                self.get_aliens = True
        if self.lives == 0:
            explosion_group.add(explosion)
            self.kill()


class TieFighter(Spaceships):
    def __init__(self, x, y, speed, list, plus_angle, direction, bullet_angle):
        self.index = 0
        lives = 2
        shoot_count = 800
        self.list = list
        image = list[self.index]
        cooldown = 800
        speed_y = 1
        sound = 'tie_shoot_better.mp3'
        super().__init__(image, speed, lives, shoot_count, x, y, cooldown, direction, sound, speed_y)
        self.plus_angle = plus_angle
        self.counter = 0
        self.angle = 0
        self.bullet_angle = bullet_angle

    def update_rotation(self):
        rotate_speed = 6  # wird für die länge des anzeigens eines Bildes verwendet
        self.counter += 1
        self.angle += self.plus_angle
        if self.counter >= rotate_speed and self.index < len(self.list) - 1:
            self.counter = 0
            self.index += 1
            self.image = pygame.image.load(self.list[self.index])
            self.image = pygame.transform.scale(self.image, (64, 64))
            self.image = pygame.transform.rotate(self.image, self.angle)

    def move(self, func, spaceship, surface, explosion_group, group):
        self.rect.x += self.speed
        self.rect.y += self.speed_y
        if 350 < self.rect.x <= 368:
            self.update_rotation()
            self.speed_y = - self.speed_y
        if not 1000 >= self.rect.x > -200:
            self.kill()

    def shoot(self, current_time, h_group, bullet_group, volume):
        if current_time - self.last_shot > self.shoot_count:
            shooting_sound = mixer.Sound(f'sounds/{self.sound}')
            shooting_sound.set_volume(volume)
            shooting_sound.play()
            bullet = Bullet(self.rect.centerx, self.rect.bottom, "death_star_laser1.png", math.pi / self.direction, 10,
                            self.bullet_angle)
            bullet_group.add(bullet)
            if current_time - self.last_shot > self.cooldown:
                self.last_shot = current_time

# shoot muss nicht verändert werden (soweit umschreiben!)
class TieFighterRight(TieFighter):
    def __init__(self, x, y):
        list = [f'tie_r/tie{1}.png',
                f'tie_r/tie{2}.png',
                f'tie_r/tie{3}.png',
                f'tie_r/tie{4}.png']
        speed = -2
        plus_angle = -4
        direction = -0.9
        bullet_angle = 110
        super().__init__(x, y, speed, list, plus_angle, direction, bullet_angle)


class TieFighterLeft(TieFighter):
    def __init__(self, x, y):
        list = [f'tie_l/tie{1}.png',
                f'tie_l/tie{2}.png',
                f'tie_l/tie{3}.png',
                f'tie_l/tie{4}.png']
        speed = 2
        plus_angle = 4
        direction = 4
        bullet_angle = 50
        super().__init__(x, y, speed, list, plus_angle, direction, bullet_angle)
#Menu Classes

import random

import pygame
from MotherClasses import Buttons, Window
from GameClasses import SpeedEnemy, BossSpaceship, NormalEnemy, Hearts
from Level3 import Endboss


# einzelne Buttons


class LevelButton(Buttons):
    def __init__(self):
        x = 200
        y = 200
        image = "rounded-rectangle.png"
        extra_image_sizex = 128
        extra_image_sizey = 128
        bg_image = "ray_shield.png"
        bgimage_sizex = 120
        bgimage_sizey = 70
        text = 'Levels'
        plus_vecx = 3
        plus_vecy = 30
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class HighScoreButton(Buttons):
    def __init__(self):
        x = 600
        y = 200
        image = "rounded-rectangle.png"
        extra_image_sizex = 128
        extra_image_sizey = 128
        bg_image = "ray_shield.png"
        bgimage_sizex = 120
        bgimage_sizey = 70
        text = 'Scores'
        plus_vecx = 3
        plus_vecy = 30
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class FastGame(Buttons):
    def __init__(self):
        x = 400
        y = 200
        image = "rounded-rectangle.png"
        extra_image_sizex = 100
        extra_image_sizey = 134
        bg_image = "play.png"
        bgimage_sizex = 100
        bgimage_sizey = 70
        text = 'Play'
        plus_vecx = 3
        plus_vecy = 30
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class ChooseLevelButtons(Buttons):
    def __init__(self, x, y):
        image = "rounded-rectangle.png"
        extra_image_sizex = 128
        extra_image_sizey = 128
        bg_image = "play.png"
        bgimage_sizex = 120
        bgimage_sizey = 70
        text = 'Level'
        plus_vecx = 3
        plus_vecy = 30
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class VolumeButton(Buttons):
    def __init__(self):
        x = 400
        y = 200
        image = "rect_vol.png"
        extra_image_sizex = 480
        extra_image_sizey = 60
        bg_image = "ray_shield2.png"
        bgimage_sizex = 480
        bgimage_sizey = 27
        text = 'volume'
        plus_vecx = 0
        plus_vecy = 18
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)
        self.volume = 1

    def draw(self, m_pos, surface):
        x, y = pygame.mouse.get_pos()
        print(x)
        surface.blit(self.bg_image, (self.rect.x + self.plus_vecx, self.rect.y + self.plus_vecy))
        if self.rect.collidepoint(m_pos) and x > self.rect.x and x < 631:
            self.bg_image = pygame.transform.scale(self.bg_image, (0 + x - self.rect.x, 27))
            self.volume = ((x - self.rect.x) / 480)
        self.draw_text(surface, 27, self.rect.x + 180, self.rect.y + 6, self.text)


class MenuWindow(Window):
    def __init__(self):
        caption = 'Menu'
        image = "menu_bg.png"
        window_open = True
        super().__init__(caption, image, window_open)
        self.level_button = LevelButton()
        self.high_score_button = HighScoreButton()
        self.fast_game_button = FastGame()
        self.settings_button = SettingsButton()
        pygame.mixer.init()
        self.group.add(self.level_button)
        self.group.add(self.high_score_button)
        self.group.add(self.fast_game_button)
        self.group.add(self.settings_button)

    def draw(self, m_pos):
        super().draw(m_pos)
        self.print_headline((320, 50))
        for sprite in self.group.sprites():
            sprite.draw_text(self.screen, 27, sprite.rect.x + 6, sprite.rect.y + 40, str(sprite.text))

    def update(self, m_pos, current_time, lvl_window, hs_window, menu_window, game_window, level_three_window,
               setting_window):
        for sprite in self.group.sprites():
            sprite.action = sprite.update(m_pos, menu_window, game_window, level_three_window, setting_window)
            if self.settings_button.action:
                self.window_open = self.change_screen_boolians(setting_window, self.settings_button)
            if self.level_button.action:
                self.window_open = self.change_screen_boolians(lvl_window, self.level_button)
            if self.high_score_button.action:
                self.window_open = self.change_screen_boolians(hs_window, self.high_score_button)

            if self.fast_game_button.action:
                for _ in range(5):
                    game_window.enemy_group.add(NormalEnemy(random.randint(0, 736), random.randint(-130, -60)))

                for _ in range(0):
                    game_window.enemy_group.add(SpeedEnemy(random.randint(0, 736), random.randint(-130, -60)))

                for _ in range(1):
                    game_window.enemy_group.add(BossSpaceship(random.randint(0, 736), 50))

                for heart in range(3):
                    hearts = Hearts(16 + heart * 16, 45)
                    game_window.heart_group.add(hearts)

                self.window_open = self.change_screen_boolians(game_window, self.fast_game_button)
                game_window.player_group.add(game_window.player_spaceship)
                game_window.player_spaceship.lives = 3
                game_window.player_spaceship.rect.x = 400
                game_window.player_spaceship.rect.y = 515
                game_window.player_spaceship.dead = False
                game_window.player_spaceship.z = True
                game_window.pause.action = False
                game_window.name_field.action = False


class SettingsWindow(Window):
    def __init__(self):
        caption = 'Settings'
        image = "setting_bg1.jpg"
        window_open = False
        super().__init__(caption, image, window_open)
        self.volume_button = VolumeButton()
        self.group.add(self.volume_button)
        self.group.add(self.back_button)

    def draw(self, m_pos):
        super().draw(m_pos)
        self.print_headline((270, 50))


class SettingsButton(Buttons):
    def __init__(self):
        x = 30
        y = 30
        image = "settings1.png"
        extra_image_sizex = 32
        extra_image_sizey = 32
        bg_image = "settings2.png"
        bgimage_sizex = 32
        bgimage_sizey = 32
        text = ''
        plus_vecx = 0
        plus_vecy = 0
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class LevelWindow(Window):
    def __init__(self):
        caption = 'Levels'
        image = "level_bg.jpg"
        window_open = False
        super().__init__(caption, image, window_open)
        for levels in range(2):
            self.group.add(ChooseLevelButtons(300 + levels * 200, 300))
        self.group.add(self.back_button)

    def draw(self, m_pos):
        super().draw(m_pos)
        self.print_headline((290, 50))
        for sprite in self.group.sprites():
            sprite.draw(m_pos, self.screen)
            sprite.draw_text(self.screen, 24, sprite.rect.x + 10, sprite.rect.y + 39,
                             sprite.text + str(self.group.sprites().index(sprite) + 1))

    def update(self, m_pos, current_time, lvl_window, hs_window, menu_window, game_window, level_three_window,
               setting_window):
        super().update(m_pos, current_time, lvl_window, hs_window, menu_window, game_window, level_three_window,
                       setting_window)
        for sprite in self.group.sprites():
            sprite.action = sprite.update(m_pos, menu_window, game_window, level_three_window)
        if self.group.sprites()[1].action:
            self._window_setup(level_three_window, self.group.sprites()[1], Endboss)
        if self.group.sprites()[0].action:
            self._window_setup(game_window, self.group.sprites()[0], BossSpaceship)
            for _ in range(5):
                game_window.enemy_group.add(NormalEnemy(random.randint(0, 736), random.randint(-130, -60)))

            for _ in range(2):
                game_window.enemy_group.add(SpeedEnemy(random.randint(0, 736), random.randint(-130, -60)))

    def _window_setup(self, window, sprite, Enemy):
        window.window_open = True
        window.enemy_group.add(Enemy(300, -400))

        for heart in range(3):
            hearts = Hearts(16 + heart * 16, 45)
            window.heart_group.add(hearts)

        window.player_group.add(window.player_spaceship)
        window.player_spaceship.lives = 3
        window.player_spaceship.rect.x = 400
        window.player_spaceship.rect.y = 515
        window.player_spaceship.dead = False
        window.player_spaceship.z = True
        self.window_open = self.change_screen_boolians(window, sprite)


class HighScoreWindow(Window):
    def __init__(self):
        caption = 'High Score'
        image = "hs_bg.jpg"
        window_open = False
        super().__init__(caption, image, window_open)
        self.group.add(self.back_button)
        self.color = (105, 105, 105)

    def draw(self, m_pos):
        super().draw(m_pos)
        self.print_headline((320, 50))
        self.draw_table(self.screen)
        self.draw_text(self.screen)
        self.draw_high_score(self.screen)
        self.back_button.draw(m_pos, self.screen)

    def draw_table(self, surface):
        pygame.draw.rect(surface, self.color, (150, 150, 500, 310), 4)
        pygame.draw.line(surface, self.color, (150, 225), (649, 225), 4)
        pygame.draw.line(surface, self.color, (150, 300), (649, 300), 4)
        pygame.draw.line(surface, self.color, (150, 375), (649, 375), 4)
        pygame.draw.line(surface, self.color, (300, 150), (300, 455), 4)

    def draw_text(self, surface):
        font = pygame.font.Font('mainmenufont.ttf', 27)
        text = font.render('Points    Name', True, (255, 165, 1))
        surface.blit(text, (160, 195))

    def draw_high_score(self, surface):
        start_point = 250
        index = 0
        name_index = 0
        yellow = (255, 165, 1)
        with open('high_score', 'r') as file:
            lines = file.readlines()
            font = pygame.font.Font('mainmenufont.ttf', 27)
            for line in range(3):
                text = font.render(str(lines[index]), True, yellow)
                surface.blit(text, (180, start_point + line * 80))
                index += 1

        with open('names', 'r') as file:
            lines = file.readlines()
            for line in range(3):
                text = font.render(str(lines[name_index]), True, yellow)
                surface.blit(text, (325, start_point + line * 82))
                name_index += 1
Larz60+ write May-06-2023, 09:25 AM:
Invalid URL.

Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Reply
#2
What is your frame rate?

What does this mean?
Quote:let him 3 sec shoot
Are you stopping your game for 3 seconds each time a laser is shot? That cannot be allowed. You can make the beam grow, but you need to let the game proceed at the same time. Like this:
import pygame

class Beam(pygame.sprite.Sprite):
    def __init__(self, speed = 10):
        super().__init__()
        self.x, self.y = 0, 0
        self.length = 0
        self.shooting = False
        self.speed = speed

    def at(self, x, y):
        self.x, self.y = x, y
    
    def shoot(self):
        self.length = 0
        self.shooting = True

    def draw(self, screen):
        if self.shooting:
            self.length += self.speed
            end = self.y + self.length
            start = max(self.y, end-100)
            pygame.draw.line(screen, (255, 0, 0), (self.x, start), (self.x, end), width=5)
            self.shooting = end < screen.get_height()


pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((200, 400))
beam = Beam()
beam.at(100, 50)
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            beam.shoot()
    screen.fill("black")
    beam.draw(screen)
    pygame.display.flip()
    clock.tick(30)
Reply
#3
Im sorry i tried it yesterday (back there it works). Thats the correct link (for now :D) https://github.com/wired88/Best-Space-Invaders-.git

For the reason that it does not work here is the code for the Boss (Death-Star):

@deanhystead
@Larz60+
class BossSpaceship(Spaceships):
    def __init__(self, x, y):
        image = "death-star.png"
        speed = 1
        lives = 3
        shoot_count = 600
        cooldown = 2000
        speed_y = 100
        sound = 'death-star_shoot_sound.mp3'
        super().__init__(image, speed, lives, shoot_count, x, y, cooldown, 2, sound, speed_y)

    def shoot(self, current_time, h_group, bullet_group, volume):
        if current_time - self.last_shot > self.shoot_count and len(h_group) > 0:                                            #1 
            shooting_sound = mixer.Sound(f'sounds/{self.sound}')
            shooting_sound.play()
            shooting_sound.set_volume(volume)
            bullet = Bullet(self.rect.centerx, self.rect.bottom, "death_star_laser1.png", math.pi/2, 10, 0) 
            bullet_group.add(bullet)                                                                                                                   #2
            if current_time - self.last_shot > self.cooldown:                                                                                 #3
                self.last_shot = current_time
#1 current time is definied in game loop(with a different name) and says current_time = pygame.time.get_ticks()
the code is for counting when the alens shoud shoot


#2 than i create a bullet and add it to the bullet group

#3 here i say if the time (the death star is shootuing) > cooldown(2sec):
the timer is 0 so it can begin again ( and till the 2seconds over the method add every loop run a bullet to grop so that it looks like a laser beam)

I mean its very logical to understand why the game is running so slow but like i sayd in the post above i dont know how to handle the laser beam without adding multiple bullets.
deanhystad write May-06-2023, 06:51 PM:
Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Reply
#4
Ah i have a idea i think i will do it with pygame.transform.scale.

But the problem now is, that the score absolutley does not work. I dont understand sometimes i think my code do things himselves. If i work on it and it works - tomorrow when i get on it and will continue my work it does not work anymore.........
Reply
#5
(May-05-2023, 10:26 PM)wired98 Wrote: Hey im very new to python and programming at this moment space invaders(my first project)

I have made it in star wars theme with little death stars that shoot a long laser beam. My problem is that my game runs sooooo super slow. I think its bcause this laserbeam. Because i dont have one sprizte for that i just start the timer and let him 3 sec shoot (looks perfectly like a laserbeam). And if i put in just a long lder pic that looks ugly af. Did anybody have a idea how i can make this better? I post you the code in the bottom. Thanks for answers.


Ah and the second problem is that if i shoot the NormalEnemy-Sprites the game_score equivalent like before. I dont know why. The other code in the function is running perfectly just the game_score stays the same. The same problem comes out when im in level_three_window(level two at this moment)
when the Score is at 450 and the tie-fighter pop up the counter stays the same and continue running just when the tie fighters flght away...



I will mak you some Videos so you can understand it better. ( If you want me to send you athe images and sounds then tell me)




Here is the Full Code:




#MotherClasses
import math
import random

import pygame
from pygame import mixer


class Window(pygame.sprite.Sprite):
    def __init__(self, caption, image, window_open):
        super().__init__()
        self.width = 800
        self.height = 600
        self.change_y_screen_image = 0
        self.caption = caption
        pygame.display.set_caption(caption)
        self.screen = pygame.display.set_mode((self.width, self.height))

        self.window_open = window_open

        self.image = pygame.image.load(image).convert()
        self.image = pygame.transform.scale(self.image, (self.width, self.height))

        self.group = pygame.sprite.Group()
        self.back_button = BackButton()
        self.spaceship_group = pygame.sprite.Group()

        self.xwing = XWing()
        self.tiefighter = TFighterBG()

        self.spaceship_group.add(self.xwing)
        self.spaceship_group.add(self.tiefighter)

    def print_headline(self, pos):
        orange = (255, 165, 0)
        menu_font = pygame.font.Font("Starjedi.ttf", 55)
        menu_font = menu_font.render(self.caption, True, orange)
        self.screen.blit(menu_font, pos)

    def draw(self, m_pos):
        self.screen.blit(self.image, (0, 0))
        for sprite in self.group.sprites():
            sprite.draw(m_pos, self.screen)
        self.group.draw(self.screen)
        self.spaceship_group.draw(self.screen)

    def update(self, m_pos, current_time, lvl_window, hs_window, menu_window, game_window, level_three_window, setting_window):
        for sprite in self.spaceship_group.sprites():
            sprite.update(current_time)
        self.back_button.update(m_pos, menu_window, game_window, level_three_window)
        if self.back_button.action:
            menu_window.window_open = True
            self.window_open = False
            self.back_button.action = False

    def change_screen_boolians(self, clicked_window, clicked_button):
        clicked_window.window_open = True
        clicked_button.action = False
        return False


class BackGroundSpaceships(pygame.sprite.Sprite):
    def __init__(self, x, y, image, spaceship_size_x, spaceship_size_y, flight_count, speedx, speedy):
        super().__init__()
        self.x = x
        self.y = y
        self.image = pygame.image.load(image)
        self.spaceship_size_x = spaceship_size_x
        self.spaceship_size_y = spaceship_size_y
        self.image = pygame.transform.scale(self.image, (spaceship_size_x, spaceship_size_y))
        self.rect = self.image.get_rect(center=[self.x, self.y])
        self.last_count = pygame.time.get_ticks()
        self.flight_count = flight_count
        self.speedx = speedx
        self.speedy = speedy

    def move(self):
        self.rect.x += self.speedx
        self.rect.y += self.speedy

    def update(self, current_time):
        if current_time - self.last_count > self.flight_count and self.rect.x <= 1000:
            self.move()
        if self.rect.x <= -200:
            self.last_count = current_time
            self.rect.x = 950

    def draw(self, m_pos, surface):
        pass


class TFighterBG(BackGroundSpaceships):
    def __init__(self):
        x = 1000
        y = 200
        image = "t_fighter_menu.png"
        spaceship_size_x = 64
        spaceship_size_y = 64
        flight_count = 6000
        speedx = -5
        speedy = 2
        super().__init__(x, y, image, spaceship_size_x, spaceship_size_y, flight_count, speedx, speedy)


class XWing(BackGroundSpaceships):
    def __init__(self):
        x = 600
        y = 800
        image = "battleship.png"
        spaceship_size_x = 64
        spaceship_size_y = 64
        flight_count = 3000
        speedx = -2
        speedy = -5
        super().__init__(x, y, image, spaceship_size_x, spaceship_size_y, flight_count, speedx, speedy)
        self.image = pygame.transform.rotate(self.image, 15)


class Buttons(pygame.sprite.Sprite):
    def __init__(self, x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey, text, plus_vecx, plus_vecy):
        super().__init__()
        self.x = x
        self.y = y
        self.image = pygame.image.load(image)
        self.image = pygame.transform.scale(self.image, (extra_image_sizex, extra_image_sizey))
        self.rect = self.image.get_rect()
        self.rect.center = [x, y]
        self.bg_image = pygame.image.load(bg_image)
        self.bg_image = pygame.transform.scale(self.bg_image, (bgimage_sizex, bgimage_sizey))
        self.star_wars_color = (255, 165, 1)
        self.clicked = False
        self.action = False
        self.text = text
        self.plus_vecx = plus_vecx
        self.plus_vecy = plus_vecy

    def draw(self, m_pos, surface):
        if self.rect.collidepoint(m_pos):
            surface.blit(self.bg_image, (self.rect.x + self.plus_vecx, self.rect.y + self.plus_vecy))

    def update(self, m_pos, menu_window, game_window, level_three_window, empty_groups=None,
               group_l=None, explosion_group=None, extra_posx=0, extra_posy=0):
        sound = mixer.Sound('sounds/button_click_ogg.ogg')
        if self.rect.collidepoint(m_pos) and pygame.mouse.get_pressed()[0] == 1 and not self.clicked:
            sound.play()
            self.clicked = True
            self.action = True
        if pygame.mouse.get_pressed()[0] == 0:
            self.clicked = False
        return self.action

    def draw_text(self, surface, size, x, y, text):
        grey = (105, 105, 105)
        font = pygame.font.Font("Starjedi.ttf", size)
        text = font.render(str(text), True, grey)
        surface.blit(text, (x, y))


########################################################################################################################
# Game Mother Classes
class StaticObjects(pygame.sprite.Sprite):
    def __init__(self, image, x, y):
        super().__init__()
        self.x = x
        self.y = y
        self.image = pygame.image.load(image)
        self.rect = self.image.get_rect()
        self.rect.center = [x, y]
        self.show_shield = False

    def update(self, player):
        pass

    def check_click(self):
        pass

    def draw(self, current_time, player, print_counter, surface):
        pass


class PowerUp(pygame.sprite.Sprite):
    def __init__(self, image, x, y):
        super().__init__()
        self.x = x
        self.y = y
        self.speed = 5
        self.image = pygame.image.load(image)
        self.rect = self.image.get_rect()
        self.rect.center = [x, y]
        self.last_powerup = pygame.time.get_ticks()

    def check_collision(self, player, heart_g):
        if self.rect.colliderect(player.rect):
            self.apply(player, heart_g)
            self.kill()

    def apply(self, player, heart_gr):
        pass

    def move(self):
        self.rect.y += self.speed
        if self.rect.y >= 600:
            self.kill()

    def update(self, player, heart_g, current_time, powerup_group):
        self.move()
        self.check_collision(player, heart_g)





class Spaceships(pygame.sprite.Sprite):
    def __init__(self, image, speed, lives, shoot_count, x, y, cooldown, direction, sound, speed_y, image_size_x=64, image_size_y=64):
        super().__init__()
        self.x = x
        self.y = y
        self.speed = speed
        self.speed_y = speed_y
        self.image = pygame.image.load(image)
        self.image = pygame.transform.scale(self.image, (image_size_x, image_size_y))
        self.rect = self.image.get_rect(center=[x, y])
        self.lives = lives
        self.last_shot = pygame.time.get_ticks()
        self.shoot_count = shoot_count
        self.cooldown = cooldown
        self.mask = pygame.mask.from_surface(self.image)
        self.direction = direction
        self.sound = sound
        self.lives_index = 0

    def draw(self, surface, print_counter):
        pass

    def shoot(self, current_time, h_group, bullet_group, volume):
        if current_time - self.last_shot > self.shoot_count and len(h_group) > 0:
            shooting_sound = mixer.Sound(f'sounds/{self.sound}').play()
            shooting_sound.set_volume(volume)
            bullet = Bullet(self.rect.centerx, self.rect.bottom, "death_star_laser1.png", math.pi/2, 10, 0)
            bullet_group.add(bullet)
            if current_time - self.last_shot > self.cooldown:
                self.last_shot = current_time

    def move_y(self, speed):
        self.rect.y = min(max(self.rect.y, 0), 536)
        self.rect.y += speed

    def move_x(self, speed):
        self.rect.x = min(max(self.rect.x, 0), 736)
        self.rect.x += speed

    def move(self, func, spaceship, surface, explosion_group, group):
        self.move_x(self.speed)
        if self.rect.x >= 736 or self.rect.x <= 0:
            self.speed = -self.speed
            self.rect.y += self.speed_y
        if self.rect.y >= 600:
            func()
            spaceship.dead = True

    def update(self, surface, volume, current_time, func, h_group, game_score, explosion_group, group, bullet_group, enemy_bullet_group, spaceship):
        game_score = self.check_collision(h_group, game_score, spaceship, explosion_group, enemy_bullet_group, group)
        self.shoot(current_time, h_group, bullet_group, volume)
        self.move(func, spaceship, surface, explosion_group, group)
        return game_score

    def check_collision(self, h_group, game_score, player, explosion_group, enemy_bullet_group, group):
        game_score = game_score
        explosion = Explosion(self.rect.centerx, self.rect.centery, 1)
        if pygame.sprite.collide_mask(self, player):
            explosion_group.add(explosion)
            if not player.shield_bool and len(h_group) > 0:
                h_group.sprites()[-1].kill()
                player.lives -= 1
            self.kill()
        for bullet in enemy_bullet_group.sprites():
            if pygame.sprite.collide_mask(self, bullet):
                self.lives_index += 1
                explosion_small = Explosion(bullet.rect.centerx, bullet.rect.centery, 1)
                explosion_group.add(explosion_small)
                bullet.kill()
                game_score += 1
                self.lives -= 1
                if self.lives == 0:
                    self.check_live()
        return game_score

    def check_live(self):
        self.rect.x = random.randint(0, 736)
        self.rect.y = random.randint(-130, -60)
        self.lives += self.lives_index
        self.lives_index = 0


class BackButton(Buttons):
    def __init__(self):
        x = 40
        y = 40
        image = "previous.png"
        extra_image_sizex = 32
        extra_image_sizey = 32
        bg_image = "previou_green.png"
        bgimage_sizex = 32
        bgimage_sizey = 32
        text = ''
        plus_vecx = 0
        plus_vecy = 0
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class Bullet(pygame.sprite.Sprite):  # 13
    def __init__(self, x, y, image, direction, speed=-10, angle=60):
        super().__init__()
        self.x = x
        self.y = y
        self.speed = speed
        self.image = pygame.image.load(image)

        self.rect = self.image.get_rect()
        self.rect.center = [x, y]

        self.mask = pygame.mask.from_surface(self.image)
        self.angle = angle
        self.direction = direction
        self.image = pygame.transform.rotate(self.image, self.angle)

        self.bullet_transform = 7
        self.beam_lengh = 0
        self.beam = False

    def update(self):  # 14
        new_x = self.rect.x + (self.speed * math.cos(self.direction))
        new_y = self.rect.y + (self.speed * math.sin(self.direction))
        self.rect.x = new_x
        self.rect.y = new_y
        if self.rect.bottom < 0 or self.rect.bottom > 1000 or self.rect.x > 800 or self.rect.x < -30:
            self.kill()

    def update_laser_beam(self, enemy, x_transform, extry_x, extra_y):
        if self.rect.bottom < 600:
            self.beam_lengh += self.bullet_transform
            self.image = pygame.transform.scale(self.image, (x_transform, self.beam_lengh))
            self.rect = self.image.get_rect()
            self.rect.y = enemy.rect.bottom + extra_y
        if self.rect.bottom >= 600:
            self.rect.y += 30
            self.bullet_transform = -1
            if self.rect.top > 600:
                self.beam = False
        self.rect.x = enemy.rect.centerx + extry_x


class Explosion(pygame.sprite.Sprite):
    def __init__(self, x, y, size):
        pygame.sprite.Sprite.__init__(self)
        self.x = x
        self.y = y
        self.images = []
        for i in range(1, 6):
            self.img = pygame.image.load(f"exp/exp{i}.png")
            if size == 1:
                self.img = pygame.transform.scale(self.img, (50, 50))  # alle Bilder auf die gleihe Größe skallieren
            elif size == 2:
                self.img = pygame.transform.scale(self.img, (100, 100))
            elif size == 3:
                self.img = pygame.transform.scale(self.img, (1000, 1000))
            self.images.append(self.img)
        self.index = 0  # zeigt das momentane Bild
        self.image = self.images[self.index]
        self.rect = self.image.get_rect()
        self.rect.center = [x, y]
        self.counter = 0
        self.sound = ''

    def update(self):
        explosion_speed = 4  # wird für die länge des anzeigens eines Bildes verwendet
        self.counter += 1
        if self.counter >= explosion_speed and self.index < len(self.images) - 1:
            self.counter = 0
            self.index += 1
            self.image = self.images[self.index]
        if self.index >= len(self.images) - 1 and self.counter >= explosion_speed:
            self.kill()
# Gmae(level1) Classes


import math
import random
import pygame
from pygame import mixer

from MotherClasses import Window, Spaceships, PowerUp, Buttons, StaticObjects, Bullet, Explosion


class GameWindow(Window):
    def __init__(self, caption, image):
        window_open = False
        super().__init__(caption, image, window_open)

        self.score = 0

        self.player_spaceship = PlayerSpaceship(400, 515)
        self.name_field = Name()
        self.pause = Pause()

        self.group_names = ['enemy_group',
                            'heart_group',
                            'powerup_group',
                            'explosion_group',
                            'player_bullet_group',
                            'enemy_bullet_group',
                            'player_group']

        for name in self.group_names:
            setattr(self, name, pygame.sprite.Group())

        self.volume = 100

        self.button_group = pygame.sprite.Group(self.pause)
        self.name_group = pygame.sprite.Group(self.name_field)

        self.last_powerup = pygame.time.get_ticks()
        self.change_y_screen_image = 0

        self.index = 1
        self.more_enemies = True
        self.more_enemies_at_score_points = 50

        # pause Attributes
        self.back_to_meu_button = BackToMenu()
        self.continue_button = Continue()
        self.back_group = pygame.sprite.Group(self.back_to_meu_button)
        self.pause_button_group = pygame.sprite.Group(self.back_to_meu_button,
                                                      self.continue_button)

        # lists
        self.bullet_group_list = [self.player_bullet_group,
                                  self.enemy_bullet_group]

        self.button_group_list = [self.button_group,
                                  self.name_group]

        self.group_list = [self.enemy_group,
                           self.heart_group,
                           self.powerup_group,
                           self.explosion_group,
                           self.player_bullet_group,
                           self.enemy_bullet_group,
                           self.player_group]

        with (open('high_score', 'r')) as file:
            self.high_score = int(file.readline(4))

    def update(self, m_pos, current_time, lvl_window, hs_window, menu_window, game_window, level_three_window,
               setting_window):
        self.spaceship_params = [self.screen,
                                 setting_window.volume_button.volume,
                                 current_time,
                                 self.empty_all_groups,
                                 self.heart_group,
                                 self.score,
                                 self.explosion_group,
                                 self.enemy_group]

        if not self.name_field.action:
            for group in self.button_group_list:  # update name-field before start game
                for sprite in group:
                    sprite.update(m_pos, menu_window, self, level_three_window, self.empty_all_groups, self.group_list,
                                  self.explosion_group)
        elif self.pause.action:
            self.pause_button_group.update(m_pos, menu_window, game_window, level_three_window, self.empty_all_groups,
                                           self.group_list,
                                           self.explosion_group)

        else:
            if not self.player_spaceship.dead:
                self.pause.update(m_pos, menu_window, self, level_three_window)
            else:
                self.back_group.update(m_pos, menu_window, game_window, level_three_window, self.empty_all_groups,
                                       self.group_list,
                                       self.explosion_group)

            for sprite in self.enemy_group.sprites():
                self.score = sprite.update(*self.spaceship_params,
                                           self.enemy_bullet_group,
                                           self.player_bullet_group,
                                           self.player_spaceship)


            self.player_spaceship.update(*self.spaceship_params,
                                         self.player_bullet_group,
                                         self.enemy_bullet_group,
                                         self.enemy_group)

            for bullet_group in self.bullet_group_list:
                bullet_group.update()

            if len(self.explosion_group) > 0:
                self.explosion_group.update()

            if len(self.powerup_group) > 0:
                self.powerup_group.update(self.player_spaceship,
                                      self.heart_group,
                                      current_time,
                                      self.powerup_group)
            if self.player_spaceship.lives <= 1:
                self.check_lives_and_enemy_position(self.score,
                                                    self.player_spaceship,
                                                    self.enemy_group,
                                                    self.group_list,
                                                    self.screen,
                                                    self.empty_all_groups,
                                                    self.print_game_over,
                                                    self.explosion_group,
                                                    self.group,
                                                    self.back_group,
                                                    m_pos)

            self.initialize_powerup(current_time,
                                    self.heart_group,
                                    self.powerup_group)

        #    if self.score >= self.more_enemies_at_score_points:
        #        self.add_enemies(self.enemy_group)
        #        self.more_enemies_at_score_points += 50

    def draw(self, m_pos):
        super().draw(m_pos)

        self.change_y_screen_image = self.seamless_background(self.change_y_screen_image,
                                                              self.image,
                                                              self.height,
                                                              self.screen)
        if not self.name_field.action:
            self.name_group.draw(self.screen)
            self.name_field.draw(m_pos, self.screen)

        elif self.pause.action:
            self.pause_button_group.draw(self.screen)

            for sprite in self.pause_button_group.sprites():
                sprite.draw(m_pos, self.screen)
        else:
            for group in self.group_list:
                group.draw(self.screen)

            if not self.player_spaceship.dead:
                self.pause.draw(m_pos, self.screen)
                self.button_group.draw(self.screen)
            else:
                self.back_group.draw(self.screen)
                for sprite in self.back_group.sprites():
                    sprite.draw(m_pos, self.screen)

            for sprite in self.enemy_group.sprites():
                sprite.draw(self.screen,
                            self.print_newhs_score_counter)

            for bullet_group in self.bullet_group_list:
                bullet_group.draw(self.screen)

            self.player_group.draw(self.screen)

            self.player_spaceship.draw(self.screen,
                                       self.print_newhs_score_counter)

            self.print_newhs_score_counter(
                "freesansbold.ttf",
                16,
                f"Punkte: {str(self.score)}",
                (155, 200, 255),
                (8, 8),
                self.screen,
            )

            if self.score > int(self.high_score):
                self.print_newhs_score_counter('Starjedi.ttf',
                                               10,
                                               'New Record!',
                                               (255, 134, 31),
                                               (8, 20),
                                               self.screen)

    def empty_all_groups(self, group_l, explosion_group):
        for group in group_l:
            if group != explosion_group:
                group.empty()

    def seamless_background(self, change_screen, image, screen_height, surface):
        change_screen += 1
        surface.blit(image, (0, change_screen))
        if change_screen >= screen_height:
            return 0
        if change_screen > 0:
            surface.blit(image, (0, 0 - screen_height + change_screen))
            return change_screen

    def initialize_powerup(self, current_time, heart_g, powerup_group):
        power_up_counter = 3000
        if current_time - self.last_powerup > power_up_counter and len(heart_g) <= 2:
            powerup = random.choice(PowerUp.__subclasses__())
            powerup_group.add(powerup(random.randint(0, 736), random.randint(-130, -60)))
            self.last_powerup = current_time

    def add_enemies(self, group):
        if len(group) == 2 and self.more_enemies:
            # add more enemies
            self.index += 1
            for _ in range(9 + self.index):
                group.add(NormalEnemy(random.randint(0, 736), random.randint(-130, -60)))
            for _ in range(0 + self.index):
                group.add(SpeedEnemy(random.randint(0, 736), random.randint(-130, -60)))

    # print methods
    def print_newhs_score_counter(self, font, font_size, text, color, pos, surface):
        score_font = pygame.font.Font(font, font_size)
        score_text = score_font.render(text, True, color)
        surface.blit(score_text, pos)

    def check_lives_and_enemy_position(self, game_score, player, enemies_g, group_l,
                                       surface, empty_groups, print_game_over, explosion_group, my_group, back_group,
                                       m_pos):

        if player.lives == 0:
            empty_groups(group_l, explosion_group)
            print_game_over(game_score, surface)
            player.dead = True
            back_group.draw(surface)

        elif len(enemies_g) == 0 and len(my_group) == 0:
            self.print_mission_complete(surface)
            empty_groups(group_l, explosion_group)
            back_group.draw(surface)
            for sprite in back_group.sprites():
                sprite.draw(m_pos, surface)

    def print_mission_complete(self, surface):
        win_font = pygame.font.Font("freesansbold.ttf", 64)
        win_font2 = pygame.font.Font("freesansbold.ttf", 48)
        win_text = win_font.render("Mission Complete", True, (153, 204, 0))
        win_text2 = win_font2.render("Möchtest du noch eine Runde spielen?", True, (204, 204, 255))
        surface.blit(win_text, (350, 250))
        surface.blit(win_text2, (350, 350))

    def print_game_over(self, game_score, surface):
        go_font = pygame.font.Font("freesansbold.ttf", 64)
        go_text = go_font.render("GAME OVER", True, (255, 255, 255))
        score_font1 = pygame.font.Font("freesansbold.ttf", 16)
        go_text_score = score_font1.render(
            f"Dein Punktestand: {str(game_score)}", True, (100, 200, 10)
        )
        surface.blit(go_text, (200, 150))
        surface.blit(go_text_score, (325, 250))

    def save_high_score_data(self, score, name_field, high_score):
        if score > high_score:
            with open('high_score', 'r+') as file:
                lines = file.readlines()
                lines.append(f"{score}\n")
                lines.sort(key=int, reverse=True)
                lines = lines[:3]
            with open('high_score', 'w') as f:
                f.writelines(lines)

            with open('names', 'r+') as file:
                hs_names = file.readlines()
                index = lines.index(f"{score}\n")
                hs_names.insert(index, name_field.name + '\n')
                hs_names = hs_names[:3]
            with open('names', 'w') as f:
                f.writelines(hs_names)


class ShieldSymbol(StaticObjects):
    def __init__(self):
        x = 20
        y = 65
        image = "shield_pu.png"
        super().__init__(image, x, y)

    def draw(self, current_time, player, print_counter, surface):
        pass


class PowerUpShieldSpaceship(StaticObjects):
    def __init__(self, x, y):
        image = "shield.png"
        super().__init__(image, x, y)

    def update(self, player):
        self.rect.x = player.rect.x
        self.rect.y = player.rect.y


class Hearts(StaticObjects):
    def __init__(self, x, y):
        image = "heart.png"
        super().__init__(image, x, y)


class HealthPowerUp(PowerUp):
    def __init__(self, x, y):
        image = "passion.png"
        super().__init__(image, x, y)

    def apply(self, player, heart_gr):
        if player.lives < 3:
            player.lives += 1
            heart = Hearts(16 * len(heart_gr) + 16, 45)
            heart_gr.add(heart)


class ShieldPowerUp(PowerUp):
    def __init__(self, x, y):
        image = "shield_pu.png"
        super().__init__(image, x, y)

    def apply(self, player, heart_gr):
        player.add_shield()


class DoubleShootPowerUp(PowerUp):
    def __init__(self, x, y):
        image = "fire.png"
        super().__init__(image, x, y)

    def apply(self, player, heart_gr):
        player.add_shoot_bar()


class NormalEnemy(Spaceships):
    def __init__(self, x, y):
        image = "ufo.png"
        speed = 5
        lives = 1
        shoot_count = 0
        cooldown = 0
        speed_y = 60
        sound = None
        super().__init__(image, speed, lives, shoot_count, x, y, cooldown, 2, sound, speed_y)

    def shoot(self, current_time, group, bullet_group, volume):
        pass


class SpeedEnemy(Spaceships):
    def __init__(self, x, y):
        image = "aircraft.png"
        speed = 10
        lives = 2
        shoot_count = 1000
        cooldown = 0
        speed_y = 60
        sound = 'tie_shoot_better.mp3'
        super().__init__(image, speed, lives, shoot_count, x, y, cooldown, 2, sound, speed_y)


class BossSpaceship(Spaceships):
    def __init__(self, x, y):
        image = "death-star.png"
        speed = 1
        lives = 3
        shoot_count = 2000
        cooldown = 500
        speed_y = 100
        sound = 'death-star_shoot_sound.mp3'
        super().__init__(image, speed, lives, shoot_count, x, y, cooldown, 2, sound, speed_y)

    def shoot(self, current_time, h_group, bullet_group, volume):
        bullet = Bullet(self.rect.centerx, self.rect.bottom, "death_star_laser1.png", math.pi / 2, 0, 0)
        if current_time - self.last_shot > self.shoot_count and len(h_group) > 0 and not bullet.beam:
            shooting_sound = mixer.Sound(f'sounds/{self.sound}').play()
            shooting_sound.set_volume(volume)
            bullet_group.add(bullet)
            bullet.beam = True
        for sprite in bullet_group.sprites():
            if sprite.beam:
                sprite.update_laser_beam(self, 30, -10, -10)
                if current_time - self.last_shot > self.cooldown:
                    self.last_shot = current_time


class PlayerSpaceship(Spaceships):
    def __init__(self, x, y):
        image = "battleship.png"
        speed = 0
        lives = 3
        shoot_count = 200
        cooldown = 200
        sound = 'player-shoot-sound_ogg.ogg'
        super().__init__(image, speed, lives, shoot_count, x, y, cooldown, 3, sound, speed_y=None)
        self.amo = 0
        self.double_shoot = False
        self.shield_bool = False
        self.dead = False
        self.z = True
        self.move_choice = random.choice([-5, 5])
        self.angle = 0
        self.shield_group = pygame.sprite.Group()
        self.total_seconds = 7
        self.last_up = pygame.time.get_ticks()

    def draw(self, surface, print_counter):
        super().draw(surface, print_counter)
        self.shield_group.draw(surface)
        if self.double_shoot:
            self.draw_double_shoot_bar(surface)
        if self.shield_bool:
            self.draw_shield_timer(surface, print_counter)

    def draw_shield_timer(self, surface, print_counter):
        shield_symbol = ShieldSymbol()
        surface.blit(shield_symbol.image, (20, 40))
        print_counter("mainmenufont.ttf", 27, str(self.total_seconds), (255, 165, 0),
                      (30, 40), surface)

    def update(self, surface, volume, current_time, func, h_group, game_score, explosion_group, group, bullet_group,
               enemy_bullet_group, spaceship):

        super().update(surface, volume, current_time, func, h_group, game_score, explosion_group, group, bullet_group,
                       enemy_bullet_group, spaceship)

        if self.shield_bool:
            self.shield_counter_update(current_time)
            self.shield_group.update(self)

    def shield_counter_update(self, current_time):
        if current_time - self.last_up > 1000:
            self.total_seconds -= 1
            self.last_up = current_time
        if self.total_seconds <= 0:
            self.shield_bool = False
            self.shield_group.empty()
            self.total_seconds = 7

    def shoot(self, current_time, heart_g, bullet_group, volume):
        key = pygame.key.get_pressed()
        if key[pygame.K_SPACE] and current_time - self.last_shot > self.shoot_count and len(heart_g) > 0:

            shooting_sound = mixer.Sound(f'sounds/{self.sound}')
            shooting_sound.play()
            shooting_sound.set_volume(volume)

            if not self.double_shoot:
                bullet = Bullet(self.rect.centerx,
                                self.rect.top,
                                "laser.png",
                                math.pi / 2,
                                -10,
                                0)
                bullet_group.add(bullet)
            else:
                bullet_double_shoot = Bullet(self.rect.left,
                                             self.rect.top,
                                             "laser.png",
                                             math.pi / 2,
                                             -10,
                                             0)
                bullet_double_shoot2 = Bullet(self.rect.right,
                                              self.rect.top,
                                              "laser.png",
                                              math.pi / 2,
                                              -10,
                                              0)

                bullet_group.add(bullet_double_shoot)
                bullet_group.add(bullet_double_shoot2)

                self.amo -= 2

            self.last_shot = current_time

    def check_collision(self, h_group, game_score, spaceship, explosion_group, enemy_bullet_group, group):
        for bullet in enemy_bullet_group.sprites():
            if self.rect.colliderect(bullet) and not self.shield_bool and len(h_group) > 0:
                bullet.kill()
                h_group.sprites()[-1].kill()
                self.lives -= 1
                explosion_group.add(Explosion(self.rect.x, self.rect.y, 1))

    def add_shield(self):
        powerup_shield = PowerUpShieldSpaceship(self.rect.centerx, self.rect.centery)
        self.shield_group.add(powerup_shield)
        self.shield_bool = True
        self.total_seconds = 7

    def move(self, func, spaceship, surface, explosion_group, group=None):
        if not self.dead:
            key = pygame.key.get_pressed()
            if key[pygame.K_LEFT] or key[pygame.K_a]:
                self.move_x(-10)
            if key[pygame.K_RIGHT] or key[pygame.K_d]:
                self.move_x(10)
            if key[pygame.K_UP] or key[pygame.K_w]:
                self.move_y(-10)
            if key[pygame.K_DOWN] or key[pygame.K_s]:
                self.move_y(10)
        else:
            self.shield_bool = False
            self.double_shoot = False
            self.create_rotate_img(explosion_group, surface)

    def create_rotate_img(self, explosion_group, surface):
        self.angle += 4
        self.rotated_image = pygame.transform.rotate(self.image, self.angle)
        explosion = Explosion(self.rect.centerx, self.rect.centery, 2)
        huge_explosion = Explosion(400, 250, 3)
        if 736 >= self.rect.x > 10 and 10 < self.rect.y < 536:
            self.kill()
            surface.blit(self.rotated_image, (self.rect.x, self.rect.y))
            self.move_x(self.move_choice)
            self.move_y(self.move_choice)
        elif len(explosion_group) == 0 and self.z:
            explosion_group.add(explosion)
            explosion_group.add(huge_explosion)
            self.z = False

    def add_shoot_bar(self):
        self.amo = 200
        self.double_shoot = True

    def draw_double_shoot_bar(self, surface):
        if self.double_shoot:
            blue = (0, 0, 255)
            orange = (255, 165, 0)
            pygame.draw.rect(surface, orange, (self.rect.x, (self.rect.bottom + 10), self.rect.width, 10))
            pygame.draw.rect(surface, blue,
                             (self.rect.x, (self.rect.bottom + 10), int(self.rect.width * (self.amo / 200)), 10))
            if self.amo <= 0:
                self.double_shoot = False


class Pause(Buttons):
    def __init__(self):
        x = 740
        y = 40
        image = "pause.png"
        extra_image_sizex = 32
        extra_image_sizey = 32
        bg_image = "pause-button.png"
        bgimage_sizex = 32
        bgimage_sizey = 32
        text = ''
        plus_vecx = 0
        plus_vecy = 0
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class Name(Buttons):
    def __init__(self):
        x = 680
        y = 500
        image = "check.png"
        extra_image_sizex = 42
        extra_image_sizey = 42
        bg_image = "check_green.png"
        bgimage_sizex = 42
        bgimage_sizey = 42
        text = ''
        plus_vecx = 0
        plus_vecy = 0
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)
        self.name = ''

        self.yoda_img = pygame.image.load('yoda.png')
        self.yoda_img = pygame.transform.scale(self.yoda_img, (100, 200))

        self.field = pygame.image.load('frame.png')
        self.field = pygame.transform.scale(self.field, (600, 500))

        self.bubble = pygame.image.load('speech-bubble.png')
        self.bubble = pygame.transform.scale(self.bubble, (400, 200))

        self.text_field = pygame.image.load('cell.png')
        self.text_field = pygame.transform.scale(self.text_field, (300, 200))

    def update(self, m_pos, menu_window, game_window, level_three_window, empty_groups, group_l, explosion_group):
        super().update(m_pos, menu_window, game_window, level_three_window, empty_groups, group_l, explosion_group)
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN and len(self.name) <= 13:
                if event.key == pygame.K_BACKSPACE:
                    self.name = self.name[:-1]
                else:
                    self.name += event.unicode

    def draw(self, m_pos, surface):
        super().draw(m_pos, surface)
        surface.blit(self.field, (100, 50))
        surface.blit(self.bubble, (200, 150))
        surface.blit(self.yoda_img, (125, 270))
        self.draw_text(surface, 16, 224, 210, 'Deinen Namen eingeben, du solltest')
        surface.blit(self.text_field, (280, 240))
        self.draw_text(surface, 18, 340, 325, self.name)
        return self.name


class BackMainMenu(Buttons):
    def __init__(self):
        x = 680
        y = 460
        image = "rounded-recktangle.png"
        extra_image_sizex = 64
        extra_image_sizey = 64
        bg_image = "check_green.png"
        bgimage_sizex = 64
        bgimage_sizey = 64
        text = ''
        plus_vecx = 0
        plus_vecy = 0
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class BackToMenu(Buttons):
    def __init__(self):
        x = 400
        y = 350
        image = "rounded-rectangle.png"
        extra_image_sizex = 250
        extra_image_sizey = 128
        bg_image = "ray_shield.png"
        bgimage_sizex = 250
        bgimage_sizey = 70
        text = 'Back to Menu'
        plus_vecx = 3
        plus_vecy = 30
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)

    def update(self, m_pos, menu_window, game_window, level_three_window, empty_groups, group_l, explosion_group):
        super().update(m_pos, menu_window, game_window, level_three_window, empty_groups, group_l, explosion_group)
        if self.action:
            empty_groups(group_l, explosion_group)
            # Save the game states
            game_window.save_high_score_data(game_window.score, game_window.name_field, game_window.high_score)
            level_three_window.save_high_score_data(level_three_window.score, level_three_window.name_field,
                                                    level_three_window.high_score)
            # Reset the scores
            game_window.score = 0
            level_three_window.score = 0
            # Reset the player spaceship's shield and double shoot abilities
            game_window.player_spaceship.shield_bool = False
            game_window.player_spaceship.double_shoot = False
            # Set the window booleans
            menu_window.window_open = True
            game_window.window_open = False
            level_three_window.window_open = False
            # Empty the enemy group in level three window
            level_three_window.enemy_group.empty()
            # Set the action to False
            self.action = False

    def draw(self, m_pos, surface):
        super().draw(m_pos, surface)
        self.draw_text(surface, 27, self.rect.x + 10, self.rect.y + 40, str(self.text))


class Continue(Buttons):
    def __init__(self):
        x = 400
        y = 250
        image = "rounded-rectangle.png"
        extra_image_sizex = 160
        extra_image_sizey = 128
        bg_image = "ray_shield.png"
        bgimage_sizex = 160
        bgimage_sizey = 70
        text = 'Continue'
        plus_vecx = 3
        plus_vecy = 30
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)

    def update(self, m_pos, menu_window, game_window, level_three_window, empty_groups, group_l, explosion_group):
        super().update(m_pos, menu_window, game_window, level_three_window, empty_groups, group_l, explosion_group)
        if self.action:
            self.action = False
            game_window.pause.action = False
            level_three_window.pause.action = False

    def draw(self, m_pos, surface):
        super().draw(m_pos, surface)
        self.draw_text(surface, 27, self.rect.x + 10, self.rect.y + 40, str(self.text))


class Settings(Buttons):
    def __init__(self):
        x = 400
        y = 250
        image = "rounded-rectangle.png"
        extra_image_sizex = 160
        extra_image_sizey = 128
        bg_image = "ray_shield.png"
        bgimage_sizex = 160
        bgimage_sizey = 70
        text = 'Continue'
        plus_vecx = 3
        plus_vecy = 30
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)
'main- loop

import pygame
from pygame import mixer
from GameClasses import GameWindow
from MenuClasses import MenuWindow, LevelWindow, HighScoreWindow, SettingsWindow
from Level3 import LevelThreeWindow

# Todo morgen
# - score reaparieren
# level 1 mit play verlinken
# sound button schöner
# exe
level_window = LevelWindow()
high_score_window = HighScoreWindow()
main_menu_window = MenuWindow()
game_window = GameWindow('Space Invaders', 'vortex.png')
level_three_game_window = LevelThreeWindow('ENDLEVEL', 'blue_nebula.png')
setting_window = SettingsWindow()

window_group = pygame.sprite.Group(main_menu_window,
                                   high_score_window,
                                   level_window,
                                   game_window,
                                   level_three_game_window,
                                   setting_window)


pygame.init()
mixer.init(44100, -16, 2, 2048)
clock = pygame.time.Clock()
menu = True
while menu:
    clock.tick(60)
    mouse_pos = pygame.mouse.get_pos()
    time_now = pygame.time.get_ticks()
    for event in pygame.event.get():
        if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
            menu = False
        elif event.type == pygame.mouse.get_pressed(5):
            menu = False

    for window in window_group.sprites():
        if window.window_open:
            window.draw(mouse_pos)
            window.update(mouse_pos,
                          time_now,
                          level_window,
                          high_score_window,
                          main_menu_window,
                          game_window,
                          level_three_game_window,
                          setting_window)

    pygame.display.update()
# Level2

import pygame
from pygame import mixer
from GameClasses import GameWindow, Explosion
from MotherClasses import Spaceships, Bullet
import math


class LevelThreeWindow(GameWindow):
    def __init__(self, caption, image):
        super().__init__(caption, image)

    def add_enemies(self, group):
        pass


class Endboss(Spaceships):
    def __init__(self, x, y):
        image = "endboss_final3.png"
        speed = 1
        lives = 500
        shoot_count = 2000
        cooldown = 3000
        speed_y = 1
        image_size_x = 450
        image_size_y = 450
        sound = 'death-star_shoot_sound.mp3'
        super().__init__(image, speed, lives, shoot_count, x, y, cooldown, 4, sound, speed_y, image_size_x, image_size_y)
        self.get_aliens = True

    def draw(self, surface, print_counter):
        super().draw(surface, print_counter)
        if self.lives != 0:
            self.draw_health_bar(surface)

    def move_x(self, speed):
        self.rect.x = min(max(self.rect.x, -100), 601)
        self.rect.x += self.speed

    def move_y(self, speed):
        self.rect.y = min(max(self.rect.y, -500), -100)
        self.rect.y += self.speed_y

    def move(self, func, spaceship, surface, explosion_group, group):
        self.move_y(self.speed_y)
        if len(group) == 1 and self.rect.y > -109:
            self.move_x(self.speed)
            if self.rect.x >= 550:
                self.speed = -self.speed
            if self.rect.x <= -100:
                self.speed = 1
        elif len(group) < 1:
            self.move_x(self.speed)
            self.speed_y = -1
            if self.rect.x > 300:
                self.speed = 0

    def shoot(self, current_time, h_group, bullet_group, volume):
        bullet = Bullet(self.rect.centerx, self.rect.bottom, "death-star_laser_final1.png", math.pi / 2, 0, 0)
        if current_time - self.last_shot > self.shoot_count and len(h_group) > 0 and not bullet.beam:
            shooting_sound = mixer.Sound(f'sounds/{self.sound}').play()
            shooting_sound.set_volume(volume)
            bullet_group.add(bullet)
            bullet.beam = True
        for sprite in bullet_group.sprites():
            if sprite.beam:
                sprite.update_laser_beam(self, 120, -40, -50)
                if current_time - self.last_shot > 1000:
                    self.last_shot = current_time

    def draw_health_bar(self, surface):
        red = (255, 0, 0)
        green = (0, 255, 0)
        pygame.draw.rect(surface, red, (self.rect.x + 125, self.rect.centery, 200, 10))
        pygame.draw.rect(surface, green, (self.rect.x + 125, self.rect.centery, int(200 * (self.lives / 500)), 10))

    def check_collision(self, h_group, game_score, spaceship, explosion_group, enemy_bullet_group, group):
        self.check_live(group, explosion_group)
        for bullet in enemy_bullet_group:
            explosion_small = Explosion(bullet.rect.centerx, bullet.rect.centery, 1)
            if pygame.sprite.collide_mask(self, bullet):
                explosion_group.add(explosion_small)
                bullet.kill()
                game_score += 1
                self.lives -= 1
        explosion_normal_size = Explosion(spaceship.rect.centerx, spaceship.rect.centery, 2)
        if pygame.sprite.collide_mask(self, spaceship):
            if not spaceship.shield_bool and len(h_group) > 0:
                h_group.sprites()[-1].kill()
                spaceship.lives -= 1
                explosion_group.add(explosion_normal_size)
        return game_score

    def check_live(self, group, explosion_group):
        explosion = Explosion(self.rect.centerx, self.rect.centery, 3)
        live_check_list = [450, 400, 350, 300, 250, 200, 150, 100, 50]
        for live in live_check_list:
            if self.lives == live and self.get_aliens:
                for enemy in range(2):
                    group.add(TieFighterLeft(-100, 0 + enemy * 200))
                for enemy in range(2):
                    group.add(TieFighterRight(900, 50 + enemy * 200))
                self.get_aliens = False
            if self.lives == live + 1:
                self.get_aliens = True
        if self.lives == 0:
            explosion_group.add(explosion)
            self.kill()


class TieFighter(Spaceships):
    def __init__(self, x, y, speed, list, plus_angle, direction, bullet_angle):
        self.index = 0
        lives = 2
        shoot_count = 800
        self.list = list
        image = list[self.index]
        cooldown = 800
        speed_y = 1
        sound = 'tie_shoot_better.mp3'
        super().__init__(image, speed, lives, shoot_count, x, y, cooldown, direction, sound, speed_y)
        self.plus_angle = plus_angle
        self.counter = 0
        self.angle = 0
        self.bullet_angle = bullet_angle

    def update_rotation(self):
        rotate_speed = 6  # wird für die länge des anzeigens eines Bildes verwendet
        self.counter += 1
        self.angle += self.plus_angle
        if self.counter >= rotate_speed and self.index < len(self.list) - 1:
            self.counter = 0
            self.index += 1
            self.image = pygame.image.load(self.list[self.index])
            self.image = pygame.transform.scale(self.image, (64, 64))
            self.image = pygame.transform.rotate(self.image, self.angle)

    def move(self, func, spaceship, surface, explosion_group, group):
        self.rect.x += self.speed
        self.rect.y += self.speed_y
        if 350 < self.rect.x <= 368:
            self.update_rotation()
            self.speed_y = - self.speed_y
        if not 1000 >= self.rect.x > -200:
            self.kill()

    def shoot(self, current_time, h_group, bullet_group, volume):
        if current_time - self.last_shot > self.shoot_count:
            shooting_sound = mixer.Sound(f'sounds/{self.sound}')
            shooting_sound.set_volume(volume)
            shooting_sound.play()
            bullet = Bullet(self.rect.centerx, self.rect.bottom, "death_star_laser1.png", math.pi / self.direction, 10,
                            self.bullet_angle)
            bullet_group.add(bullet)
            if current_time - self.last_shot > self.cooldown:
                self.last_shot = current_time

# shoot muss nicht verändert werden (soweit umschreiben!)
class TieFighterRight(TieFighter):
    def __init__(self, x, y):
        list = [f'tie_r/tie{1}.png',
                f'tie_r/tie{2}.png',
                f'tie_r/tie{3}.png',
                f'tie_r/tie{4}.png']
        speed = -2
        plus_angle = -4
        direction = -0.9
        bullet_angle = 110
        super().__init__(x, y, speed, list, plus_angle, direction, bullet_angle)


class TieFighterLeft(TieFighter):
    def __init__(self, x, y):
        list = [f'tie_l/tie{1}.png',
                f'tie_l/tie{2}.png',
                f'tie_l/tie{3}.png',
                f'tie_l/tie{4}.png']
        speed = 2
        plus_angle = 4
        direction = 4
        bullet_angle = 50
        super().__init__(x, y, speed, list, plus_angle, direction, bullet_angle)
#Menu Classes

import random

import pygame
from MotherClasses import Buttons, Window
from GameClasses import SpeedEnemy, BossSpaceship, NormalEnemy, Hearts
from Level3 import Endboss


# einzelne Buttons


class LevelButton(Buttons):
    def __init__(self):
        x = 200
        y = 200
        image = "rounded-rectangle.png"
        extra_image_sizex = 128
        extra_image_sizey = 128
        bg_image = "ray_shield.png"
        bgimage_sizex = 120
        bgimage_sizey = 70
        text = 'Levels'
        plus_vecx = 3
        plus_vecy = 30
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class HighScoreButton(Buttons):
    def __init__(self):
        x = 600
        y = 200
        image = "rounded-rectangle.png"
        extra_image_sizex = 128
        extra_image_sizey = 128
        bg_image = "ray_shield.png"
        bgimage_sizex = 120
        bgimage_sizey = 70
        text = 'Scores'
        plus_vecx = 3
        plus_vecy = 30
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class FastGame(Buttons):
    def __init__(self):
        x = 400
        y = 200
        image = "rounded-rectangle.png"
        extra_image_sizex = 100
        extra_image_sizey = 134
        bg_image = "play.png"
        bgimage_sizex = 100
        bgimage_sizey = 70
        text = 'Play'
        plus_vecx = 3
        plus_vecy = 30
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class ChooseLevelButtons(Buttons):
    def __init__(self, x, y):
        image = "rounded-rectangle.png"
        extra_image_sizex = 128
        extra_image_sizey = 128
        bg_image = "play.png"
        bgimage_sizex = 120
        bgimage_sizey = 70
        text = 'Level'
        plus_vecx = 3
        plus_vecy = 30
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class VolumeButton(Buttons):
    def __init__(self):
        x = 400
        y = 200
        image = "rect_vol.png"
        extra_image_sizex = 480
        extra_image_sizey = 60
        bg_image = "ray_shield2.png"
        bgimage_sizex = 480
        bgimage_sizey = 27
        text = 'volume'
        plus_vecx = 0
        plus_vecy = 18
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)
        self.volume = 1

    def draw(self, m_pos, surface):
        x, y = pygame.mouse.get_pos()
        print(x)
        surface.blit(self.bg_image, (self.rect.x + self.plus_vecx, self.rect.y + self.plus_vecy))
        if self.rect.collidepoint(m_pos) and x > self.rect.x and x < 631:
            self.bg_image = pygame.transform.scale(self.bg_image, (0 + x - self.rect.x, 27))
            self.volume = ((x - self.rect.x) / 480)
        self.draw_text(surface, 27, self.rect.x + 180, self.rect.y + 6, self.text)


class MenuWindow(Window):
    def __init__(self):
        caption = 'Menu'
        image = "menu_bg.png"
        window_open = True
        super().__init__(caption, image, window_open)
        self.level_button = LevelButton()
        self.high_score_button = HighScoreButton()
        self.fast_game_button = FastGame()
        self.settings_button = SettingsButton()
        pygame.mixer.init()
        self.group.add(self.level_button)
        self.group.add(self.high_score_button)
        self.group.add(self.fast_game_button)
        self.group.add(self.settings_button)

    def draw(self, m_pos):
        super().draw(m_pos)
        self.print_headline((320, 50))
        for sprite in self.group.sprites():
            sprite.draw_text(self.screen, 27, sprite.rect.x + 6, sprite.rect.y + 40, str(sprite.text))

    def update(self, m_pos, current_time, lvl_window, hs_window, menu_window, game_window, level_three_window,
               setting_window):
        for sprite in self.group.sprites():
            sprite.action = sprite.update(m_pos, menu_window, game_window, level_three_window, setting_window)
            if self.settings_button.action:
                self.window_open = self.change_screen_boolians(setting_window, self.settings_button)
            if self.level_button.action:
                self.window_open = self.change_screen_boolians(lvl_window, self.level_button)
            if self.high_score_button.action:
                self.window_open = self.change_screen_boolians(hs_window, self.high_score_button)

            if self.fast_game_button.action:
                for _ in range(5):
                    game_window.enemy_group.add(NormalEnemy(random.randint(0, 736), random.randint(-130, -60)))

                for _ in range(0):
                    game_window.enemy_group.add(SpeedEnemy(random.randint(0, 736), random.randint(-130, -60)))

                for _ in range(1):
                    game_window.enemy_group.add(BossSpaceship(random.randint(0, 736), 50))

                for heart in range(3):
                    hearts = Hearts(16 + heart * 16, 45)
                    game_window.heart_group.add(hearts)

                self.window_open = self.change_screen_boolians(game_window, self.fast_game_button)
                game_window.player_group.add(game_window.player_spaceship)
                game_window.player_spaceship.lives = 3
                game_window.player_spaceship.rect.x = 400
                game_window.player_spaceship.rect.y = 515
                game_window.player_spaceship.dead = False
                game_window.player_spaceship.z = True
                game_window.pause.action = False
                game_window.name_field.action = False


class SettingsWindow(Window):
    def __init__(self):
        caption = 'Settings'
        image = "setting_bg1.jpg"
        window_open = False
        super().__init__(caption, image, window_open)
        self.volume_button = VolumeButton()
        self.group.add(self.volume_button)
        self.group.add(self.back_button)

    def draw(self, m_pos):
        super().draw(m_pos)
        self.print_headline((270, 50))


class SettingsButton(Buttons):
    def __init__(self):
        x = 30
        y = 30
        image = "settings1.png"
        extra_image_sizex = 32
        extra_image_sizey = 32
        bg_image = "settings2.png"
        bgimage_sizex = 32
        bgimage_sizey = 32
        text = ''
        plus_vecx = 0
        plus_vecy = 0
        super().__init__(x, y, image, extra_image_sizex, extra_image_sizey, bg_image, bgimage_sizex, bgimage_sizey,
                         text, plus_vecx, plus_vecy)


class LevelWindow(Window):
    def __init__(self):
        caption = 'Levels'
        image = "level_bg.jpg"
        window_open = False
        super().__init__(caption, image, window_open)
        for levels in range(2):
            self.group.add(ChooseLevelButtons(300 + levels * 200, 300))
        self.group.add(self.back_button)

    def draw(self, m_pos):
        super().draw(m_pos)
        self.print_headline((290, 50))
        for sprite in self.group.sprites():
            sprite.draw(m_pos, self.screen)
            sprite.draw_text(self.screen, 24, sprite.rect.x + 10, sprite.rect.y + 39,
                             sprite.text + str(self.group.sprites().index(sprite) + 1))

    def update(self, m_pos, current_time, lvl_window, hs_window, menu_window, game_window, level_three_window,
               setting_window):
        super().update(m_pos, current_time, lvl_window, hs_window, menu_window, game_window, level_three_window,
                       setting_window)
        for sprite in self.group.sprites():
            sprite.action = sprite.update(m_pos, menu_window, game_window, level_three_window)
        if self.group.sprites()[1].action:
            self._window_setup(level_three_window, self.group.sprites()[1], Endboss)
        if self.group.sprites()[0].action:
            self._window_setup(game_window, self.group.sprites()[0], BossSpaceship)
            for _ in range(5):
                game_window.enemy_group.add(NormalEnemy(random.randint(0, 736), random.randint(-130, -60)))

            for _ in range(2):
                game_window.enemy_group.add(SpeedEnemy(random.randint(0, 736), random.randint(-130, -60)))

    def _window_setup(self, window, sprite, Enemy):
        window.window_open = True
        window.enemy_group.add(Enemy(300, -400))

        for heart in range(3):
            hearts = Hearts(16 + heart * 16, 45)
            window.heart_group.add(hearts)

        window.player_group.add(window.player_spaceship)
        window.player_spaceship.lives = 3
        window.player_spaceship.rect.x = 400
        window.player_spaceship.rect.y = 515
        window.player_spaceship.dead = False
        window.player_spaceship.z = True
        self.window_open = self.change_screen_boolians(window, sprite)


class HighScoreWindow(Window):
    def __init__(self):
        caption = 'High Score'
        image = "hs_bg.jpg"
        window_open = False
        super().__init__(caption, image, window_open)
        self.group.add(self.back_button)
        self.color = (105, 105, 105)

    def draw(self, m_pos):
        super().draw(m_pos)
        self.print_headline((320, 50))
        self.draw_table(self.screen)
        self.draw_text(self.screen)
        self.draw_high_score(self.screen)
        self.back_button.draw(m_pos, self.screen)

    def draw_table(self, surface):
        pygame.draw.rect(surface, self.color, (150, 150, 500, 310), 4)
        pygame.draw.line(surface, self.color, (150, 225), (649, 225), 4)
        pygame.draw.line(surface, self.color, (150, 300), (649, 300), 4)
        pygame.draw.line(surface, self.color, (150, 375), (649, 375), 4)
        pygame.draw.line(surface, self.color, (300, 150), (300, 455), 4)

    def draw_text(self, surface):
        font = pygame.font.Font('mainmenufont.ttf', 27)
        text = font.render('Points    Name', True, (255, 165, 1))
        surface.blit(text, (160, 195))

    def draw_high_score(self, surface):
        start_point = 250
        index = 0
        name_index = 0
        yellow = (255, 165, 1)
        with open('high_score', 'r') as file:
            lines = file.readlines()
            font = pygame.font.Font('mainmenufont.ttf', 27)
            for line in range(3):
                text = font.render(str(lines[index]), True, yellow)
                surface.blit(text, (180, start_point + line * 80))
                index += 1

        with open('names', 'r') as file:
            lines = file.readlines()
            for line in range(3):
                text = font.render(str(lines[name_index]), True, yellow)
                surface.blit(text, (325, start_point + line * 82))
                name_index += 1




Here is a Link to a video of my Game (as i recorded it a new problem came out: As the tie fighters in level 2 floght in the surface, the game breaks with this error:
File "C:\Users\melis\PycharmProjects\pythonProject1\Level3.py", line 61, in shoot
shooting_sound.set_volume(volume)
AttributeError: 'NoneType' object has no attribute 'set_volume'


https://mega.nz/file/nMBxlKyT#W7m3FaTE6H...0qkpAKQyb8
Reply
#6
A laser beam is not a bullet. They are fundamentally different. You should make a special class for the laser beam instead of adding a laser update method to bullet. That way you can let pygame groups take care of all the updating.

I did this in my original post with a line. This is how it would be done with an image.
import pygame


class Beam(pygame.sprite.Sprite):
    beam = pygame.image.load("beam.png")
    width = beam.get_width()

    def __init__(self, x, y, speed=20):
        super().__init__()
        self.rect = pygame.rect.Rect(x - self.width / 2, y, self.width, 0)
        self.speed = speed
        self.height = 600 - y

    def update(self):
        self.rect.height += self.speed
        if self.rect.height >= self.height:
            self.kill()
        else:
            # Scale beam image to approppriate size for sprite image
            self.image = pygame.transform.scale(self.beam, (self.rect.width, self.rect.height))


pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((200, 400))
beams = pygame.sprite.Group()
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            beams.add(Beam(*event.pos))
    screen.fill("black")
    beams.update()
    beams.draw(screen)
    pygame.display.flip()
    clock.tick(30)
About your shooting sound volume problem, I found this:

https://stackoverflow.com/questions/6640...eturn-none

When I saw the error message I assumed the problem was caused by play() returning None, but I did not know why, nor find why, that might happen. The pygame mixer documentation says the sound will not play if there is no channel available, but I could not find where it said it will return None when this happens.

The short answer is that you'll have to check the return value from play() before you try to set_volume() (or you can catch the exception).
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020