Перегрузка pygame.Surface для динамического увеличения размера поверхности - PullRequest
2 голосов
/ 24 апреля 2020

Я пытаюсь создать приложение, которое требует, чтобы пользователь что-то нарисовал.

Для этого я создаю холст (объект pygame.Surface), на котором зарегистрирован чертеж, и затем я блею это на окно. Мне бы хотелось, чтобы холст был бесконечным , чтобы, когда пользователь прокручивает, он мог продолжать рисовать (конечно, только небольшая часть холста скрывается в окне). Но, на самом деле, Surface в Pygame требует конечной ширины и высоты, а главное, он не такой большой! (Я думаю, это потому, что он фактически блокирует пространство в памяти).

Итак, я попытался создать чанков : каждый чанк имеет фиксированный размер (например, в два раза больше размера экрана), и каждому куску выделяется определенная поверхность. Чанки создаются динамически, по требованию, и в целом это работает довольно хорошо.

Моя проблема в том, что когда я пытаюсь нарисовать линии, которые пересекаются на несколько чанков, это требует больших усилий для вычисления того, какие чанки эта линия должна На самом деле быть нарисованным, и на какие части он должен быть разбит. Я даже не пытался рисовать прямоугольники, потому что на самом деле было затруднительно, чтобы функция 'рисовать линию' работала.

Именно тогда я подумал, что то, что я делал, было в корне неверно: вместо того, чтобы пытаться переписать все функции pygame.draw и pygame.gfxdraw, чтобы они в основном выполняли работу для каждого чанка, я должен действительно перегружать pygame.Surface (скажем, создать дочерний класс MySurface класса Surface), поэтому всякий раз, когда пиксель изменяется, я внутренне выбрал, к какому чанку он принадлежит, и на самом деле изменил его в этом чанке, и передал этот новый объект Surface в функции pygame.

Я много искал в pygame сделать c, но там не объясняется, как это сделать. Я даже не знаю, какие методы объекта Surface внутренне вызываются, когда я рисую на нем! Я также гуглю это, и я не нашел никого, кто пытался бы делать такие вещи (может быть, я иду не в ту сторону?).

Итак, мой вопрос (ы): это правильный подход ? И, если да, как мне это осознать?

Я не публикую код, потому что мне нужно больше объяснения того, где найти то, что я пытаюсь сделать больше, чем код обзор.

1 Ответ

4 голосов
/ 24 апреля 2020

Вы не можете просто подкласс Surface, потому что это написано не в python, а в C. Вот исходный код ; поищите сами.

Вы можете выбрать другой подход и вместо расчета, где рисовать вещи, сначала разбить его на временный Surface и перебросить его на куски относительно позиции чанка.

Вот простой пример, который я взломал вместе:

 import pygame

class Chunk(pygame.sprite.Sprite):
    def __init__(self, grid_pos, size, color):
        super().__init__()
        self.image = pygame.Surface(size)
        self.rect = self.image.get_rect(
            x = grid_pos[0] * size[0],
            y = grid_pos[1] * size[1]
        )
        self.image.fill(pygame.Color(color))

    def patch(self, surface):
        self.image.blit(surface, (-self.rect.x, -self.rect.y))

def main():
    pygame.init()
    size = 800, 600
    screen = pygame.display.set_mode(size)
    chunks = pygame.sprite.Group(
        Chunk((0,0), size, 'green'),
        Chunk((1,0), size, 'red'),
        Chunk((0,1), size, 'blue'),
        Chunk((1,1), size, 'yellow')
    )
    dragging = None
    drawing = None
    tmp_s = pygame.Surface(size, pygame.SRCALPHA)

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 3:
                    dragging = event.pos
                if event.button == 1:
                    drawing = event.pos

            if event.type == pygame.MOUSEBUTTONUP:
                if event.button == 3:
                    dragging = None
                if event.button == 1:
                    drawing = None
                    for chunk in chunks:
                        chunk.patch(tmp_s)

            if event.type == pygame.MOUSEMOTION:
                if dragging:
                    for chunk in chunks:
                        chunk.rect.move_ip(event.rel)

        screen.fill((0, 0, 0))
        chunks.draw(screen)

        tmp_s.fill((0,0,0,0))
        if drawing:
            size = pygame.Vector2(pygame.mouse.get_pos()) - drawing
            pygame.draw.rect(tmp_s, pygame.Color('white'), (*drawing, *size), 10)

        screen.blit(tmp_s, (0, 0))
        chunks.update()
        pygame.display.flip()

main()

enter image description here

Как видите, холст состоит из 4 кусков. Используйте правую кнопку мыши, чтобы переместить холст, и левую кнопку, чтобы начать рисовать прямоугольник.

...