Pygame:如何旋转表面区域而不会使图像闪烁两次?

Pygame: How can I rotate a surface area without blitzing the images twice?

我正在尝试旋转整个屏幕,以及表面上的所有对象。但是当我 blit 表面时它只是创造了一个新的,给我留下了四个。换一种说法;我有两个不旋转的图像,两个是。我想删除那些不旋转的。 我已经找了几个小时试图找到答案。但是什么也没有。甚至可能...? (鼠标移动时旋转。)

# import os
import pygame
from pygame.locals import *

pygame.init()
screen = pygame.display.set_mode((500, 500), pygame.RESIZABLE)
pic = pygame.image.load("image.png")
pic2 = pygame.image.load("image.png")

pygame.display.flip()

angle = 1


while True:
    screen.fill((0, 0, 0))
    screen.blit(pic, (30, 20))
    screen.blit(pic2, (22, 40))
    # This creates a copy and blitz it. So there's 4, when there should be 2.
    # The 2 that are not rotating should not be on the screen.
    screen.blit(pygame.transform.rotate(screen, angle), (100, 0))  # x = 100 so you 
can see the other 2 behind it.
    pygame.display.flip()

    angle += 1

    pygame.event.pump()
    event = pygame.event.wait()
    if event.type == QUIT:
        pygame.display.quit()
    elif event.type == VIDEORESIZE:
        screen = pygame.display.set_mode(event.dict['size'], HWSURFACE | DOUBLEBUF 
| RESIZABLE)
        pygame.display.flip()

代码没有正确处理事件,这就是它只在鼠标移动时旋转的原因。

这两个图像不断出现,因为它们正在主循环中重新绘制。代码将它们绘制到 window,然后复制 window,旋转它,最后重新绘制它向右偏移。所以它已经在复制屏幕上的内容,因此您会看到 4 个对象。

我不是 100% 清楚你问题的措辞,但我想你只是想看到那些旋转的物体的图像。所以要做的第一件事是制作一个包含这些图像的离屏表面,并使用它进行旋转并绘制到实际屏幕上:

screen = pygame.display.set_mode((400, 400), pygame.RESIZABLE)
pic = pygame.image.load("emitter_128.png")
pic2 = pygame.image.load("big_alien.png")

# Make the original surface to rotate
original_surface = pygame.Surface( ( screen.get_rect().width, screen.get_rect().height ) )
original_surface.fill( (0, 0, 0))
original_surface.blit( pic, (30, 20))
original_surface.blit( pic2, (22, 40))

然后在代码主体中,旋转 original_surface,并将其绘制到屏幕上。

# This creates a copy and blitz it. So there's 4, when there should be 2.
# The 2 that are not rotating should not be on the screen.
screen.fill( ( 0, 0, 50 ) )
if ( rotating ):
    angle += 1
    rotated_surface = pygame.transform.rotate( original_surface, angle )
    rotated_surface_rect = rotated_surface.get_rect()
    rotated_surface_rect.center = screen_centre

screen.blit( rotated_surface, rotated_surface_rect )

当方形位图图像旋转时,尺寸会发生变化,因为结果(比如现在的菱形,角朝上)仍然必须适合方形位图。如果你一直画到同一个坐标,旋转看起来很不稳定。

解决此问题的一种方法是围绕其 中心 绘制旋转位图,使中心点保持在屏幕上的相同位置。这会导致位图似乎在围绕自身旋转(围绕它的质心)。为此,我们需要将位图的中心移动到所需的屏幕坐标。这就是为什么我们需要处理 rotated_surface Rect.

注意:选择可怕的闪烁背景颜色组合是为了说明哪个部分是旋转位图,哪个部分是它后面的屏幕。

对于糟糕的动画 .GIF 帧率表示歉意。在屏幕上非常流畅。

参考代码:

import pygame

pygame.init()
SURFACE = pygame.HWSURFACE | pygame.DOUBLEBUF | pygame.RESIZABLE
screen  = pygame.display.set_mode((400, 400), SURFACE )
pic1    = pygame.image.load("emitter_128.png")
pic2    = pygame.image.load("big_alien.png")

# Make the original surface to rotate
original_surface = pygame.Surface( ( screen.get_rect().width, screen.get_rect().height ) )
original_surface.fill( (0, 0, 0))
original_surface.blit( pic1, (30, 20))
original_surface.blit( pic2, (22, 40))

# We need to centre the image so the rotation looks smooth
screen_centre = ( screen.get_rect().width//2, screen.get_rect().height//2 )

angle = 1
rotating = True  # used to pause rotation
running  = True  # used to exit
while running:
    # Handle user-input
    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            running = False          # exit
        elif ( event.type == pygame.KEYDOWN ):
            rotating = not rotating  # pause rotation on any key
        elif ( event.type == pygame.VIDEORESIZE ):
            screen = pygame.display.set_mode(event.dict['size'], SURFACE )
            screen_centre = ( screen.get_rect().width//2, screen.get_rect().height//2 )

    # This creates a copy and blitz it. So there's 4, when there should be 2.
    # The 2 that are not rotating should not be on the screen.
    # screen.fill( ( 0, 0, 50 ) ) - use for horrible background
    screen.fill( ( 0, 0, 0 ) )
    if ( rotating ):
        angle += 1
        rotated_surface = pygame.transform.rotate( original_surface, angle )
        rotated_surface_rect = rotated_surface.get_rect()
        rotated_surface_rect.center = screen_centre

    # finally draw the rotated bitmap to the screen
    screen.blit( rotated_surface, rotated_surface_rect )

    # Update the window
    pygame.display.flip()

pygame.display.quit()