重载 pygame.Surface 以动态增加表面的大小
Overloading pygame.Surface in order to dynamically augment the size of the surface
我正在尝试构建一个需要用户绘制内容的应用程序。
为此,我创建了一个 canvas(一个 pygame.Surface 对象),在其上注册了绘图,然后我将其 blit 到 window。我希望 canvas 是 infinite,这样当用户滚动时他可以继续绘图(当然只有一小部分 canvas 被 blited到 window)。但是,实际上,pygame 中的 Surface 需要有限的宽度和高度,最重要的是,它并没有那么大! (我认为那是因为它实际上将 space 锁定在内存中)。
所以,我尝试创建 chunks:每个块都有固定的大小(比如屏幕大小的两倍),并且每个块都分配了一个特定的 Surface。块是按需动态创建的,总体上运行良好。
我的问题是,当我尝试绘制跨越多个块的线条时,需要花费大量精力来计算实际应该在哪些块上绘制该线,以及应该在哪些部分断开。我什至没有尝试绘制矩形,因为真的让'draw-a-line'函数工作很痛苦。
那时我认为我所做的根本是错误的:与其尝试重写所有 pygame.draw 和 pygame.gfxdraw 函数以便它们基本上按块进行工作,我应该确实使 pygame.Surface 过载(例如,创建 Surface 的 MySurface class 子级)所以每当修改像素时,我都会在内部选择它属于哪个块并实际在该块上更改它,然后传递新的pygame 函数的曲面对象。
我在 the pygame doc 上搜索了很多,但没有说明如何进行搜索。当我 blit/draw 访问 Surface 对象时,我什至不知道内部调用了哪些方法!我也 google 它而且我没有发现任何人试图做那种事情(也许我走错路了?)。
所以,我的问题是:这是正确的方法吗?而且,如果是,我应该如何实现它?
我不 post 编写代码,因为我需要的更多是关于在哪里可以找到我尝试做的事情的文档的解释,而不是代码审查。
你不能只继承Surface
,因为它不是用python写的,而是用C写的。Here's the source code;自己找。
您可以采用另一种方法,而不是计算绘制内容的位置,而是首先将其 blit 到一个临时 Surface
,然后将其 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()
如您所见,canvas 由 4 个块组成。使用鼠标右键移动 canvas,使用鼠标左键开始绘制矩形。
我正在尝试构建一个需要用户绘制内容的应用程序。
为此,我创建了一个 canvas(一个 pygame.Surface 对象),在其上注册了绘图,然后我将其 blit 到 window。我希望 canvas 是 infinite,这样当用户滚动时他可以继续绘图(当然只有一小部分 canvas 被 blited到 window)。但是,实际上,pygame 中的 Surface 需要有限的宽度和高度,最重要的是,它并没有那么大! (我认为那是因为它实际上将 space 锁定在内存中)。
所以,我尝试创建 chunks:每个块都有固定的大小(比如屏幕大小的两倍),并且每个块都分配了一个特定的 Surface。块是按需动态创建的,总体上运行良好。
我的问题是,当我尝试绘制跨越多个块的线条时,需要花费大量精力来计算实际应该在哪些块上绘制该线,以及应该在哪些部分断开。我什至没有尝试绘制矩形,因为真的让'draw-a-line'函数工作很痛苦。
那时我认为我所做的根本是错误的:与其尝试重写所有 pygame.draw 和 pygame.gfxdraw 函数以便它们基本上按块进行工作,我应该确实使 pygame.Surface 过载(例如,创建 Surface 的 MySurface class 子级)所以每当修改像素时,我都会在内部选择它属于哪个块并实际在该块上更改它,然后传递新的pygame 函数的曲面对象。
我在 the pygame doc 上搜索了很多,但没有说明如何进行搜索。当我 blit/draw 访问 Surface 对象时,我什至不知道内部调用了哪些方法!我也 google 它而且我没有发现任何人试图做那种事情(也许我走错路了?)。
所以,我的问题是:这是正确的方法吗?而且,如果是,我应该如何实现它?
我不 post 编写代码,因为我需要的更多是关于在哪里可以找到我尝试做的事情的文档的解释,而不是代码审查。
你不能只继承Surface
,因为它不是用python写的,而是用C写的。Here's the source code;自己找。
您可以采用另一种方法,而不是计算绘制内容的位置,而是首先将其 blit 到一个临时 Surface
,然后将其 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()
如您所见,canvas 由 4 个块组成。使用鼠标右键移动 canvas,使用鼠标左键开始绘制矩形。