首页 > 解决方案 > 重载 pygame.Surface 以动态增加表面的大小

问题描述

我正在尝试构建一个需要用户绘制东西的应用程序。

为此,我创建了一个画布(一个 pygame.Surface 对象),在其上注册了绘图,然后将其粘贴到窗口上。我希望画布是无限的,这样当用户滚动时,他可以继续绘图(当然只有一小部分画布被粘贴到窗口上)。但是,实际上,pygame 中的 Surface 需要有限的宽度和高度,最重要的是,它并没有那么大!(我认为那是因为它实际上锁定了内存空间)。

因此,我尝试创建:每个块都具有固定大小(例如,屏幕大小的两倍),并且为每个块分配了一个特定的 Surface。块是根据需要动态创建的,并且总体上运行良好。

我的问题是,当我尝试绘制跨越多个块的线时,需要付出很大的努力来计算该线应该实际绘制到哪些块上,以及应该在哪些部分中断开。我什至没有尝试绘制矩形,因为让“画线”功能工作真的很痛苦。

那时我认为我所做的从根本上是错误的:与其尝试重写所有 pygame.draw 和 pygame.gfxdraw 函数以便它们基本上完成每个块的工作,我真的应该重载 pygame.Surface (比如说,创建 Surface 的 MySurface 子类),因此每当修改像素时,我在内部选择它属于哪个块并实际在该块上更改它,并将该新 Surface 对象传递给 pygame 函数。

我在pygame doc上进行了很多搜索,但没有解释如何做到这一点。我什至不知道当我对它进行 blit/draw 时,内部调用了 Surface 对象的哪些方法!我也用谷歌搜索,没有发现有人试图做那种事情(也许我走错路了?)。

所以,我的问题是:这是正确的方法吗?而且,如果是,我应该如何实现它?

我不发布代码是因为我需要更多的是解释在哪里可以找到我尝试做的文档,而不是代码审查。

标签: python-3.xpygamepygame-surface

解决方案


你不能只是子类Surface,因为它不是用 python 编写的,而是用 C 编写的。这是源代码;寻找自己。

您可以采取另一种方法,而不是计算在哪里绘制东西,而是Surface先将它blit到一个临时的上,然后将它blit到相对于块位置的块上。

这是我一起破解的简单示例:

 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()

在此处输入图像描述

如您所见,画布由 4 个块组成。使用鼠标右键移动画布,使用鼠标左键开始绘制矩形。


推荐阅读