【问题标题】:Is there a way to copy a certain section of a surface using Surface.copy()?有没有办法使用 Surface.copy() 复制曲面的某个部分?
【发布时间】:2019-09-21 23:35:29
【问题描述】:

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

我查看了 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.:我是这个网站的新手,如果我做错了什么请告诉我!

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

【问题讨论】:

    标签: python animation pygame updating surface


    【解决方案1】:

    你想做的事可以通过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) 
    

    【讨论】:

    • 太棒了!正是我想要的,谢谢!
    【解决方案2】:

    您可以使用subsurface 指定要复制的区域,然后在返回的Surface 上调用copy

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

    另外请注意,您永远不应该在游戏中使用time.sleep。当sleep 阻止你的游戏进程时,你的游戏不能处理事件,所以你例如这段时间无法退出游戏。此外,如果您不通过调用pygame.event.get 处理事件,您的游戏窗口可能不会被重绘;一旦事件队列因为你从不调用pygame.event.get而填满,你的游戏就会冻结。

    【讨论】:

    • 感谢您的帮助,是的,我知道使用time.sleep 是有害的,我只是用它来演示所需的结果,而没有实际制作游戏循环。我将研究地下并用我的发现更新我的帖子。
    • 在做了一些研究之后,使用次表面 blit 到同一表面上不会起作用,因为 pygame 出于某种原因会自动锁定次表面。请参阅:stackoverflow.com/questions/4117407/…
    • 那是我在我的回答中说你必须复制地下。
    猜你喜欢
    • 2017-12-16
    • 2019-08-26
    • 1970-01-01
    • 1970-01-01
    • 2011-10-09
    • 1970-01-01
    • 1970-01-01
    • 2022-08-11
    • 2013-03-22
    相关资源
    最近更新 更多