Python 3.x 重载pygame.Surface,以便动态增大曲面的大小
我正在尝试构建一个应用程序,它需要用户绘制一些东西 为此,我创建了一个画布(一个pygame.Surface对象),在上面注册了图形,然后将其放到窗口上。我希望画布是无限的,这样当用户滚动时,他就可以继续绘制(当然,只有画布的一小部分会显示在窗口上)。但是,实际上,pygame中的曲面需要有限的宽度和高度,最重要的是,它没有那么大!(我认为这是因为它实际上锁定了内存中的空间) 因此,我尝试创建块:每个块都有固定的大小(比如,屏幕大小的两倍),每个块都分配了一个特定的曲面。区块是按需以友好方式创建的,总体上运行良好 我的问题是,当我试图在多个块上画交叉线时,需要花很大的精力来计算该线应该画在哪些块上,以及应该在哪些块上断开。我甚至没有尝试画矩形,因为让“画一条线”功能工作起来真的很痛苦 当时我认为我所做的是根本错误的:与其试图重写所有pygame.draw和pygame.gfxdraw函数,以便它们基本上完成每一块的工作,不如让pygame.Surface过载(比如,创建一个MySurface类Surface的子类),这样每当修改像素时,我在内部选择了它所属的块,并在该块上实际更改它,然后将新的曲面对象传递给pygame函数 我在上搜索了很多,但没有解释如何做到这一点。我甚至不知道当我在曲面对象上blit/draw时,它的内部调用了什么方法!我也在谷歌上搜索过,我没有发现有人试图做那种事情(也许我走错了方向?) 因此,我的问题是:这是正确的方法吗?如果是的话,我该如何认识到这一点Python 3.x 重载pygame.Surface,以便动态增大曲面的大小,python-3.x,pygame,pygame-surface,Python 3.x,Pygame,Pygame Surface,我正在尝试构建一个应用程序,它需要用户绘制一些东西 为此,我创建了一个画布(一个pygame.Surface对象),在上面注册了图形,然后将其放到窗口上。我希望画布是无限的,这样当用户滚动时,他就可以继续绘制(当然,只有画布的一小部分会显示在窗口上)。但是,实际上,pygame中的曲面需要有限的宽度和高度,最重要的是,它没有那么大!(我认为这是因为它实际上锁定了内存中的空间) 因此,我尝试创建块:每个块都有固定的大小(比如,屏幕大小的两倍),每个块都分配了一个特定的曲面。区块是按需以友好方式创建
我不发布代码,因为我需要的不仅仅是代码审查,更重要的是解释在哪里可以找到我试图做的事情的文档。你不能只是子类
Surface
,因为它不是用python编写的,而是用C编写的;你自己找吧
您可以采用另一种方法,而不是计算在何处绘制内容,首先将其放到一个临时的表面上,然后将其与块的位置相对应地映射到块上
下面是我拼凑的一个简单例子:
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个块组成。使用鼠标右键移动画布,左键开始绘制矩形。。。。我想我可以看到两个选择:进入C级或者简单地接受你的伟大解决方案(我已经做出了选择:P)。顺便说一句,如果我理解的很好,我不必对我的块做任何特殊的事情,但是我仍然需要为标准的绘图函数创建包装器?无论如何,谢谢你的回答和反应!您不必包装绘图函数本身。只是不要直接画到屏幕表面。好的,我已经实现了它,但是我在性能上遭受了巨大的损失。我从~300fps以~30fps的速度通过,只是因为我在每一帧将临时曲面blit到块上。当你想永久改变块时,你只需要将临时曲面blit到块上。此外,由于您的块与屏幕一样大或更大,因此最多有四个块需要更改。你应该知道当前哪些块是可见的,并且只在临时表面上显示这些块。这实际上就是我后来试图提高效率的地方(要求块比屏幕大,生成看到的块的坐标,检索这些块或者创建它们(如果它们还不存在),最后只显示一次,当用户尝试滚动时,请重置临时曲面。因此,我认为我的性能问题来自我的程序中的一个bug,而不是您的解决方案,我将修复它(迟早)。谢谢你的帮助!