Пример #1
0
class AsteroidsGame:
    def setup(self, startWindow=None, playerName=None):
        self.params = GameParams()  # To be filled by user input

        # Set up scorekeeping
        self.score = 0
        self.scoreKeeper = ScoreKeeper()
        self.scoreKeeper.setFile('asteroidScore.txt')

        # Set up window
        width = 800
        height = 600
        font = sf.Font.from_file("rust.ttf")
        self.params.setFont(font)

        if startWindow is None:
            # startWindow is None unless this is a restart
            startWindow = sf.RenderWindow(sf.VideoMode(width, height),
                                          "Asteroids")
            startWindow.framerate_limit = 60
            startWindow.clear(sf.Color.BLACK)

            #Display Welcome
            welcomeText = utils.drawText(startWindow,
                                         string="Asteroids",
                                         size=60,
                                         font=font,
                                         position='center')
            startWindow.display()

        # Wait for any input
        while (True):
            setup = False
            for event in startWindow.events:
                if type(event) is sf.CloseEvent:
                    exit()
                elif (type(event) is sf.MouseButtonEvent
                      or type(event) is sf.KeyEvent):
                    setup = True
            if setup:
                break

        # Select Player Name
        if playerName is None:
            playerName = utils.textInput(startWindow,
                                         "Enter Name:",
                                         font,
                                         maxLength=10)
        self.params.setPlayerName(playerName.lower())

        #Choose Difficulty
        difficulty = utils.selectOptions(startWindow,
                                         ["Easy", "Medium", "Hard"], [0, 1, 2],
                                         font)
        makeTimes = [20, 15, 12]
        timeModifiers = [0.98, 0.95, 0.92]
        self.params.setDifficulty(difficulty)
        self.timeToMakeAsteroid = makeTimes[difficulty]
        self.makeTimeModifier = timeModifiers[difficulty]
        self.lastAsteroidTime = time.time() - self.timeToMakeAsteroid

        self.timeToMakePowerup = 20
        self.lastPowerupTime = time.time() - self.timeToMakePowerup
        self.powerupProbability = 1 / 600

        # Set up Board
        self.board = Board(title="Asteroids", width=700, height=700)

        # Set up Ship
        self.ship = Ship(position=(self.board.getBoundary()[0] / 2,
                                   self.board.getBoundary()[1] / 2))
        self.ship.setWrapping(True)
        self.ship.setBoundary(self.board.getBoundary())

        startWindow.close()

    def endGame(self):
        gameOverText = utils.drawText(self.board.window,
                                      string="Game Over",
                                      font=self.params.font,
                                      size=60,
                                      position='center',
                                      color=sf.Color.RED)

        oldScore = self.scoreKeeper.checkScore(self.params.playerName,
                                               self.params.getDifficulty())
        scoreTextYPosition = gameOverText.position[
            1] + gameOverText.local_bounds.height + 10

        if self.score > oldScore:
            # display a "New Highscore" screen
            self.scoreKeeper.setScore(self.params.playerName, self.score,
                                      self.params.getDifficulty())

            utils.drawText(self.board.window,
                           string="New High Score! {}".format(self.score),
                           font=self.params.font,
                           size=30,
                           position='center',
                           yposition=scoreTextYPosition,
                           color=sf.Color.GREEN)
        else:
            # Display the old highscore
            utils.drawText(self.board.window,
                           string="High Score: {}".format(oldScore),
                           font=self.params.font,
                           size=30,
                           position='center',
                           yposition=scoreTextYPosition,
                           color=sf.Color.WHITE)

        utils.drawText(self.board.window,
                       string="Press ENTER to Relplay",
                       font=self.params.font,
                       size=15,
                       position='center',
                       yposition=self.board.window.height - 20,
                       color=sf.Color.WHITE)

        self.board.window.display()
        while (True):
            for event in self.board.window.events:
                if (type(event) is sf.CloseEvent
                        or (type(event) is sf.KeyEvent
                            and event.code is sf.Keyboard.ESCAPE)):
                    exit()
                if (type(event) is sf.KeyEvent
                        and event.code is sf.Keyboard.RETURN):
                    # Reset
                    self.setup(self.board.window, self.params.getPlayerName())
                    self.playGame()

    def _generateAsteroid(self, asteroidManager, velocityLimit=2):
        if (time.time() - self.lastAsteroidTime >= self.timeToMakeAsteroid):
            self.lastAsteroidTime = time.time()
            self.timeToMakeAsteroid *= self.makeTimeModifier  #make asteroids appear faster as time progresses

            # Generate beyond the border so it doesn't appear in middle of screen
            # random velocity will make it appear evenly on either side
            position = (random.uniform(-20, 0), random.uniform(-20, 0))
            velocity = (random.uniform(-velocityLimit, velocityLimit),
                        random.uniform(-velocityLimit, velocityLimit))
            asteroid = Asteroid(4,
                                position,
                                velocity,
                                wrapping=True,
                                boundary=self.board.getBoundary())
            asteroidManager.addObject(asteroid)

    def _generatePowerup(self, powerupManager, velocityLimit=2):
        if ((time.time() - self.lastPowerupTime >= self.timeToMakePowerup)
                and random.random() < self.powerupProbability):

            typeNum = random.randint(0, 2)
            typeNames = ["cooldown", "agility", "acceleration"]
            typeColors = [sf.Color.BLUE, sf.Color.GREEN, sf.Color.YELLOW]

            # Lots of calculations to make it start evenly on any side of the board
            # and ensure that it moves across the board no matter where it starts
            positionX = None
            positionY = None
            velocityX = None
            velocityY = None
            boundary = self.board.getBoundary()
            if random.random() < 0.5:
                positionX = random.uniform(-20, 0)
            else:
                positionX = random.uniform(boundary[0], boundary[0] + 20)
            if random.random() < 0.5:
                positionY = random.uniform(-20, 0)
            else:
                positionY = random.uniform(boundary[0], boundary[0] + 20)

            if (positionX < 0):
                velocityX = random.uniform(0, velocityLimit)
            else:
                velocityX = random.uniform(-velocityLimit, 0)
            if (positionY < 0):
                velocityY = random.uniform(0, velocityLimit)
            else:
                velocityY = random.uniform(-velocityLimit, 0)

            velocity = (velocityX, velocityY)
            position = (positionX, positionY)
            powerup = Powerup(position=position,
                              velocity=velocity,
                              color=typeColors[typeNum],
                              powerupType=typeNames[typeNum])
            powerupManager.addObject(powerup)
            self.lastPowerupTime = time.time()

    def playGame(self):
        self.board.window.clear(sf.Color.BLACK)
        self.ship.draw(self.board.window)
        self.board.displayBoard()

        play = False
        while not play:
            for event in self.board.window.events:
                if type(event) is sf.CloseEvent:
                    exit()
                elif (type(event) is sf.KeyEvent):
                    play = True

        bulletManager = ObjectManager(cleanSize=10)
        asteroidManager = ObjectManager(cleanSize=10)
        powerupManager = ObjectManager(cleanSize=5)

        while (True):
            self.board.window.clear(sf.Color.BLACK)

            self._generateAsteroid(asteroidManager)
            self._generatePowerup(powerupManager)

            # Input handler
            for event in self.board.window.events:
                if type(event) is sf.CloseEvent:
                    exit()
                if type(
                        event
                ) is sf.KeyEvent and event.code is sf.Keyboard.SPACE and event.pressed:
                    bullet = self.ship.shootBullet(
                        boundary=self.board.getBoundary())
                    if bullet:
                        bulletManager.addObject(bullet)
            if sf.Keyboard.is_key_pressed(sf.Keyboard.RIGHT):
                self.ship.turnRight()
            if sf.Keyboard.is_key_pressed(sf.Keyboard.UP):
                self.ship.accelerate()
            if sf.Keyboard.is_key_pressed(sf.Keyboard.LEFT):
                self.ship.turnLeft()

            # Move and draw bullets
            for i in range(bulletManager.getLength()):
                bullet = bulletManager.getItem(i)
                bullet.move()
                bullet.draw(self.board.window)

            # Move and draw Asteroids
            for i in range(asteroidManager.getLength()):
                asteroid = asteroidManager.getItem(i)
                asteroid.move()
                asteroid.draw(self.board.window)

            # Move and draw Powerups
            for i in range(powerupManager.getLength()):
                powerup = powerupManager.getItem(i)
                powerup.move()
                powerup.draw(self.board.window)

            # Move and draw Ship
            self.ship.moveForward()
            self.ship.draw(self.board.window)

            # Check for collisions
            newAsteroids = []
            for i in reversed(range(asteroidManager.getLength())):
                asteroid = asteroidManager.getItem(i)
                # Asteroid-Ship collision
                if (self.ship.circleTriangleCollision(asteroid.getShape())):
                    self.endGame()

                for j in reversed(range(bulletManager.getLength())):
                    bullet = bulletManager.getItem(j)
                    # if collision: break asteroid
                    if asteroid.didCollide(bullet):
                        self.score += 1
                        if asteroid.breakAsteroid():
                            for newAsteroid in asteroid.breakAsteroid():
                                newAsteroids.append(newAsteroid)
                        bulletManager.removeIndex(j)
                        asteroidManager.removeIndex(i)
                        break
            asteroidManager.addObjects(newAsteroids)

            # Check for powerup collisions
            for i in reversed(range(powerupManager.getLength())):
                powerup = powerupManager.getItem(i)
                if self.ship.circleTriangleCollision(powerup.getShape()):
                    power = powerup.getType()
                    if power == "acceleration":
                        oldAcc = self.ship.getAcceleration()
                        self.ship.setAcceleration(1.1 * oldAcc)
                    elif power == "cooldown":
                        oldCool = self.ship.getCooldown()
                        self.ship.setCooldown(0.9 * oldCool)
                    elif power == "agility":
                        oldSpeed = self.ship.getRotateSpeed()
                        self.ship.setRotateSpeed(1.1 * oldSpeed)
                    powerupManager.removeIndex(i)

            self._drawScore(self.board.window)

            self.board.window.display()

    def _drawScore(self, window):
        if hasattr(self, 'scoreText'):
            self.scoreText.string = str(self.score)
        else:
            self.scoreText = utils.drawText(window,
                                            size=25,
                                            font=self.params.font,
                                            string=str(self.score))
        window.draw(self.scoreText)
Пример #2
0
class Asteroids(Game):
    """
    Asteroids extends the base class Game to provide logic for the specifics of the game
    """
    def __init__(self, name, width, height):
        super().__init__(name, width, height)
        self.ship = Ship()
        self.asteroids = []
        self.stars = []
        self.screen = pygame.display.set_mode((self.width, self.height))
        self.max_num_asteroids = 5
        self.current_level = 1
        self.new_level = True
        self.timer = 0
        self.state = "startmenu"
        self.background_image = self.image_handle()
        self.buttons = []
        self.highscore = Highscoreboard()
        self.newhighscore = False
        self.score = 0
        self.timer_ship_alien_collide = 0
        self.is_alien = False
        self.alien = Alien(self.ship.position.x + 300, HEIGHT - 40)
        self.sound = True
        self.testing()

    def testing(self):
        if TEST_LASTLEVEL:
            self.current_level = 5
            self.check_max_asteroids()
        if TEST_HIGHSCORE:
            self.score = (self.highscore.get_min_score() + 10)
            self.ship.life = 1
            self.ship.lifebar = "{}".format("♥") * self.ship.life
        if TEST_GAMEOVER:
            self.ship.life = 0
            self.ship.lifebar = "{}".format("♥") * self.ship.life
        if TEST_VICTORY:
            self.current_level = 5
            self.max_num_asteroids = 0

    def image_handle(self):
        if self.state == "startmenu":
            return pygame.image.load("menu.jpg").convert()
        if self.state == "gameover":
            return pygame.image.load("gameover.png").convert()
        if self.state == "menuoption":
            return pygame.image.load("help.jpg").convert()
        if self.state == "victory":
            return pygame.image.load("victory.jpg").convert()
        else:
            return False

    def handle_input(self):
        super().handle_input()
        keys_pressed = pygame.key.get_pressed()
        if self.state == "playing":
            if keys_pressed[K_s]:
                self.ship.activate_shield()
            if keys_pressed[K_p]:
                self.state = "paused"
            if keys_pressed[K_SPACE]:
                if pygame.time.get_ticks() > self.timer:
                    pygame.mixer.Channel(1).play(shoot_sound)
                    self.timer = pygame.time.get_ticks() + 300
                    if len(self.ship.bullets) >= 5:
                        self.ship.bullets.clear()
                    self.ship.bullets.append(
                        Bullet(self.ship.position, self.ship.rotation))
            if keys_pressed[K_LEFT] and self.ship:
                self.ship.rotate(-0.6)
                if self.ship.shield_activated:
                    self.ship.shield.rotate(-0.6)
            if keys_pressed[K_RIGHT] and self.ship:
                self.ship.rotate(0.6)
                if self.ship.shield_activated:
                    self.ship.shield.rotate(0.6)
            if keys_pressed[K_UP] and self.ship:
                self.ship.accelerate(0.003)
                if self.ship.shield_activated:
                    self.ship.shield.accelerate(0.003)
            if keys_pressed[K_DOWN] and self.ship:
                self.ship.accelerate(0)
                if self.ship.shield_activated:
                    self.ship.shield.accelerate(0)

        if keys_pressed[K_r] and self.state in {"playing", "gameover"}:
            self.restart_game()

        if self.state == "paused":
            if keys_pressed[K_SPACE]:
                self.state = "playing"
            if keys_pressed[K_r]:
                pygame.mixer.music.stop()
                self.state = "startmenu"

        if keys_pressed[K_RETURN] and self.state == "menuoption":
            pygame.mixer.music.stop()
            self.state = "startmenu"

        if self.state == "middlescreen":
            if keys_pressed[K_c]:
                self.new_level = True
                self.current_level += 1
                self.check_max_asteroids()
                self.state = "playing"

    def restart_game(self):
        self.ship.life = 5
        self.ship.lifebar = "{}".format("♥") * self.ship.life
        self.max_num_asteroids = 5
        self.score = 0
        self.current_level = 1
        self.new_level = True
        self.is_alien = False
        self.state = "playing"
        self.newhighscore = False

    def calc_distance(self, p, q):
        return math.sqrt((p.x - q.x)**2 + (p.y - q.y)**2)

    def collision_handle(self):
        transform_asteroid = False
        #if you shoot
        if len(self.ship.bullets) > 0:
            for bullet in self.ship.bullets:
                for asteroid in self.asteroids:
                    if (self.calc_distance(bullet.position,
                                           asteroid.position) < 70
                            and asteroid.size == "big") or (self.calc_distance(
                                bullet.position, asteroid.position) < 30):
                        if asteroid.explode():
                            self.asteroids.remove(asteroid)
                            self.score += 10
                        else:
                            transform_asteroid = True
                            newsize = asteroid.get_size()
                            position = asteroid.position
                            self.asteroids.remove(asteroid)
                            self.score += 5

                        if bullet in self.ship.bullets:
                            self.ship.bullets.remove(bullet)

        if transform_asteroid:
            self.asteroids.extend((self.CreateAsteroid(position, newsize),
                                   self.CreateAsteroid(position, newsize)))

        #if the ship and an astreoid collides
        if len(self.asteroids) > 0 and self.ship.life > 0:
            for asteroid in self.asteroids:
                if self.calc_distance(
                        self.ship.position, asteroid.position
                ) < 70 and asteroid.size == "big" or self.calc_distance(
                        self.ship.position, asteroid.position) < 30:
                    asteroid.explode()
                    self.asteroids.remove(asteroid)
                    self.ship.collide()
                    if not self.ship.shield_activated:
                        self.ship.lifebar = self.ship.lifebar[:-1]

    def CreateAsteroid(self, pos, size):
        if pos == "random":
            x = random.randint(0, 600)
            y = random.randint(0, 430)

            while self.calc_distance(Point(x, y), self.ship.position) < 80:
                x = random.randint(0, 600)
                y = random.randint(0, 430)
        else:
            x = pos.x
            y = pos.y

        rotation = random.randint(0, 5)
        point_x = random.uniform(-0.001, 0.5)
        point_y = random.uniform(-0.001, 0.5)
        angular_velocity = random.uniform(0.1, 0.8)

        if size == "medium":
            points = MEDIUM_ASTEROID
        elif size == "small":
            points = SMALL_ASTEROID
        else:
            points = BIG_ASTEROID

        return Astreoid(points, x, y, rotation, Point(point_x, point_y),
                        angular_velocity, size)

    def spawn_asteroids(self):
        sizes = ["small", "medium", "big"]

        if self.new_level:
            self.asteroids.clear()
            for i in range(0, self.max_num_asteroids):
                size = sizes[random.randint(0, 2)]
                self.asteroids.append(self.CreateAsteroid("random", size))
                self.new_level = False

    def show_lifebar(self):
        self.ship.show_lifebar(self.screen)
        if self.is_alien:
            self.alien.show_lifebar(self.screen)

    def shield_bar(self):
        pygame.draw.rect(self.screen, (LIFEBARBLUE),
                         (10, 50, self.ship.shield.health, 20), 0)

        if not self.ship.shield_activated:
            if pygame.time.get_ticks(
            ) > self.ship.shield.timer and not self.ship.shield.health == 200:
                self.ship.shield.timer = pygame.time.get_ticks() + 190
                pygame.draw.rect(self.screen, (0, 102, 102),
                                 (10, 50, self.ship.shield.health, 20), 0)
                self.ship.shield.health += 5

        pygame.draw.rect(self.screen, (WHITE), (8, 48, 204, 24), 1)

    def death_handler(self):
        self.highscorecheck()
        name = ""
        output = "INPUT YOUR INITIALS"
        if self.newhighscore == False:
            self.background_image = self.image_handle()
            self.screen.blit(self.background_image, [0, 0])
            self.screen.blit(respawn, (250, 100))
        else:
            pygame.mixer.music.stop()
            # while not self.highscore.right_lenght_string(name):
            name = self.highscore.ask_for_input(self.screen, output)
            # output = "MUST BE 3 LETTERS OR CHARACTERS"
            self.highscore.newname = name.upper()
            self.highscore.newscore = self.score
            self.highscore.update_board()
            self.highscore.printboard(self.screen)
            self.state = "menuoption"

    def check_max_asteroids(self):
        if self.current_level == 1:
            self.max_num_asteroids = 5
        elif self.current_level == 2:
            self.max_num_asteroids = 10
        elif self.current_level == 3:
            self.max_num_asteroids = 15
        elif self.current_level == 4:
            self.max_num_asteroids = 20
        elif self.current_level == 5:
            self.max_num_asteroids = 20
            self.is_alien = True

    def highscorecheck(self):
        if self.score > self.highscore.get_min_score():
            self.newhighscore = True

    def next_level_check(self):
        if len(self.asteroids) == 0 and not self.state == "gameover":
            if self.current_level == 5:
                self.state = "victory"
                pygame.display.flip()
                self.screen.blit(self.image_handle(), [0, 0])
                self.screen.blit(victory_text, (230, 200))
            else:
                self.state = "middlescreen"
                self.screen.fill(BLACK)
                self.screen.blit(next_level_text, (120, 200))
                self.screen.blit(continue_text, (120, 240))

    def spawn_stars(self):
        if self.new_level:
            self.stars.clear()
        if len(self.stars) < 100 and not self.ship.life == 0:
            self.stars.append(Star())

    def print_score_and_level(self):
        score_text = pygame.font.SysFont(myfont,
                                         20).render("Score:" + str(self.score),
                                                    1, WHITE)
        stage_text = pygame.font.SysFont(myfont, 20).render(
            "Stage:" + str(self.current_level), 1, WHITE)
        self.screen.blit(score_text, (700, 10))
        self.screen.blit(stage_text, (700, 25))

    def start_menu(self):
        self.screen.fill(BLACK)
        self.background_image = self.image_handle()
        self.screen.blit(self.background_image, [0, 0])
        self.screen.blit(welcome_text, (300, 70))
        self.screen.blit(welcome_text_two, (240, 120))
        self.buttons.extend((start_button, options_button, quit_button,
                             help_button, highscore_button))
        for b in self.buttons:
            b.draw(self.screen)

    def paused(self):
        self.screen.blit(return_text, (180, 200))
        self.screen.blit(start_text, (215, 240))
        self.screen.blit(pause_text, (335, 100))

    def bhelp(self):
        self.background_image = self.image_handle()
        self.screen.blit(self.background_image, [0, 0])

    def runGame(self):
        super().runGame()

    def life_check(self):
        if self.ship.life == 0:
            self.state = "gameover"

    def update_simulation(self):
        """
        update_simulation() causes all objects in the game to update themselves
        """
        super().update_simulation()
        if self.ship:
            self.ship.update(self.width, self.height)
            if self.ship.shield_activated:
                self.ship.shield.update(self.width, self.height)
        for asteroid in self.asteroids:
            asteroid.update(self.width, self.height)
        for star in self.stars:
            star.update(self.width, self.height)
        for bullets in self.ship.bullets:
            bullets.update(self.width, self.height)
        if self.is_alien:
            self.alien.alien_in_game(self.ship, self.width, self.height,
                                     self.screen)
            for bullets in self.alien.bullets:
                bullets.update(self.width, self.height)
            if self.alien.life == 0:
                self.is_alien = False

    def handle_state(self):
        if self.state == "gameover":
            self.death_handler()
        if self.state == "playing":

            self.screen.fill(BLACK)
            self.life_check()
            self.spawn_stars()
            self.spawn_asteroids()
            self.collision_handle()
            self.next_level_check()
            self.print_score_and_level()
            self.show_lifebar()

        if self.state == "paused":
            self.paused()
        elif self.state == "startmenu":
            self.start_menu()
        for event in pygame.event.get():
            for button in self.buttons:
                if 'click' in button.handleEvent(event):
                    if button._propGetCaption() == "QUIT":
                        self.running = False
                    if button._propGetCaption() == "START":
                        if self.sound:
                            pygame.mixer.music.play(-1)
                        self.state = "playing"
                    if button._propGetCaption() == "OPTIONS":
                        self.state = "menuoption"
                    if button._propGetCaption() == "HELP":
                        self.state = "menuoption"
                        self.bhelp()
                    if button._propGetCaption() == "HIGHSCORE":
                        self.state = "menuoption"
                        self.highscore.printboard(self.screen)

    def render_objects(self):
        """
        render_objects() causes all objects in the game to draw themselves onto the screen
        """
        super().render_objects()
        # Render the ship:
        if self.state == "playing":
            if self.ship.shield_activated:
                self.ship.shield.draw(self.screen)
            self.ship.draw(self.screen)
            self.shield_bar()
            # Render all the stars, if any:
            for star in self.stars:
                star.draw(self.screen)
                # Render all the asteroids, if any:
            for asteroid in self.asteroids:
                asteroid.draw(self.screen)
                # Render all the bullet, if any:
            for bullet in self.ship.bullets:
                bullet.draw(self.screen)
            if self.is_alien:
                self.alien.draw(self.screen)
                for bullet in self.alien.bullets:
                    bullet.draw_a(self.screen)
                    if bullet.position.x >= self.width - 5 or bullet.position.y >= self.height - 5:
                        self.alien.bullets.remove(bullet)