Ejemplo n.º 1
0
    def draw_in_world(self, camera=None):
        """
        Отрисовка объекта в мире.
        :param camera: Камера, относительно которой нужно отрисовывать объект
        :return:
        """
        # Внимание! Меняя что-то здесь, не забывай поменять данную функцию в WorldObject!
        if self.visible:
            if self.image is not None:
                surface_to_draw = self.image.get_current()
                rect_to_draw = Rect.copy(self.object_rect)  # TODO: подумать, можно ли избежать здесь ненужного копирования
                if self.image.get_size() != self.object_rect.size:
                    # Если размер изображения не совпадает с размером объекта
                    surface_to_draw = transform.scale(surface_to_draw,
                                                      (self.object_rect.width, self.object_rect.height))
                if self.current_angle != "UP":
                    surface_to_draw = transform.rotate(surface_to_draw, ANGLE[self.current_angle])
                if camera is not None:
                    rect_to_draw.x += camera.get_coords()[0]
                    rect_to_draw.y += camera.get_coords()[1]
                self.parent_world.parent_surface.blit(surface_to_draw, rect_to_draw)
                if self.need_to_animate:
                    self.image.next()

                # Тестовое:
                if ID_DEBUG:
                    self.test_text = self.test_font.render("id={}".format(self.world_id), 0, (255, 255, 255))
                    self.parent_world.parent_surface.blit(self.test_text, (self.object_rect.x + camera.get_coords()[0],
                                                                           self.object_rect.y + camera.get_coords()[1]))
Ejemplo n.º 2
0
 def __init__(self, bounds: Rect, color: Optional[Color]):
     self.relative_bounds = bounds
     self.absolute_bounds = bounds.copy()
     self.color = color
     self.childs = []
     self.enabled = True
     self.parent = None
Ejemplo n.º 3
0
class GameObject:
    def __init__(self, x, y, w, h, speed=[0, 0]):
        self.bounds = Rect(x, y, w, h)
        self.speed = speed.copy()
        self.old_pos = None
        self.old_speed = None

    @property
    def left(self):
        return self.bounds.left

    @property
    def right(self):
        return self.bounds.right

    @property
    def top(self):
        return self.bounds.top

    @property
    def bottom(self):
        return self.bounds.bottom

    @property
    def width(self):
        return self.bounds.width

    @property
    def height(self):
        return self.bounds.height

    @property
    def center(self):
        return self.bounds.center

    @property
    def centerx(self):
        return self.bounds.centerx

    @property
    def centery(self):
        return self.bounds.centery

    def draw(self, surface):
        pass

    def move(self, dx: object, dy: object) -> object:
        self.bounds = self.bounds.move(dx, dy)

    def update(self):
        """"""
        self.old_pos = self.bounds.copy()
        self.old_speed = self.speed.copy()

        if self.speed == [0, 0]:
            return

        self.move(*self.speed)
Ejemplo n.º 4
0
    def __init__(self,
                 bounds: Rect,
                 color: Optional[Color],
                 absolute_anchor: Anchor = Anchor.TOP_LEFT,
                 relative_anchor: Anchor = Anchor.TOP_LEFT):
        """

        :param bounds: Bounds of element relatively to parent element
        :param color: Main color of element
        :param absolute_anchor: Anchor of location at the point of the parent element
        :param relative_anchor:Anchor of point of (x, y) = (0, 0) on element
        """
        self.relative_bounds = bounds
        self.absolute_anchor = absolute_anchor
        self.relative_anchor = relative_anchor
        self.absolute_bounds = bounds.copy()
        self.color = color
        self.childs = []
        self.enabled = True
        self.parent = None
