Example #1
0
class DeleteAccountScene(Scene):
    header = None
    confirm_text = None
    yes_btn = None
    no_btn = None

    # Create the various gui elements
    def start(self, screen):
        width = screen.get_width()
        height = screen.get_height()

        if not self.already_loaded:
            self.header = Label(pygame.rect.Rect(width / 2 - 200, 10, 400, 30), "Delete an account", options={
                Options.BACKGROUND: (20, 61, 89),
                Options.FOREGROUND: (244, 180, 26),
                Options.BORDER_WIDTH: 0,
            })
            self.confirm_text = Label(pygame.rect.Rect(width / 2 - 200, height / 2 - 50, 400, 30), "", options={
                                          Options.BACKGROUND: (82, 173, 200),
                                          Options.FOREGROUND: (20, 61, 89),
                                          Options.BORDER_WIDTH: 0
                                      })
            self.yes_btn = Button(pygame.rect.Rect(width / 2 - 200, height / 2 + 50, 50, 40), "Yes", options={
                Options.BACKGROUND: (20, 61, 89),
                Options.FOREGROUND: (244, 180, 26),
                Options.HOVERED_BACKGROUND: (10, 30, 45),
                Options.BORDER_WIDTH: 0,
            })
            self.no_btn = Button(pygame.rect.Rect(width / 2 + 150, height / 2 + 50, 50, 40), "No", options={
                Options.BACKGROUND: (20, 61, 89),
                Options.FOREGROUND: (244, 180, 26),
                Options.HOVERED_BACKGROUND: (10, 30, 45),
                Options.BORDER_WIDTH: 0,
            })

            self.already_loaded = True

        self.confirm_text.text = f"Are you sure you want to delete account {Account.account_to_delete.name}?"
        self.confirm_text.recreate()

    def update(self, event):
        for elt in (self.yes_btn, self.no_btn):
            elt.update(event)

        if self.yes_btn.clicked:
            Account.delete_account(Account.account_to_delete)
            Account.account_to_delete = None
            Scene.push_scene(1)

        if self.no_btn.clicked:
            Scene.push_scene(1)

    # Clear the screen and draw the gui
    def draw(self, screen):
        screen.fill((82, 173, 200))

        for elt in (self.header, self.confirm_text, self.yes_btn, self.no_btn):
            elt.draw(screen)
