有没有办法使用 Surface.copy() 复制曲面的某个部分?

Is there a way to copy a certain section of a surface using Surface.copy()?

我是脏矩形动画的新手,我目前正在尝试存储主显示表面的快照 window,但是我只想存储我的项目将被 blit 的区域所以下一帧我可以调用这个存储的快照而不是重新 blitting 整个背景。

我查看了 Surface.copy() 的文档,但它没有参数,除了 pygame.pixelcopy() 我找不到任何类似的东西,据我所知,这不是什么我在寻找。如果 Surface.copy() 不是我要找的,请告诉我其他选择。

import pygame, time
pygame.init()
screen = pygame.display.set_mode((500, 500))

screen.fill((128, 128, 128))
pygame.display.update()

#immagine a complex pattern being blit to the screen here
pygame.draw.rect(screen, (128, 0, 0), (0, 0, 50, 50))
pygame.draw.rect(screen, (0, 128, 0), (50, 0, 50, 50))
pygame.draw.rect(screen, (0, 0, 128), (200, 0, 50, 50))

#my complex background area that i want to save ()
area_to_save = pygame.Rect(0, 0, 100, 50)

rest_of_background = pygame.Rect(200, 0, 50, 50)

#updating for demo purposes
dirty_rects = [area_to_save, rest_of_background]
for rect in dirty_rects:
    pygame.display.update(rect)
temp_screen = screen.copy()

time.sleep(3)
#after some events happen and I draw the item thats being animated onto the background
item_to_animate = pygame.Rect(35, 10, 30, 30)
pygame.draw.rect(screen, (0, 0, 0), item_to_animate)
pygame.display.update(item_to_animate)

time.sleep(3)
item_to_animate = pygame.Rect(50, 60, 30, 30)
pygame.draw.rect(screen, (0, 0, 0), item_to_animate)
#now that the item has moved, draw back old frame, which draws over the whole surface
screen.blit(temp_screen, (0, 0))
pygame.display.update()

#I understand swapping the drawing of the new item location to after temp_surface blit
#will provide me the desired outcome in this scenario but this is a compressed version of my problem
#so for simplicity sake, is there a way of not saving the whole surface, only those rects defined?

我希望此代码的输出显示我的背景 3 秒,然后黑色方块覆盖图案,再过 3 秒后,黑色方块出现在我的图案下方。

P.S.:我是这个网站的新手,如果我做错了什么请告诉我!

编辑:对于任何想知道此解决方案(先保存背景,然后在新项目位置被 blit 覆盖之前重新绘制保存的背景)是否比重绘整个背景然后 blit 更有效的人该项目在方格图案上使用简单的方形动画,每次都重新绘制整个背景,将我的整体 fps 从 1000(重新绘制背景之前)平均降低了 50% 左右。在使用脏矩形和上述方法时,我得到大约 900 fps。

您可以在返回的 Surface 上使用 subsurface to specify the area you want to copy, and then call copy

但请注意,这可能根本不会提高游戏的性能,因为复制大量 Surfaces 并不是免费的。只是尝试检查自己是否真的比每帧绘制一个背景表面更好。

另请注意,切勿在游戏中使用 time.sleep。虽然 sleep 正在阻止您的游戏进程,但您的游戏无法处理事件,因此您例如这段时间不能退出游戏。此外,如果您不通过调用 pygame.event.get 来处理事件,您的游戏的 window 可能不会被重新绘制;一旦事件队列因您从未调用 pygame.event.get 而填满,您的游戏就会冻结。

你想做的事情可以通过pygame.Surface.blit()实现。

创建一个具有确定大小的表面和 blit 到该表面的屏幕区域。请注意,bilt 的第三个参数是一个可选参数,它选择源表面的矩形区域:

# create a surface with size 'area_to_save.size'
temp_screen = pygame.Surface(area_to_save.size)

# blit the rectangular area 'area_to_save' from 'screen' to 'temp_screen' at (0, 0) 
temp_screen.blit(screen, (0, 0), area_to_save)