重载pygame.Surface以动态增加表面的大小

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

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

因此,我尝试创建块:给定固定大小(例如,屏幕大小的两倍)的每个块,并为每个块分配一定的Surface。块是按需动态创建的,并且效果很好。

我的问题是,当我尝试绘制跨多个块的线时,需要付出很大的努力才能计算出该线应实际绘制在哪些块上,以及应将其分成几部分。我什至没有尝试绘制矩形,因为使“画一条线”功能确实很痛苦。

那时候我以为我在做的事情根本上是错误的:与其试图重写所有pygame.draw和pygame.gfxdraw函数,以便它们基本上完成每个块的工作,我应该真正使pygame.Surface重载(例如,创建一个Surface的MySurface类子级),以便每当修改像素时,我都会在内部选择其所属的块,并在该块上进行实际更改,然后将新的Surface对象传递给pygame函数。

I've searched a lot at the pygame doc, but there it isn't explained how to do that. I don't even know what methods of a Surface object are internally called when I blit/draw onto it! I also google it and I didn't find anyone trying to do that kind of stuff (maybe I'm going the wrong way?).

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

我不发布代码,因为我需要的是更多的解释,而不是代码审查,这是关于在哪里可以找到我想做的事的文档的说明。

评论
  • 忆Oo红颜
    忆Oo红颜 回复

    You can't just subclass Surface, because it's not written in python, but in C. Here's the source code; look for yourself.

    You could take another approach and instead of calculating where to draw stuff, blit it onto a temporary Surface first and blit that to the chunks relative to the chunk's position.

    这是我一起砍的一个简单示例:

     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个块组成。使用鼠标右键移动画布,使用左键开始绘制矩形。