Example #2
0
class GameScene(Scene):
    GAME_OVER_EVENT = pygame.USEREVENT + 1
    game_over = False

    ENEMY_MOVE_DELAY = 100

    world = None
    table = None
    players = None

    current_player_index = -1
    victory_state = -1
    move_made = True

    turn_count = 0
    ai_counter = 0

    turn_text = None
    victory_text = None

    drag_start_pos = None
    mouse_dragging = False
    drag_end_pos = None

    player_sprites = []
    width, height = 0, 0

    def start(self, screen):
        if not self.already_loaded:
            self.width, self.height = screen.get_width(), screen.get_height()

            self.turn_text = Label(
                pygame.Rect(10, 10, 100, 30), "", {
                    Options.BACKGROUND: (0, 51, 102),
                    Options.FOREGROUND: (255, 255, 255),
                    Options.BORDER_WIDTH: 0,
                })

            self.victory_text = Label(
                pygame.Rect(self.width / 2 - 100, self.height / 2 - 30, 200,
                            60), "",
                {
                    Options.FONT: pygame.font.SysFont("Comic Sans MS", 25),
                    Options.BACKGROUND: (0, 51, 102),
                    Options.FOREGROUND: (255, 255, 255),
                    Options.BORDER_WIDTH: 0,
                })

            self.reset_game_data()
            self.already_loaded = True

        if GameScene.game_over:
            self.reset_game_data()

    def reset_game_data(self):
        GameScene.game_over = False

        self.world = World((0, 0))

        world_center = screen_to_world((self.width / 2, self.height / 2))
        table_size = screen_to_world((1200, 600))

        self.table = Table(world_center, table_size, self.world)
        self.players = [
            Pen(PenData.current_pen, (world_center[0] - 35, world_center[1]),
                self.table.body, self.world),
            Pen(PenData.current_enemy_pen,
                (world_center[0] + 35, world_center[1]), self.table.body,
                self.world)
        ]

        self.ai_counter = GameScene.ENEMY_MOVE_DELAY
        self.turn_count = 0
        self.move_made = True

        self.current_player_index = 1
        self.victory_state = -1

        self.player_sprites = {
            p: PenSprite(Resources.get(p.data.image_file))
            for p in self.players
        }

        self.next_turn()

    def update(self, event):
        if event.type == pygame.KEYDOWN and event.key == pygame.K_p:
            Scene.push_scene(8)

        elif self.current_player_index == 0 and not self.move_made:
            if event.type == pygame.MOUSEBUTTONDOWN and not self.mouse_dragging:
                self.drag_start_pos = self.drag_end_pos = pygame.mouse.get_pos(
                )
                self.mouse_dragging = True
            elif event.type == pygame.MOUSEMOTION and self.mouse_dragging:
                self.drag_end_pos = pygame.mouse.get_pos()
            elif event.type == pygame.MOUSEBUTTONUP and self.mouse_dragging:
                self.drag_end_pos = pygame.mouse.get_pos()

                drag_start = Vec2(
                    screen_to_world((self.drag_start_pos[0],
                                     self.height - self.drag_start_pos[1])))
                drag_end = Vec2(
                    screen_to_world((self.drag_end_pos[0],
                                     self.height - self.drag_end_pos[1])))
                hit_point = GameScene.cast_ray(self.players[0].fixture,
                                               drag_start, drag_end)
                if hit_point is not None:
                    randomness = random.random() * 5 - 2.5
                    force = (hit_point - drag_start) * (20 + randomness)
                    self.players[0].apply_force(hit_point, force)
                    self.move_made = True

                self.mouse_dragging = False

        elif event.type == GameScene.GAME_OVER_EVENT:
            pygame.time.set_timer(GameScene.GAME_OVER_EVENT, 0)
            GameScene.game_over = True
            GameOverScene.result = GameResult(self.victory_state)
            Scene.push_scene(10)

    def draw(self, screen):
        screen.fill((0, 51, 102))

        table_rect = pygame.Rect((0, 0),
                                 world_to_screen(self.table.dimensions))
        table_rect.center = world_to_screen(self.table.center)
        pygame.draw.rect(screen, (204, 102, 0), table_rect)

        if self.victory_state == -1:
            self.turn_text.draw(screen)
            self.draw_player(screen, self.players[0])
            self.draw_player(screen, self.players[1])
        elif self.victory_state != GameResult.VictoryState.TIE:
            self.draw_player(screen, self.players[self.victory_state.value])

        self.check_bounds()

        if self.mouse_dragging:
            drag_start = Vec2(
                screen_to_world((self.drag_start_pos[0],
                                 self.height - self.drag_start_pos[1])))
            drag_end = Vec2(
                screen_to_world((self.drag_end_pos[0],
                                 self.height - self.drag_end_pos[1])))

            hit_point = GameScene.cast_ray(self.players[0].fixture, drag_start,
                                           drag_end)
            if hit_point is not None:
                end = world_to_screen(hit_point)
                end = (end[0], self.height - end[1])
                GameScene.draw_arrow(screen, (0, 255, 0), self.drag_start_pos,
                                     end)
            else:
                GameScene.draw_arrow(screen, (255, 0, 0), self.drag_start_pos,
                                     self.drag_end_pos)

        if self.victory_state != -1:
            self.victory_text.draw(screen)

        if self.victory_state == -1 and not self.move_made and self.current_player_index == 1:
            if self.ai_counter == 0:
                self.ai_counter = GameScene.ENEMY_MOVE_DELAY

                target, hit_point = PenData.current_enemy_strategy(
                    self.players[1], self.players[0], self.table)
                randomness = random.random() * 10 - 5
                force = (target - hit_point) * (20 + randomness)
                self.players[1].apply_force(hit_point, force)
                self.move_made = True

            else:
                self.ai_counter -= 1

        self.world.Step(1.0 / 30.0, 20, 20)
        self.world.ClearForces()

    def next_turn(self):
        self.move_made = False
        self.current_player_index = 1 - self.current_player_index

        self.turn_text.text = f"Player's Turn" if self.current_player_index == 0 else f"Computer's Turn"
        self.turn_text.recreate(False)

    def check_bounds(self):
        if self.victory_state == -1:
            player_outside = not self.table.contains_point(
                self.players[0].body.position)
            comp_outside = not self.table.contains_point(
                self.players[1].body.position)

            if player_outside and comp_outside:
                self.set_winner(GameResult.VictoryState.TIE)

            elif (GameScene.velocity_near_zero(self.players[0]) or player_outside) and \
                 (GameScene.velocity_near_zero(self.players[1]) or comp_outside):

                if player_outside:
                    self.set_winner(GameResult.VictoryState.LOSE)
                elif comp_outside:
                    self.set_winner(GameResult.VictoryState.WIN)
                elif self.move_made:
                    self.next_turn()

    def set_winner(self, result):
        self.victory_state = result

        if result == GameResult.VictoryState.TIE:
            self.victory_text.text = f"It's a tie!"
        elif result == GameResult.VictoryState.LOSE:
            self.victory_text.text = f"Computer wins!"
        elif result == GameResult.VictoryState.WIN:
            self.victory_text.text = f"Player wins!"

        self.victory_text.recreate()
        pygame.time.set_timer(GameScene.GAME_OVER_EVENT, 2000)

    def draw_player(self, screen, player):
        position = player.body.position
        position = world_to_screen(position)
        position = (position[0], self.height - position[1])

        rotation = player.body.angle
        rotation = math.degrees(rotation)

        sprite = self.player_sprites[player]
        sprite.set_transform(position, rotation)
        sprite.draw(screen)

    @staticmethod
    def cast_ray(fixture, start, end):
        input = RayCastInput(p1=start, p2=end, maxFraction=1.1)
        output = RayCastOutput()
        if fixture.RayCast(output, input, 0):
            hit_point = start + (end - start) * output.fraction
            return hit_point
        return None

    @staticmethod
    def draw_arrow(surface, color, start, end, line_size=3, arrow_size=7):
        pygame.draw.line(surface, color, start, end, line_size)
        rotation = math.atan2(start[1] - end[1],
                              end[0] - start[0]) + math.pi / 2
        pygame.draw.polygon(
            surface, color,
            [(end[0] + arrow_size * math.sin(rotation),
              end[1] + arrow_size * math.cos(rotation)),
             (end[0] + arrow_size * math.sin(rotation - 2.0944),
              end[1] + arrow_size * math.cos(rotation - 2.0944)),
             (end[0] + arrow_size * math.sin(rotation + 2.0944),
              end[1] + arrow_size * math.cos(rotation + 2.0944))])

    @staticmethod
    def velocity_near_zero(player,
                           linear_threshold=0.2,
                           angular_threshold=0.5):
        return player.body.linearVelocity.lengthSquared <= linear_threshold ** 2 \
               and player.body.angularVelocity <= angular_threshold
