简短回答:
当您使用 pygame.transform.rotate
旋转图像时,新旋转后的图像尺寸会增加。您必须确保旋转后的图像位置在原始图像中心的基础上进行调整。为此,获取原始图像的矩形并设置其位置。获取旋转后的图像的矩形并通过原始矩形的中心位置设置其中心位置。
从函数red_center
返回一个元组,包含旋转后的图像和旋转后图像的边界矩形:
def rot_center(image, angle, x, y):
rotated_image = pygame.transform.rotate(image, angle)
new_rect = rotated_image.get_rect(center = image.get_rect(center = (x, y)).center)
return rotated_image, new_rect
或者编写一个函数,对图像进行旋转和 .blit
操作:
def blitRotateCenter(surf, image, topleft, angle):
rotated_image = pygame.transform.rotate(image, angle)
new_rect = rotated_image.get_rect(center = image.get_rect(topleft = topleft).center)
surf.blit(rotated_image, new_rect)
长话短说:
一个图像(pygame.Surface
)可以通过pygame.transform.rotate
进行旋转。
如果在循环中逐步执行该操作,那么图像会变形并迅速增大:
while not done:
image = pygame.transform.rotate(image, 1)
screen.blit(image, pos)
pygame.display.flip()
![](https://istack.dev59.com/AXgmY.gif)
这是因为旋转图像的边界矩形总是大于原始图像的边界矩形(除了某些90度倍数的旋转)。
由于多个复制,图像发生了扭曲。每次旋转都会产生小误差(不精确)。误差的总和在增加,图像会损坏。
可以通过保留原始图像并从原始图像生成一个单独的旋转操作图像来修复这个问题。
angle = 0
while not done:
rotated_image = pygame.transform.rotate(image, angle)
angle += 1
screen.blit(rotated_image, pos)
pygame.display.flip()
![](https://istack.dev59.com/vrhgt.gif)
现在,由于图像的大小通过旋转而改变,其位置似乎任意更改,而原点始终是图像的边界矩形的左上角。
可以通过比较旋转前后的图像轴对齐边界框来进行补偿。
以下数学计算使用pygame.math.Vector2
。请注意在屏幕坐标中,y 指向屏幕下方,但是数学 y 轴从底部指向顶部。这导致在计算期间必须“翻转” y 轴。
设置一个包含边界框 4 个角点的列表:
w, h = image.get_size()
box = [pygame.math.Vector2(p) for p in [(0, 0), (w, 0), (w, -h), (0, -h)]]
通过pygame.math.Vector2.rotate
将向量旋转到角点位置:
box_rotate = [p.rotate(angle) for p in box]
获取旋转后点的最小值和最大值:
min_box = (min(box_rotate, key=lambda p: p[0])[0], min(box_rotate, key=lambda p: p[1])[1])
max_box = (max(box_rotate, key=lambda p: p[0])[0], max(box_rotate, key=lambda p: p[1])[1])
通过将旋转框的最小值添加到位置,计算图像左上角点的“补偿”原点。对于y坐标,max_box[1]
是最小值,因为沿y轴“翻转”:
origin = (pos[0] + min_box[0], pos[1] - max_box[1])
rotated_image = pygame.transform.rotate(image, angle)
screen.blit(rotated_image, origin)
![](https://istack.dev59.com/IKZ6a.gif)
甚至可以在原始图像上定义一个枢轴点。计算从图像中心到枢轴的偏移向量并旋转该向量。可以使用pygame.math.Vector2
表示向量,并可使用pygame.math.Vector2.rotate
进行旋转。请注意,pygame.math.Vector2.rotate
的旋转方向与pygame.transform.rotate
相反。因此,必须反转角度:
计算从图像中心到枢轴的向量:
image_rect = image.get_rect(topleft = (pos[0] - originPos[0], pos[1]-originPos[1]))
offset_center_to_pivot = pygame.math.Vector2(pos) - image_rect.center
旋转向量。
rotated_offset = offset_center_to_pivot.rotate(-angle)
计算旋转图像的中心点:
rotated_image_center = (pos[0] - rotated_offset.x, pos[1] - rotated_offset.y)
旋转并绘制图像:
rotated_image = pygame.transform.rotate(image, angle)
rotated_image_rect = rotated_image.get_rect(center = rotated_image_center)
screen.blit(rotated_image, rotated_image_rect)
在下面的示例程序中,函数
blitRotate(surf, image, pos, originPos, angle)
执行所有上述步骤,并将旋转后的图像“ blit ”到表面上。
这意味着,blitRotate
的第二个参数(pos
)是窗口中枢轴点的位置,第三个参数(originPos
)是旋转表面上枢轴点的位置:
最小示例:
repl.it/@Rabbid76/PyGame-RotateAroundPivot
![](https://istack.dev59.com/qnDPP.gif)
import pygame
pygame.init()
screen = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
def blitRotate(surf, image, pos, originPos, angle):
image_rect = image.get_rect(topleft = (pos[0] - originPos[0], pos[1]-originPos[1]))
offset_center_to_pivot = pygame.math.Vector2(pos) - image_rect.center
rotated_offset = offset_center_to_pivot.rotate(-angle)
rotated_image_center = (pos[0] - rotated_offset.x, pos[1] - rotated_offset.y)
rotated_image = pygame.transform.rotate(image, angle)
rotated_image_rect = rotated_image.get_rect(center = rotated_image_center)
surf.blit(rotated_image, rotated_image_rect)
pygame.draw.rect(surf, (255, 0, 0), (*rotated_image_rect.topleft, *rotated_image.get_size()),2)
def blitRotate2(surf, image, topleft, angle):
rotated_image = pygame.transform.rotate(image, angle)
new_rect = rotated_image.get_rect(center = image.get_rect(topleft = topleft).center)
surf.blit(rotated_image, new_rect.topleft)
pygame.draw.rect(surf, (255, 0, 0), new_rect, 2)
try:
image = pygame.image.load('AirPlaneFront.png')
except:
text = pygame.font.SysFont('Times New Roman', 50).render('image', False, (255, 255, 0))
image = pygame.Surface((text.get_width()+1, text.get_height()+1))
pygame.draw.rect(image, (0, 0, 255), (1, 1, *text.get_size()))
image.blit(text, (1, 1))
w, h = image.get_size()
angle = 0
done = False
while not done:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pos = (screen.get_width()/2, screen.get_height()/2)
screen.fill(0)
blitRotate(screen, image, pos, (w/2, h/2), angle)
angle += 1
pygame.draw.line(screen, (0, 255, 0), (pos[0]-20, pos[1]), (pos[0]+20, pos[1]), 3)
pygame.draw.line(screen, (0, 255, 0), (pos[0], pos[1]-20), (pos[0], pos[1]+20), 3)
pygame.draw.circle(screen, (0, 255, 0), pos, 7, 0)
pygame.display.flip()
pygame.quit()
exit()
另请参见旋转表面和以下问题的答案: