def update(self, t=0, v=None):
        """ update render position (velocity is vector in OpenGL style coorinates/timestep)"""
        # if update() has not been run, set time_since_update to current time
        Sprite.update(self, t=t, v=v)

        p1, p2 = self.position_current
        if self.use_polar_coords:
            x, y = pol2cart(p1, p2)
        else:
            x, y = (p1, p2)
        sz = self.size
        th = self.thickness
        self.vertices = [  # horizontal beam
            (x - sz / 2.0, y + th / 2),  # left-top
            (x - sz / 2.0, y - th / 2),  # left-bottom
            (x + sz / 2.0, y - th / 2),  # right-bottom
            (x + sz / 2.0, y + th / 2),  # right-top
            # vertical beam
            (x - th / 2, y + sz / 2.0),  # left-top
            (x - th / 2, y - sz / 2.0),  # left-bottom
            (x + th / 2, y - sz / 2.0),  # right-bottom
            (x + th / 2, y + sz / 2.0),  # right-top
        ]
        self.t_since_update = t  # set time_since_update to current time
예제 #2
0
class MainMenuLocation(_Location):
    def __init__(self, parent):
        super().__init__(parent)
        self.bg = Sprite(
            0,
            0,
            image=pygame.image.load("assets/misc/mainMenu.png").convert(),
            size=c.sizes["win"])
        pygame.mixer.music.load("assets/audio/Intro.mp3")
        pygame.mixer.music.play(-1)
        self.play_button = Button(
            c.pads["play"],
            pygame.image.load("assets/misc/start.png").convert_alpha(),
            pygame.image.load(
                "assets/misc/startHighlight.png").convert_alpha())
        self.exit = Button(
            c.pads["exit"],
            pygame.image.load("assets/misc/potQuit.png").convert(),
            pygame.image.load("assets/misc/potQuitHighlight.png").convert())

    def update(self):
        mouse_pos = pygame.mouse.get_pos()

        self.bg.update(self.screen)
        self.play_button.update(self.screen, mouse_pos)
        self.exit.update(self.screen, mouse_pos)

    def event(self, event):
        mouse_pos = pygame.mouse.get_pos()
        if event.type == MOUSEBUTTONUP and event.button == 1:
            if self.play_button.click(mouse_pos):
                from .chooseYourPlants import LevelPreparationLocation
                self.parent.change_location(
                    LevelPreparationLocation(self.parent))
            if self.exit.click(mouse_pos):
                sys.exit()
