使用blitting(Pygame)有点困惑

27

我刚开始学习pygame(整体编程相对来说比较新手),我有一些非常基础的问题,想了解它的工作方式。

我还没有找到一个地方能够解释何时需要blit或者不需要将某个surface包含在屏幕上。例如,当绘制一个圆形:

circle = pygame.draw.circle(screen, (0, 0, 0), (100, 100), 15, 1)

我不需要执行screen.blit(circle),但在显示文本时需要:

text = font.render("TEXT", 1, (10, 10, 10)) 
textpos = text.get_rect()
textpos.centerx = screen.get_rect().centerx
screen.blit(text, textpos)

如果我不进行 blit 操作,文本就不会出现。

说实话,我真的不知道 blit 操作除了将所需表面“粘贴”到屏幕上之外还能做什么。希望我已经讲清楚了。


1
blitting 首先将任何非矢量图形光栅化到缓冲区中,以便可以写入视频缓冲区。通常,任何不是由基于矢量的渲染器动态生成的内容都需要进行 blitting。 - OregonTrail
pygame.draw.circle(surface, ...) 会直接绘制到 surface 上。而 font.Render() 则返回一个新的 Surface,但不会自动渲染。http://www.pygame.org/docs/ref/font.html#pygame.font.Font.render - ninMonkey
虽然有点晚了,但是@OregonTrail,你的意思是blitting将任何矢量图形光栅化到缓冲区吗?因为从阅读https://www.printcnx.com/resources-and-support/addiational-resources/raster-images-vs-vector-graphics/来看,非矢量图形似乎就是光栅图形? - samlaf
@samlaf 很好的问题。Blitting 是将矢量图形和预光栅化图形一起光栅化到缓冲区的过程。 - OregonTrail
3个回答

58

简短回答

我还没有找到一个地方来解释我何时需要将某个表面blit或不包括在屏幕上。

每个操作都会有不同的行为,您需要阅读正在使用的函数的文档。

详细回答

什么是Blitting?

首先,您需要了解Blitting在做什么。屏幕只是像素的集合,而Blitting是在另一个像素集合上进行完全复制。例如,您可以有一个包含从硬盘加载的图像的表面,并通过多次blitting该表面到screen表面上的不同位置上,在屏幕上多次显示它。

因此,您经常会看到这样的代码...

my_image = load_my_image()
screen.blit(my_image, position)
screen.blit(my_image, another_position)

用两行代码,我们通过“blitting”将大量像素从源表面(my_image)复制到屏幕上。

pygame.draw.* 函数如何执行 blit 操作?

在技术上,pygame.draw.* 方法可以被编写为执行类似的操作。所以,与其使用你的例子...

pygame.draw.circle(screen, COLOR, POS, RADIUS, WIDTH)

他们本来可以让你做这个的...

circle_surface = pygame.draw.circle(COLOR, RADIUS, WIDTH)
screen.blit(circle_surface, POS)
如果是这种情况,你会得到相同的结果。然而,在内部,pygame.draw.circle()方法直接操作传递给它的表面,而不是创建新的表面。选择这种方式可能是因为它可以比创建新表面更快或使用更少的内存来运行。
那我该怎么办呢?
所以,对于你的“何时 blit”和“何时不 blit”的问题,基本上,你需要阅读文档以查看函数实际上做了什么。
这是pygame.draw.circle()的文档: pygame.draw.circle():
在一个点周围画圆
circle(Surface, color, pos, radius, width=0) -> Rect
在表面上绘制圆形。pos参数是圆心,radius是大小。width参数是绘制外边缘的厚度。如果宽度为零,则圆将被填充。
请注意,它说“在表面上绘制形状”,因此它已经为您执行了像素更改。另外,它不返回表面(它返回一个矩形,但这只告诉您像素更改发生的位置)。
现在让我们看一下pygame.font.Font.render()文档
渲染文字到新表面
render(text, antialias, color, background=None) -> Surface 这将创建一个新的表面,并在其上呈现指定的文本。Pygame没有提供直接在现有表面上绘制文本的方法:相反,您必须使用Font.render()来创建文本的图像(表面),然后将此图像blit到另一个表面上。
正如你所看到的,它明确表示文本是绘制在一个新的表面上的,这个表面是被创建并返回给你的。这个表面不是你屏幕的表面(它不能是,因为你甚至没有告诉render()函数你的屏幕表面是什么)。这是一个非常好的迹象,表明你实际上需要将这个表面blit到屏幕上。

1
好的,你的回答很棒,谢谢!我只是有点困惑所有的事情,感谢你的澄清。 - Pabce

12

Blit的意思是“块图像传输”。

当你在屏幕上显示东西时,你会以某种方式使用screen,因为那是你放置它的地方。

当你执行以下操作时:

pygame.draw.circle(screen, (0, 0, 0), (100, 100), 15, 1)

你仍在使用屏幕,但你只是没有再进行 blitting 操作,因为 Pygame 正在代替你绘制。

当你使用文本时,Pygame 会将其渲染成图像,然后你需要进行 blitting 操作。

所以基本上你是会 blit 图像的,但你也可以让 Pygame 为你绘制它们。但要记住,当你 blit 一个图像(比如覆盖在背景上),你需要循环它前后,以便它 blits 背景、然后是图像、背景等等…

除此之外,你不需要知道更多,但你可以在这里阅读有关 Pygame Blit 的所有信息。

我希望这能有所帮助。祝你好运!


你有关于首字母缩写起源的参考资料吗?我认为你在那方面不太正确。维基百科上关于位块传输(bitblit)的解释是:“这个名字源自于 Xerox Alto 计算机的 BitBLT 程序,代表着“位边界块传输”(bit-boundary block transfer)”(强调添加),而现在的“位块传输”(bit blit)则只代表着“位块传输”。https://en.wikipedia.org/wiki/Bit_blit - eric

3

假设你是一位画家:

你有一块画布和一支笔刷。

我们可以把主屏幕看成你的画布,而其他屏幕则“在你的脑海中”——你已经知道如何绘制它们了。

当你调用 blit 函数时,你会在表面上盖上你要画的内容,覆盖掉任何被重叠的像素。这就是为什么你需要重新将整个屏幕涂黑,以便在移动对象时不会在绘画上留下污点。

正如 Mark 已经提到的,你可以使用一个函数来画圆,或者先将其 blit 到一个新的表面上,然后再将其 blit 到屏幕表面上。

如果你有一个更复杂的表面——曲线、文本等,你就不需要为此创建一个表面,因此你不必进行任何昂贵的计算,只需要进行绘画。不过这样做的缺点是,你的程序会占用更多的内存,所以你必须在这两者之间做出选择。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接