class PenSelectScene(Scene):
    header = None
    back_btn = None

    select_btn = None
    purchase_btn = None

    name_text = None
    density_text = None
    restitution_text = None
    description_lines = []

    coins_image = None
    coins_text = None

    pen_images = []
    visible_pen_images = []
    left_btn, right_btn = None, None

    center_pos = None
    pen_index = 0

    def start(self, screen):
        if not self.already_loaded:
            PenData.load_all_pens(Resources.get("all_pens"))

            width = screen.get_width()
            height = screen.get_height()

            self.back_btn = Button(
                pygame.Rect(10, 10, 60, 40), "Back", {
                    Options.BORDER_WIDTH: 0,
                    Options.BACKGROUND: (20, 61, 89),
                    Options.FOREGROUND: (244, 180, 26),
                    Options.HOVERED_BACKGROUND: (10, 30, 45),
                    Options.FONT: pygame.font.SysFont("Comic Sans MS", 15)
                })

            label_options = {
                Options.BACKGROUND: (20, 61, 89),
                Options.FOREGROUND: (244, 180, 26),
                Options.BORDER_WIDTH: 0,
            }
            self.header = Label(pygame.Rect(width / 2 - 200, 10, 400, 30),
                                "Select your weapon!", label_options)
            self.coins_text = Label(
                pygame.Rect(width - 110, height - 55, 100, 40), "0",
                label_options)

            label_options = {
                Options.BACKGROUND: (82, 173, 200),
                Options.FOREGROUND: (20, 61, 89),
                Options.BORDER_WIDTH: 0,
                Options.FONT: pygame.font.SysFont("Comic Sans MS", 18)
            }
            self.density_text = Label(pygame.Rect(width / 5, 110, 100, 20),
                                      "Density: ", label_options)
            self.restitution_text = Label(pygame.Rect(width / 5, 130, 100, 20),
                                          "Restitution: ", label_options)

            self.name_text = Label(
                pygame.Rect(width / 2 - 45, height - 125, 90, 50), "",
                label_options)
            self.description_lines = [
                Label(pygame.Rect(width * 2 / 3, 100 + i * 25, 100, 20), "",
                      label_options) for i in range(0, 3)
            ]

            self.coins_image = Image(
                pygame.Rect(width - 175, height - 60, 50, 50),
                Resources.get("coin"), {Options.BACKGROUND: (82, 173, 200)})

            btn_options = {
                Options.BORDER_WIDTH: 0,
                Options.BACKGROUND: (20, 61, 89),
                Options.FOREGROUND: (244, 180, 26),
                Options.HOVERED_BACKGROUND: (10, 30, 45),
                Options.FONT: pygame.font.SysFont("Comic Sans MS", 25)
            }
            self.left_btn = Button(pygame.Rect(10, height / 2 - 20, 20, 30),
                                   "<", btn_options)
            self.right_btn = Button(
                pygame.Rect(width - 30, height / 2 - 20, 20, 30), ">",
                btn_options)
            self.select_btn = Button(
                pygame.Rect(width / 2 - 45, height - 75, 90, 50), "Select",
                btn_options)
            self.purchase_btn = Button(
                pygame.Rect(width / 2 - 125, height - 75, 250, 40), "",
                btn_options)

            self.center_pos = pygame.Rect(width / 2 - 50, height / 2 - 50, 100,
                                          100)
            for pen in PenData.all_pens:
                self.pen_images.append(
                    Image(self.center_pos, Resources.get(pen.image_file),
                          {Options.BACKGROUND: (82, 173, 200)}))

            self.already_loaded = True

        self.reposition_images()
        self.update_shop_data()
        self.reset_coin_text()

    def update(self, event):
        for elt in (self.back_btn, self.left_btn, self.right_btn):
            elt.update(event)

        cur_pen = PenData.all_pens[self.pen_index]
        if cur_pen.name in Account.current_account.pens:
            self.select_btn.update(event)
            if self.select_btn.clicked:
                PenData.current_pen = cur_pen
                Scene.push_scene(6)
        else:
            self.purchase_btn.set_enabled(
                Account.current_account.money >= cur_pen.cost)
            self.purchase_btn.update(event)
            if self.purchase_btn.clicked:
                Account.current_account.purchase_pen(cur_pen)
                self.reset_coin_text()

        if self.back_btn.clicked:
            Scene.pop_scene()

        if self.left_btn.clicked or self.right_btn.clicked:
            if self.left_btn.clicked:
                self.pen_index -= 1
                self.reposition_images()
            elif self.right_btn.clicked:
                self.pen_index += 1
                self.reposition_images()
            self.update_shop_data()

    def reposition_images(self):
        self.visible_pen_images.clear()

        if self.pen_index > 0:
            img = self.pen_images[self.pen_index - 1]
            self.visible_pen_images.append(img)
            img.rect = self.center_pos.copy().move(-300, 40)

        self.visible_pen_images.append(self.pen_images[self.pen_index])
        self.pen_images[self.pen_index].rect = self.center_pos

        if self.pen_index < len(self.pen_images) - 1:
            img = self.pen_images[self.pen_index + 1]
            self.visible_pen_images.append(img)
            img.rect = self.center_pos.copy().move(300, 40)

        self.left_btn.set_enabled(self.pen_index > 0)
        self.right_btn.set_enabled(self.pen_index < len(self.pen_images) - 1)

    def reset_coin_text(self):
        self.coins_text.text = str(Account.current_account.money)
        self.coins_text.recreate()

    def update_shop_data(self):
        cur_pen = PenData.all_pens[self.pen_index]

        self.name_text.text = cur_pen.name
        self.name_text.recreate()

        self.density_text.text = f"Density: {cur_pen.density}"
        self.density_text.recreate()

        self.restitution_text.text = f"Restitution: {cur_pen.restitution}"
        self.restitution_text.recreate()

        line_index = 0
        for line in cur_pen.description:
            self.description_lines[line_index].text = line
            self.description_lines[line_index].recreate()
            line_index += 1

        if cur_pen.name not in Account.current_account.pens:
            self.purchase_btn.text = f"Purchase for {cur_pen.cost}"
            self.purchase_btn.recreate()

    def draw(self, screen):
        screen.fill((82, 173, 200))

        for elt in (self.header, self.back_btn, self.left_btn, self.right_btn,
                    self.name_text, self.coins_image, self.coins_text,
                    self.density_text, self.restitution_text):
            elt.draw(screen)

        for line in self.description_lines:
            line.draw(screen)

        if PenData.all_pens[
                self.pen_index].name in Account.current_account.pens:
            self.select_btn.draw(screen)
        else:
            self.purchase_btn.draw(screen)

        for img in self.visible_pen_images:
            img.draw(screen)