예제 #3
0
class TopMenu:
    """
    Class for handling menu on the top
    Which includes sun score indicator
    Plant card choices
    And shovel
    """
    def __init__(self, cards: list = None, pos: int = 100):
        if cards is None:
            cards = []
        # TODO добавить остальные цифры
        # Digits for sun display
        self.digits = {
            str(n): pygame.image.load(f"assets/misc/{n}.png").convert_alpha()
            for n in range(10)
        }
        # Main frame
        self.frame = Sprite(
            pos,
            0,
            image=pygame.image.load("assets/misc/topmenu.png").convert_alpha(),
            size=c.sizes["topmenu"])
        # Positions cards
        self.cards = pygame.sprite.Group()
        self.x = c.pads["sun"][0] + (c.pads["menubar"][0]
                                     if self.get_preparing() else 0)
        self.starting_x = self.x
        for card in cards:
            image = pygame.image.load(
                f"assets/cards/card{card.__name__}.png").convert()
            s = Card(self.x, card, image=image, size=c.sizes["card"])
            self.cards.add(s)
            self.x += c.sizes["card"][0] + c.pads["cards"]

        self.shovel = Shovel(c.sizes["topmenu"][0] + c.pads["menubar"][0], 0)

    def update(self, screen, sun: int):
        """
        Updates all parts of the interface
        :param screen: Surface
        :param sun: sun count int
        :return: None
        """
        self.frame.update(screen)
        self.cards.update(screen,
                          sun if self.get_preparing() else float("inf"))

        score_digits = list(map(lambda d: self.digits[d], str(sun)))
        digit_widths = list(map(lambda i: i.get_width(), score_digits))

        offset = (c.pads["sun"][0] - sum(digit_widths)) // 2 + (
            c.pads["menubar"][0] if self.get_preparing() else 0)
        for image, width in zip(score_digits, digit_widths):
            screen.blit(image, (offset, c.pads["sun"][1]))
            offset += width
        if self.get_preparing() and not self.shovel.taken:
            self.shovel.update(screen)

    def choose_card(self, mouse_pos: tuple, previous_choice: type or Shovel,
                    suns: int) -> type or None:
        """
        Checks mouse position on intersections with cards
        Changes choice or deletes it if clicked the same card
        :param mouse_pos: (x, y)
        :param previous_choice: plant type
        :param suns: int - checks if player can currently afford this plant
        :return: plant type or None
        """
        if self.shovel.can_take(mouse_pos):
            if previous_choice.__class__.__name__ == "Shovel":
                previous_choice.put_back()
                return None
            return self.shovel.take()

        for card in self.cards:
            if card.rect.collidepoint(mouse_pos):
                choice = card.choose()
                # Last choice deletion
                if choice == previous_choice:
                    return None
                if previous_choice.__class__.__name__ == "Shovel":
                    previous_choice.put_back()
                if suns >= choice.sunCost:
                    return choice
        return previous_choice

    def add_card(self, plant: type):
        """
        Adds card during the preparation state
        :param plant: Plant
        :return: None
        """
        if len(self.cards) > 5:
            return
        if any(filter(lambda card: card.plant == plant, self.cards)):
            return
        s = Card(self.x,
                 image=pygame.image.load(
                     f"assets/cards/card{plant.__name__}.png").convert(),
                 size=c.sizes["card"],
                 plant=plant)
        self.x += c.sizes["card"][0] + c.pads["cards"]
        self.cards.add(s)

    def remove_card(self, mouse_pos: tuple):
        """
        Removes clicked card and moves other to the left
        :param mouse_pos: (x, y)
        :return: None
        """
        for card in self.cards:
            if card.rect.collidepoint(mouse_pos):
                card.sound.play()
                self.cards.remove(card)
                # Reposition cards
                x = self.starting_x
                for card in self.cards:
                    card.rect.x = x
                    x += c.sizes["card"][0] + c.pads["cards"]
                self.x = x
                return

    def move_right(self):
        """
        After removing card all cards need to be moved left
        To remove gap
        :return: None
        """
        dx = c.pads["menubar"][0]

        self.x += dx
        for card in self.cards:
            card.rect.x += dx
        self.frame.rect.x += dx

    def lock_card(self, plant: type):
        """
        After planting player have to wait until he can use plant again
        :param plant: Plant
        :return: None
        """
        for card in self.cards:
            if card.plant == plant:
                card.set_timer()

    def get_preparing(self) -> bool:
        """
        Check where widget if located
        :return: bool
        """
        return self.frame.rect.x == 100
예제 #4
0
class PlantChoiceMenu:
    def __init__(self, cards):
        self.frame = Sprite(
            0,
            c.sizes["topmenu"][1],
            image=pygame.image.load(
                "assets/misc/chooseYourPlants.png").convert_alpha(),
            size=c.sizes["choose"])
        self.button_images = list(
            map(lambda i: pygame.transform.smoothscale(i, c.sizes["letsRock"]),
                [
                    pygame.image.load(
                        "assets/misc/letsRock.png").convert_alpha(),
                    pygame.image.load(
                        "assets/misc/letsRockHighlight.png").convert_alpha()
                ]))
        self.button = Sprite(158, 568, image=self.button_images[0])

        self.cards = pygame.sprite.Group()
        self.x = c.pads["choose"][0]
        self.starting_x = self.x
        y = c.pads["choose"][1]
        _c = 0
        for card in cards:
            _c += 1
            image = pygame.image.load(
                f"assets/cards/card{card.__name__}.png").convert()
            s = Card(self.x, card, image=image, size=c.sizes["card"], y=y)
            self.cards.add(s)
            self.x += c.sizes["card"][0] + 2
            if _c % 7 == 0:
                self.x = self.starting_x
                y += c.sizes["card"][1] + 5

    def update(self, screen, mouse_pos):
        """
        :param screen: Surface
        :param mouse_pos: (x, y)
        :return:
        """
        # Marks the Let's Rock button if mouse collides with it
        if self.button.rect.collidepoint(mouse_pos):
            self.button.image = self.button_images[1]
        else:
            self.button.image = self.button_images[0]

        self.frame.update(screen)
        self.button.update(screen)
        self.cards.update(screen, float("inf"))

    def choose_card(self, mouse_pos: tuple) -> type:
        """
        Checks mouse position on intersections with cards
        Returns choice or None
        :param mouse_pos: (x, y)
        :return: plant type or None
        """
        for card in self.cards:
            if card.rect.collidepoint(mouse_pos):
                choice = card.choose()
                return choice

    def button_click(self, mouse_pos: tuple) -> bool:
        return self.button.rect.collidepoint(mouse_pos)
예제 #5
0
파일: gameLocation.py 프로젝트: yeya24/PvZc
class GameLocation(_Location):
    def __init__(self, parent, top_menu):
        super().__init__(parent)
        # Game interface
        self.plant_choice = self.plant_choice_image = None
        self.suns = c.starting_sun + 10000
        # Sprite groups for different game objects
        self.suns_group = pygame.sprite.Group()
        self.zombies = pygame.sprite.Group()
        self.projectiles = pygame.sprite.Group()
        self.lawnmovers = [LawnMower(row) for row in range(5)]

        # Background is a sprite for easier drawing
        self.background = Sprite(
            0,
            0,
            image=pygame.image.load("assets/misc/sm_bg.png").convert_alpha(),
            size=c.sizes["win"])
        # Menu with plant choices, shovel and suns count indication
        self.menubar = top_menu
        # Creating game field
        self.cells = []
        for y in range(c.YCells):
            grid_row = []
            for x in range(c.XCells):
                tile = Grass(x, y)
                grid_row.append(tile)
            self.cells.append(grid_row)

        # Adds event of falling sun for every sun_drop_delay seconds
        pygame.time.set_timer(USEREVENT + 1, c.sun_drop_delay * 1000)
        # Music
        pygame.mixer_music.load("assets/audio/grasswalk.mp3")
        pygame.mixer.music.set_volume(0.75)
        pygame.mixer_music.play(loops=-1)

        self.zombies.add(NormalZombie(0))
        self.zombies.add(BucketHeadZombie(1))

    def update(self):
        self.background.update(self.screen)
        self.menubar.update(self.screen, self.suns)

        x, y = pygame.mouse.get_pos()
        # Draws from right to left
        for row in self.cells:
            for cell in reversed(row):
                cell.update(self.screen)
                # Transparent image of chosen plant
                if cell.isempty() and self.plant_choice is not None \
                        and cell.rect.collidepoint((x, y)) and \
                        self.plant_choice.__class__.__name__ != "Shovel":
                    # In the middle of the cell
                    self.screen.blit(
                        transform_image(self.plant_choice_image),
                        cell.get_middle_pos(self.plant_choice_image))
        self.lawnmowers_update()
        # Start drawing from right top
        for zombie in sorted(self.zombies.sprites(),
                             key=lambda z: z.row * c.XCells + z.col):
            zombie.update(self.screen)
        self.zombie_targeting()
        # Draw choice near the mouse
        if self.plant_choice is not None:
            self.screen.blit(self.plant_choice_image,
                             (x - self.plant_choice_image.get_width() / 2,
                              y - self.plant_choice_image.get_height()))

        self.projectiles.update(self.screen)
        self.projectile_collisions_check()
        self.suns_group.update(self.screen)

    def event(self, event):
        """
        Responds to game events
        :param event: pygame.event
        :return: None
        """
        # Drop sun
        if event.type == USEREVENT + 1:
            self.drop_sun()

        elif event.type == MOUSEBUTTONUP and event.button == 1:
            x, y = pygame.mouse.get_pos()
            # Check order:
            # 1. Player clicked on a sun
            # 2. Player has chosen anything on the top menu
            # 3. Player planted plant / removed one using shovel

            # Suns check
            for sun in self.suns_group:
                if sun.check_collision((x, y)):
                    sun.fly()
                    self.suns += 25
                    return

            # Top menu choice check
            choice = self.menubar.choose_card((x, y), self.plant_choice,
                                              self.suns)
            if choice != self.plant_choice:
                self.plant_choice = choice
                self.plant_choice_image = None
                if self.plant_choice is not None:
                    self.plant_choice_image = self.plant_choice.get_shadow()
                    return

            # Plant / use shovel
            # If player's suns count is lesser than the needed for this plant
            if self.plant_choice.__class__.__name__ != "Shovel":
                if self.plant_choice is None or self.suns < self.plant_choice.sunCost:
                    return

            x -= c.pads["game"][0]
            y -= c.pads["game"][1]
            if x < 0 or y < 0:
                if self.plant_choice.__class__.__name__ == "Shovel":
                    self.plant_choice.put_back()
                self.plant_choice = self.plant_choice_image = None
                return

            try:
                cell = self.cells[y // c.sizes["cell"][1]][x //
                                                           c.sizes["cell"][0]]
            except IndexError:
                self.plant_choice = self.plant_choice_image = None
                return

            if self.plant_choice.__class__.__name__ == "Shovel":
                # If player is using shovel remove plant
                if cell.remove_plant():
                    self.suns += cell.sun
                    self.plant_choice.put_back()
                    self.plant_choice = self.plant_choice_image = None
            elif cell.plant(self.plant_choice, self.suns_group,
                            self.projectiles):
                # Else plant
                self.menubar.lock_card(self.plant_choice)
                self.suns -= self.plant_choice.sunCost
                self.plant_choice = self.plant_choice_image = None

    def drop_sun(self):
        """
        This method is called periodically through custom pygame event
        Drops sun in random place on random height
        """
        max_y = random.randint(c.sizes["win"][1] // 3,
                               c.sizes["win"][1] * 2 // 3)
        x = random.randint(c.sizes["win"][0] // 10,
                           c.sizes["win"][0] * 9 // 10)
        self.suns_group.add(Sun(x, c.sizes["topmenu"][1], max_y))

    def projectile_collisions_check(self):
        """
        Checks all projectiles on collisions with zombies
        Calls zombie method take_damage if so
        """
        for zombie in self.zombies:
            # Checks for hits
            for projectile in filter(
                    lambda p: p.row == zombie.row and p.rect.x >= zombie.rect.
                    x, self.projectiles):
                zombie.take_damage(projectile)

            # Checks for potato mine explosions
            for cell in filter(lambda ce: ce.col == zombie.col,
                               self.cells[zombie.row]):
                plant = cell.planted.sprite
                if plant.__class__.__name__ == "PotatoMine":
                    if plant.armed:
                        plant.explode(zombie)

            # Check if chompers can eat zombie
            for cell in self.cells[zombie.row][zombie.col - 1:zombie.col + 1]:
                plant = cell.planted.sprite
                if plant.__class__.__name__ == "Chomper":
                    if not plant.busy():
                        plant.catch(zombie)

        # Check for cherryBomb explosion
        for row in self.cells:
            for cell in row:
                plant = cell.planted.sprite
                if plant.__class__.__name__ == "CherryBomb":
                    if plant.armed and plant.health > 0:
                        row, col = plant.coords
                        plant.explode(*filter(
                            lambda z: z.row in [row - 1, row, row + 1] and z.
                            col in [col - 1, col, col + 1], self.zombies))

    def lawnmowers_update(self):
        """
        Checks for zombie crossing the last cell
        If row lawnmover exists, make it run
        Else game is lost
        """

        for zombie in self.zombies:
            if zombie.col < 0:
                lawnmower = self.lawnmovers[zombie.row]
                if lawnmower is None:
                    self.lose()
                    return
                lawnmower.run()

        for ind, lawnmower in enumerate(self.lawnmovers):
            if lawnmower is None:
                continue
            if lawnmower.update(self.screen):
                self.lawnmovers[ind] = None
                continue
            if not lawnmower.running:
                continue

            for zombie in self.zombies:
                if zombie.row == lawnmower.row and \
                        lawnmower.rect.x > zombie.rect.x:
                    zombie.kill()

    def zombie_targeting(self):
        """
        Checks for cell intersections between plants and zombies
        Makes zombie eat plant if so
        """
        for zombie in filter(lambda z: not z.busy(), self.zombies):
            for cell in filter(
                    lambda ce: not ce.isempty() and ce.col == zombie.col,
                    self.cells[zombie.row]):
                plant = cell.planted
                zombie.change_target(plant)

    def lose(self):
        pass
예제 #6
0
class LevelPreparationLocation(_Location):
    def __init__(self, parent):
        super().__init__(parent)
        # Location music
        pygame.mixer_music.load("assets/audio/chooseYourSeeds.mp3")
        pygame.mixer_music.play(loops=-1)

        self.bg = Sprite(
            0, 0, image=pygame.image.load("assets/misc/bg.png").convert())
        # At the begging camera moves to the right side of background
        self.move_times = (self.bg.image.get_width() - c.sizes["win"][0]) / 5
        # Card choices
        self.plant_choice_widget = PlantChoiceMenu(  # Contains all working plants
            [
                PotatoMine, Sunflower, SnowPea, CherryBomb, Chomper, Repeater,
                WallNut, PeaShooter
            ])
        # Menu which usually displays suns and chosen cards
        # New cards added here
        self.top_menu = TopMenu(pos=0)
        # Sounds and images for pre-game state
        self.ready_set_plant = pygame.mixer.Sound(
            "assets/audio/readysetplant.wav")
        self.ready_set_plant_images = [
            pygame.image.load("assets/misc/StartReady.png").convert_alpha(),
            pygame.image.load("assets/misc/StartSet.png").convert_alpha(),
            pygame.image.load("assets/misc/StartPlant.png").convert_alpha(),
        ]
        self.counter = 0

    def update(self):
        if self.move_times > 0:  # Moves right before seeds choice
            self.bg.rect.x -= 5
            self.move_times -= 1
        elif self.move_times < 0:  # Moves left after seeds choice
            self.bg.rect.x += 5
            self.move_times += 1
            if self.move_times == 0:
                self.ready_set_plant.play()
                self.counter = 1

        self.bg.update(self.screen)
        if not self.move_times and not self.counter:
            self.plant_choice_widget.update(self.screen,
                                            pygame.mouse.get_pos())
            self.top_menu.update(self.screen, c.starting_sun)
        elif self.counter:
            self.counter += 1
            image = None
            if self.counter >= c.time_afterRSP:  # Change game location on game
                self.top_menu.move_right()
                self.parent.change_location(GameLocation(self, self.top_menu))
            # Ready Set Plant messages
            for i, time in enumerate(c.time_readySetPlant):
                if self.counter >= time:
                    image = self.ready_set_plant_images[2 - i]
                    break

            if image is not None:
                self.screen.blit(
                    image, ((c.sizes["win"][0] - image.get_width()) / 2,
                            (c.sizes["win"][1] - image.get_height()) / 2))

    def event(self, event):
        if event.type == MOUSEBUTTONUP and event.button == 1:
            mouse_pos = pygame.mouse.get_pos()

            self.top_menu.remove_card(mouse_pos)
            choice = self.plant_choice_widget.choose_card(mouse_pos)
            if choice is not None:
                self.top_menu.add_card(choice)

            if self.plant_choice_widget.button_click(mouse_pos):
                self.move_times = -(self.bg.image.get_width() -
                                    c.sizes["win"][0] - c.pads["game"][0]) // 5