Ejemplo n.º 5
0
    while running:
        clock.tick(FPS)

        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN:
                if event.key == K_SPACE:
                    paused = not paused
            if event.type == pygame.QUIT:
                running = False

        screen.fill(BLACK)

        transparent_surface.fill((0, 0, 0, 255))

        for carPos in SIMULATOR.getCarPositions():
            rect = CAR_RECT.copy()
            rect.center = carPos.x, carPos.y
            #pygame.draw.circle(transparent_surface, (143, 235, 52, 20), toPairI(carPos), 20)

        screen.blit(transparent_surface, (0, 0), special_flags=pygame.BLEND_RGBA_ADD)

        for street in SIMULATOR.map.streets:
            pygame.draw.line(screen, WHITE, toPairI(street.start), toPairI(street.end), 1)

        for street in SIMULATOR.map.streets:
            middlePoint = (street.start + street.end)/2
            normal = scale(street.getDefaultVector().rotate(90), 4)
            middleVertex = scale(street.getDefaultVector(), 4)
            opposite = scale(street.getDefaultVector().rotate(-90), 4)
            pygame.draw.lines(screen, WHITE, False,
                              [toPairI(middlePoint + normal), toPairI(middlePoint + middleVertex), toPairI(middlePoint + opposite)])
Ejemplo n.º 6
0
class UserInterface(Listener):

    def __init__(self, width: int, height: int):
        pygame.font.init()

        self.width = width
        self.height = height
        self.window = pygame.display.set_mode((self.width, self.height))

        self._grid_rect = None
        self._grid_rows = None
        self._grid_cols = None
        self._tile_side = None
        self._tiles_cache = None

        self._grid_spacing = 15
        self._padding = 40

        # The main padded area inside the window
        self._container = Rect(self._padding, self._padding,
                               self.width - self._padding * 2,
                               self.height - self._padding * 2)

        self._title = "2048"
        self._score = "SCORE"
        self._best = "BEST"
        self._caption = "Join the numbers and get to the 2048 tile!"
        self._how_to = OrderedDict(move=['arrows', 'W, A, S, D'], restart=['r'], quit=['q', 'ESC'])

        self.window.fill(theme.BACKGROUND)

        self._header = self._setup_header()
        self._footer = self._setup_footer()

        self._drawable = True
        pygame.display.set_caption("2048 Game by Oleg Pavlovich")
        pygame.display.update()

    def _reset_background(self):
        self.window.fill(theme.BACKGROUND)
        self._setup_header()
        self._setup_footer()

    def _setup_grid(self, grid: Grid) -> Rect:
        assert self._header
        assert self._footer

        # Calculate grid size and draw it
        margin = 40
        reserved = self._header.height + self._footer.height + 2 * margin

        min_side = min(self._container.width, self._container.height - reserved)
        scale_factor = min_side / max(grid.width, grid.height)
        grid_height = grid.height * scale_factor
        grid_width = grid.width * scale_factor
        grid_size = (grid_width, grid_height)

        # Save computed values and instances
        self._grid_rows = grid.height
        self._grid_cols = grid.width
        self._grid_rect = Rect((self._container.centerx - grid_width / 2, self._header.bottom + margin), grid_size)

        self._tile_side = (self._grid_rect.width - self._grid_spacing * (self._grid_cols + 1)) / self._grid_cols
        return self._grid_rect

    def _setup_header(self) -> Rect:
        # Draw title
        title = Rect((self._container.left, self._container.top), theme.H1_FONT.size(self._title))
        utils.draw_text(self.window, self._title, theme.COLOR_DARK, title, theme.H1_FONT, True)

        # Draw caption
        margin = 15
        caption = Rect((self._container.left, title.bottom + margin), theme.BASE_FONT.size(self._caption))
        utils.draw_text(self.window, self._caption, theme.COLOR_DARK, caption, theme.BASE_FONT, True)

        self._header = Rect(self._container.topleft, (self._container.width, caption.height + title.height + margin))
        pygame.display.update()
        return self._header

    def _setup_footer(self) -> Rect:
        # Draw tips from bottom to top
        margin_top = 5
        margin_right = 6
        tips = reversed(self._how_to.keys())

        tip_h = theme.BOLD_FONT.size("Tg")[1]
        tip_x = self._container.left
        tip_y = self._container.bottom - tip_h

        for tip in tips:
            label = f"{tip.title()}"
            label_font = theme.BOLD_FONT
            label_size = label_font.size(label)
            label_rect = Rect((tip_x, tip_y), label_size)

            options = "on " + " or ".join(self._how_to[tip])
            options_font = theme.BASE_FONT
            options_size = options_font.size(options)
            options_rect = Rect((label_rect.right + margin_right, label_rect.y), options_size)

            utils.draw_text(self.window, label, theme.COLOR_DARK, label_rect, label_font, True)
            utils.draw_text(self.window, options, theme.COLOR_DARK, options_rect, options_font, True)

            height = label_rect.height + margin_top
            tip_y = label_rect.top - height

        pygame.display.update()
        total_height = tip_h * len(self._how_to.keys())
        self._footer = Rect(self._container.left, self._container.bottom - total_height,
                            self._container.width, total_height)

        return self._footer

    def _draw_scores(self, score: int = 0, best: int = 0):
        score_margin = 10

        score_side = (self._container.width // 2 - score_margin * 2) / 2
        scale_factor = (self._header.height // 2) / score_side
        score_side *= scale_factor

        score_y = (self._header.centery - score_side / 2) - 15  # purely visual offset
        score_x = self._container.right - score_margin - 2 * score_side

        for label, value in zip((self._score, self._best), (score, best)):
            value = str(value)

            label_size = theme.LABEL_FONT.size(label)
            value_size = theme.VALUE_FONT.size(value)

            bg_rect = Rect(score_x, score_y, score_side, score_side)
            label_rect = Rect((bg_rect.centerx - label_size[0] / 2, bg_rect.top + 6), label_size)
            value_rect = Rect((bg_rect.centerx - value_size[0] / 2, label_rect.bottom), value_size)

            utils.draw_rounded_rect(self.window, theme.GRID_COLOR, bg_rect, border_radius=4)
            utils.draw_text(self.window, label, theme.COLOR_LIGHT, label_rect, theme.LABEL_FONT, True)
            utils.draw_text(self.window, value, theme.COLOR_WHITE, value_rect, theme.VALUE_FONT, True)

            # Set next block's x-coordinate
            score_x = bg_rect.right + score_margin

        pygame.display.update()

    def _draw_tiles(self, grid: Grid):
        if not self._grid_rect:
            self._setup_grid(grid)

        utils.draw_rounded_rect(self.window, theme.GRID_COLOR, self._grid_rect, border_radius=8)

        x, y = self._grid_rect.topleft
        for i in range(self._grid_rows):
            rect = None
            x = self._grid_rect.left

            for j in range(self._grid_cols):
                color = theme.CELL_COLOR
                tile = grid.get_cell(Position(j, i))
                text = None
                rect = Rect(x + self._grid_spacing, y + self._grid_spacing, self._tile_side, self._tile_side)

                if tile:
                    color = theme.TILE_COLOR_BASE
                    text = theme.H2_FONT.render(str(tile.value), True, theme.COLOR_DARK)

                utils.draw_rounded_rect(self.window, color, rect, 4)

                if text:
                    text_x = rect.left + (rect.width - text.get_width()) // 2
                    text_y = rect.top + (rect.height - text.get_height()) // 2
                    self.window.blit(text, (text_x, text_y))

                x = rect.right

            y = rect.bottom

        pygame.display.update()

    def _draw_message(self, text: str, overlay: bool = True):
        message_rect = self._header.copy()
        message_rect.y = message_rect.height * 2

        if overlay:
            alpha = 235
            color = theme.BACKGROUND
            color = color.r, color.g, color.b, alpha
            surf = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
            surf.fill(color)
            self.window.blit(surf, (0, 0))
        else:
            self.window.fill(theme.BACKGROUND)

        utils.draw_text(self.window, text, theme.COLOR_DARK, message_rect, theme.H3_FONT, True)
        pygame.display.update()

    def notify(self, event):
        if isinstance(event, GameReadyEvent):

            # Game was restarted with this flag
            if not self._drawable:
                self._reset_background()
                self._drawable = True

            self._setup_grid(event.grid)
            self._draw_tiles(event.grid)
            self._draw_scores(score=event.score, best=event.best)

        # If the game has ended this flag is raised
        if not self._drawable:
            return

        if isinstance(event, GridUpdateEvent):
            self._draw_tiles(event.grid)

        if isinstance(event, ScoreUpdateEvent):
            self._draw_scores(score=event.score, best=event.best)

        if isinstance(event, GameOverEvent):
            self._draw_scores(score=event.score, best=event.best)
            self._draw_message(f"Game over! Score {event.score}.\nPress r to restart or q to quit :)")
            self._drawable = False