Example #4
0
class EnemySelectScene(Scene):
    header = None
    back_btn = None

    select_btn = None
    name_text = None

    random_diff_btn = None
    easy_btn = None
    normal_btn = None
    hard_btn = None
    difficulty = -1

    random_pen_data = None
    pen_images = []
    visible_pen_images = []
    left_btn, right_btn = None, None

    center_pos = None
    pen_index = 0

    def start(self, screen):
        if not self.already_loaded:
            PenData.load_all_pens()

            width = screen.get_width()
            height = screen.get_height()

            self.back_btn = Button(
                pygame.Rect(10, 10, 60, 40), "Back", {
                    Options.BORDER_WIDTH: 0,
                    Options.BACKGROUND: (20, 61, 89),
                    Options.FOREGROUND: (244, 180, 26),
                    Options.HOVERED_BACKGROUND: (10, 30, 45),
                    Options.FONT: pygame.font.SysFont("Comic Sans MS", 15)
                })

            self.header = Label(
                pygame.Rect(width / 2 - 200, 10, 400, 30),
                "Choose your opponent!", {
                    Options.BACKGROUND: (20, 61, 89),
                    Options.FOREGROUND: (244, 180, 26),
                    Options.BORDER_WIDTH: 0,
                })

            self.name_text = Label(
                pygame.Rect(width / 2 - 45, height - 125, 90, 50), "", {
                    Options.BACKGROUND: (82, 173, 200),
                    Options.FOREGROUND: (20, 61, 89),
                    Options.BORDER_WIDTH: 0,
                    Options.FONT: pygame.font.SysFont("Comic Sans MS", 18)
                })

            btn_options = {
                Options.BORDER_WIDTH: 0,
                Options.BACKGROUND: (20, 61, 89),
                Options.FOREGROUND: (244, 180, 26),
                Options.HOVERED_BACKGROUND: (10, 30, 45),
                Options.FONT: pygame.font.SysFont("Comic Sans MS", 25)
            }
            self.left_btn = Button(pygame.Rect(10, height / 2 - 20, 20, 30),
                                   "<", btn_options)
            self.right_btn = Button(
                pygame.Rect(width - 30, height / 2 - 20, 20, 30), ">",
                btn_options)
            self.select_btn = Button(
                pygame.Rect(width / 2 - 45, height - 75, 90, 50), "Select",
                btn_options)

            btn_options[Options.TOGGLED_BACKGROUND] = (5, 20, 30)
            self.random_diff_btn = ToggleButton(
                pygame.Rect(width * 1 / 5 - 50, 100, 100, 30), "Random",
                btn_options)
            self.easy_btn = ToggleButton(
                pygame.Rect(width * 2 / 5 - 50, 100, 100, 30), "Easy",
                btn_options)
            self.normal_btn = ToggleButton(
                pygame.Rect(width * 3 / 5 - 50, 100, 100, 30), "Normal",
                btn_options)
            self.hard_btn = ToggleButton(
                pygame.Rect(width * 4 / 5 - 50, 100, 100, 30), "Hard",
                btn_options)
            toggle_group = [
                self.random_diff_btn, self.easy_btn, self.normal_btn,
                self.hard_btn
            ]
            for elt in toggle_group:
                elt.set_group(toggle_group)
            self.easy_btn.toggle()

            self.center_pos = pygame.Rect(width / 2 - 50, height / 2 - 50, 100,
                                          100)
            self.random_pen_data = PenData.dict_to_pen({
                "name":
                "Random",
                "image_file":
                "random_pen"
            })
            for pen in [self.random_pen_data] + PenData.all_pens:
                self.pen_images.append(
                    Image(self.center_pos, Resources.get(pen.image_file),
                          {Options.BACKGROUND: (82, 173, 200)}))

            self.already_loaded = True

        self.reposition_images()
        self.update_enemy_data()

    def update(self, event):
        for elt in (self.back_btn, self.left_btn, self.right_btn,
                    self.select_btn, self.random_diff_btn, self.easy_btn,
                    self.normal_btn, self.hard_btn):
            elt.update(event)

        if self.select_btn.clicked:
            PenData.current_enemy_pen = \
                random.choice(PenData.all_pens) if self.pen_index == 0 else \
                PenData.all_pens[self.pen_index - 1]

            PenData.current_enemy_difficulty = \
                AIDifficulty.EASY if self.easy_btn.toggled else \
                AIDifficulty.NORMAL if self.normal_btn.toggled else \
                AIDifficulty.HARD if self.hard_btn.toggled else \
                random.choice(list(AIDifficulty))

            Scene.push_scene(7)

        if self.back_btn.clicked:
            Scene.pop_scene()

        if self.left_btn.clicked or self.right_btn.clicked:
            if self.left_btn.clicked:
                self.pen_index -= 1
                self.reposition_images()
            elif self.right_btn.clicked:
                self.pen_index += 1
                self.reposition_images()
            self.update_enemy_data()

    def reposition_images(self):
        self.visible_pen_images.clear()

        if self.pen_index > 0:
            img = self.pen_images[self.pen_index - 1]
            self.visible_pen_images.append(img)
            img.rect = self.center_pos.copy().move(-300, 40)

        self.visible_pen_images.append(self.pen_images[self.pen_index])
        self.pen_images[self.pen_index].rect = self.center_pos

        if self.pen_index < len(self.pen_images) - 1:
            img = self.pen_images[self.pen_index + 1]
            self.visible_pen_images.append(img)
            img.rect = self.center_pos.copy().move(300, 40)

        self.left_btn.set_enabled(self.pen_index > 0)
        self.right_btn.set_enabled(self.pen_index < len(self.pen_images) - 1)

    def update_enemy_data(self):
        self.name_text.text = self.random_pen_data.name if self.pen_index == 0 else \
            PenData.all_pens[self.pen_index - 1].name
        self.name_text.recreate()

    def draw(self, screen):
        screen.fill((82, 173, 200))

        for elt in (self.header, self.back_btn, self.left_btn, self.right_btn,
                    self.name_text, self.select_btn, self.easy_btn,
                    self.normal_btn, self.hard_btn, self.random_diff_btn):
            elt.draw(screen)

        for img in self.visible_pen_images:
            img.draw(screen)