简体   繁体   English

“pygame.display.update()”无法清除blit图像

[英]“pygame.display.update()” does not clear blit image

I have this main loop that updates an image at a point: 我有一个主循环,在一个点更新图像:

The loop: 循环:

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
    self.spaceship.buttons()
    self.spaceship.update(self.screen)
    pygame.display.update()

Where self.spaceship.buttons() is: self.spaceship.buttons()是:

def buttons(self):
    key = pygame.key.get_pressed()
    dist = 1
    if key[pygame.K_LEFT]:
        self.x -= dist
    elif key[pygame.K_RIGHT]:
        self.x += dist

And self.spaceship.update(self.screen) is defined: 并且定义了self.spaceship.update(self.screen)

def update(self, surface):
    surface.blit(self.image, (self.x, self.y))

After the main loop updates the key presses and "blits" the image onto the screen, it is supposed to update the display ( pygame.display.update() ), but the screen doesn't get cleared. 在主循环更新后,按键并将图像“blit”到屏幕上,它应该更新显示( pygame.display.update() ),但屏幕不会被清除。 This is what the display looks like, before and after moving: 这是移动前后显示的样子:

This is what the image looks like before the blit at a different position 这是图像在不同位置的blit之前的样子

This is what the image looks like after the blit is at a different position (after moving) 这是blit处于不同位置后的图像(移动后)

Why does pygame.display.update() not clear the previous frames of the image? 为什么pygame.display.update()不清除图像的先前帧?

It's quite simple, pygame doesn't do this for you. 这很简单,pygame不会为你做这件事。
pygame.display.update() updates the entire scene to show the user the new content you've "blipped". pygame.display.update()更新整个场景,向用户显示你已经“眨眼” 的新内容 It doesn't erase the past. 它不会抹去过去。

It can also be used to only update certain areas where you know you've done some updates (to speed up stuff). 它还可以用于仅更新您知道已完成更新的某些区域(以加快速度)。

Either, you do a flip() to update the entire graphical buffer to only contain the new content that you've blipped since the last flip (note that you'll loose everything not in this cycle): 或者,你执行flip()更新整个图形缓冲区,只包含自上次翻转后你已经闪过的新内容(请注意,你将放弃所有不在此循环中的内容):

while True:
    ...
    pygame.display.flip()

Or, you simply "draw" a black box before calling update. 或者,您只需在调用更新之前“绘制”一个黑盒子。
This is however, much more taxing. 然而,这更加沉重。

while True:
    ...
    self.screen.fill((0,0,0))
    pygame.display.update()

My recommendation is that you either use draw_rect and draw a black rectangle over the previous area where the spaceship was, or simply use flip() to swap to a new buffer page in the GPU. 我的建议是你要么使用draw_rect并在太空船所在的前一个区域上绘制一个黑色矩形,要么只是使用flip()来交换GPU中的新缓冲页面。 Doing a flip() is extremely fast in most implementations. 在大多数实现中,执行flip()非常快。

I come from a Pyglet background, so the speed performance of flip() , update() and draw_rect() might work differently in Pygame, but the fundamentals should be the same and my answer should be valid, if not please point this out. 我来自Pyglet背景,所以flip()update()draw_rect()的速度性能可能在Pygame中有所不同,但基本面应该是相同的,我的答案应该是有效的,如果不是,请指出这一点。

Pygame will only draw what you tell it to. Pygame只会绘制你告诉它的内容。 If you only tell it to draw your spaceship in a new position, it will do just that, and not touch any of the other things you have previously drawn. 如果你只是告诉它将你的宇宙飞船拉到一个新的位置,它就会做到这一点,而不是触及你之前绘制的任何其他东西。 This is useful, because it allows you to only update those portions of the screen that have changed since your last update, without having to draw everything everytime. 这很有用,因为它允许您仅更新自上次更新以来已更改的屏幕部分,而无需每次都绘制所有内容。

In order to have the spaceship move, you need to draw the background (in your case just black) over the position of the old spaceship, move the spaceship to its new position and then redraw the spaceship at this new position. 为了让宇宙飞船移动,你需要在旧宇宙飞船的位置上绘制背景(在你的情况下只是黑色),将宇宙飞船移动到新的位置,然后在这个新位置重绘宇宙飞船。

If your spaceship is a pygame.sprite.Sprite (meaning it inherts from pygame.sprite.Sprite ), you can use pygame.sprite.Group to make this whole process easier, by using pygame.sprite.Group.clear(screen,background) to draw the background over all Sprites and then use pygame.sprite.Group.draw(screen) to redraw the Sprites onto the screen once they have been moved. 如果你的太空船是一个pygame.sprite.Sprite (意思是它来自pygame.sprite.Sprite ),你可以使用pygame.sprite.Group来使整个过程变得更容易,使用pygame.sprite.Group.clear(screen,background)在所有Sprite上绘制背景,然后使用pygame.sprite.Group.draw(screen)将Sprite重新绘制到屏幕上。 This is especially useful once you have to keep track of more than one moving object. 一旦必须跟踪多个移动对象,这一点尤其有用。

Example using your code snippet: 使用代码段的示例:

sprites = pygame.sprite.Group(self.spaceship)
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
    sprites.clear(self.screen,clear_callback)
    self.spaceship.buttons()
    sprites.draw(self.screen)
    pygame.display.update()

With this callback function (slightly modified from the documentation ): 使用此回调函数(稍微修改文档 ):

def clear_callback(surf, rect):
color = (0, 0, 0)
surf.fill(color, rect)

This will only redraw the parts of your screen that have been updated, making redrawing very efficient. 这只会重新绘制已更新的屏幕部分,从而使重绘效率非常高。 In order to see this, simply change the color in the callback function to something like red. 为了看到这一点,只需将回调函数中的颜色更改为红色。 You will see the red background only appear where the display updated. 您将看到红色背景仅出现在显示更新的位置。 Every part of the screen that remains black has not been touched. 屏幕的每个部分仍然是黑色的。

Instead of the callback function, you could also make a surface the same size as your screen, fill it with black and use this background surface as your second parameter for sprites.clear() . 除了回调函数,您还可以使曲面与屏幕大小相同,用黑色填充它,并使用此背景曲面作为sprites.clear()第二个参数。

bg = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
bg.fill((0,0,0))
...
while True:
    ...
    sprites.clear(self.screen,bg)
    ...

Also note, if your game gets more complex and you have to handle more Sprites, you might want to redefine your spaceship.update() function. 另请注意,如果您的游戏变得更复杂并且您必须处理更多Sprite,则可能需要重新定义您的spaceship.update()函数。 Usually you would rename spaceship.buttons() to spaceship.update() , which would only move the position of the spaceship, and then use the Spritegroup to take care of drawing (instead of having the spaceship draw itself, as in your current spaceship.update() function). 通常你会将spaceship.buttons()重命名为spaceship.update() ,它只会移动宇宙飞船的位置,然后使用Spritegroup来处理绘图(而不是像现在的spaceship.update()函数)。 This would allow you to use pygame.sprite.Group.update() function to call update on all sprites in the group, making the drawing portion of the update loop a simple call of 这将允许您使用pygame.sprite.Group.update()函数来调用组中所有sprite的更新,使更新循环的绘图部分成为一个简单的调用

sprites.clear(screen,clear_callback)
sprites.update()
sprites.draw(screen)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM