我想围绕一个支点,这是不是在中心旋转图像表面的pygame的。
枢轴是图像中的绿色十字:
我知道游戏窗口中枢轴的位置。我如何在此时跟踪图像并同时围绕该点旋转它。
image = pygame.image.load("boomerang64.png")
pos = (200, 200)
angle = 0
while True:
# [...]
rotate_rect, rotate_image = ???? # rotate around green cross by angle
surf.blit(rotated_image, rotate_rect)
angle += 1
# [...]
Run Code Online (Sandbox Code Playgroud)
首先Surface必须定义枢轴在 上的位置:
image = pygame.image.load("boomerang64.png") # 64x64 surface
pivot = (48, 21) # position of the pivot on the image
Run Code Online (Sandbox Code Playgroud)
旋转图像时,其大小会增加。我们必须比较旋转前和旋转后图像的轴对齐边界框。
对于以下数学pygame.math.Vector2使用。注意屏幕坐标中的 y 指向屏幕下方,但数学 y 轴点从底部到顶部。这会导致在计算过程中必须“翻转”y 轴
使用边界框的 4 个角点设置一个列表,并将向量旋转到角点pygame.math.Vector2.rotate。最后找到旋转框的最小值。由于 pygame 中的 y 轴指向下方,因此必须通过找到旋转倒置高度的最大值( “ max(rotate(-h)) ”)来补偿这一点:
w, h = image.get_size()
box = [pygame.math.Vector2(p) for p in [(0, 0), (w, 0), (w, -h), (0, -h)]]
box_rotate = [p.rotate(angle) for p in box]
min_x, min_y = min(box_rotate, key=lambda p: p[0])[0], max(box_rotate, key=lambda p: p[1])[1]
Run Code Online (Sandbox Code Playgroud)
可以通过三角函数直接计算旋转向量的 x 和 y 分量来改进min_x和的计算:min_y
w, h = image.get_size()
sin_a, cos_a = math.sin(math.radians(angle)), math.cos(math.radians(angle))
min_x, min_y = min([0, sin_a*h, cos_a*w, sin_a*h + cos_a*w]), max([0, sin_a*w, -cos_a*h, sin_a*w - cos_a*h])
Run Code Online (Sandbox Code Playgroud)
通过将旋转框的最小值添加到与图像上的枢轴相关的位置,计算图像左上点的“补偿”原点:
origin = (pos[0] - originPos[0] + min_x - pivot_move[0], pos[1] - originPos[1] - min_y + pivot_move[1])
rotated_image = pygame.transform.rotate(image, angle)
screen.blit(rotated_image, origin)
Run Code Online (Sandbox Code Playgroud)
在以下示例程序中,该函数blitRotate(surf, image, pos, originPos, angle)执行上述所有步骤并将blit旋转图像发送到与显示器关联的 Surface:
surf 是目标曲面image 是必须旋转的表面和 blitpos是目标 Surface 上的枢轴位置surf(相对于 的左上角surf)originPos是image表面上枢轴的位置(相对于 的左上角image)angle 是以度为单位的旋转角度import pygame
import math
def blitRotate(surf, image, pos, originPos, angle):
# calcaulate the axis aligned bounding box of the rotated image
w, h = image.get_size()
sin_a, cos_a = math.sin(math.radians(angle)), math.cos(math.radians(angle))
min_x, min_y = min([0, sin_a*h, cos_a*w, sin_a*h + cos_a*w]), max([0, sin_a*w, -cos_a*h, sin_a*w - cos_a*h])
# calculate the translation of the pivot
pivot = pygame.math.Vector2(originPos[0], -originPos[1])
pivot_rotate = pivot.rotate(angle)
pivot_move = pivot_rotate - pivot
# calculate the upper left origin of the rotated image
origin = (pos[0] - originPos[0] + min_x - pivot_move[0], pos[1] - originPos[1] - min_y + pivot_move[1])
# get a rotated image
rotated_image = pygame.transform.rotate(image, angle)
# rotate and blit the image
surf.blit(rotated_image, origin)
pygame.init()
size = (400,400)
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
image = pygame.image.load('boomerang64.png')
pivot = (48, 21)
angle, frame = 0, 0
done = False
while not done:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(0)
pos = (200 + math.cos(frame * 0.05)*100, 200 + math.sin(frame * 0.05)*50)
blitRotate(screen, image, pos, pivot, angle)
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.display.flip()
frame += 1
angle += 10
pygame.quit()
Run Code Online (Sandbox Code Playgroud)
同样的算法也可以用于Sprite。
在这种情况下,位置 ( self.pos)、枢轴 ( self.pivot) 和角度 ( self.angle) 是类的实例属性。在update方法中计算self.rect和self.image属性。
最小的例子:
repl.it/@Rabbid76/PyGame-RotateSpriteAroundOffCenterPivot
import pygame
import math
class SpriteRotate(pygame.sprite.Sprite):
def __init__(self, imageName, pos, pivot):
super().__init__()
self.image = pygame.image.load(imageName)
self.original_image = self.image
self.rect = self.image.get_rect(topleft = (pos[0]-pivot[0], pos[1]-pivot[1]))
self.pos = pos
self.pivot = pivot
self.angle = 0
def update(self):
# calcaulate the axis aligned bounding box of the rotated image
w, h = self.original_image.get_size()
sin_a, cos_a = math.sin(math.radians(self.angle)), math.cos(math.radians(self.angle))
min_x, min_y = min([0, sin_a*h, cos_a*w, sin_a*h + cos_a*w]), max([0, sin_a*w, -cos_a*h, sin_a*w - cos_a*h])
# calculate the translation of the pivot
pivot = pygame.math.Vector2(self.pivot[0], -self.pivot[1])
pivot_rotate = pivot.rotate(self.angle)
pivot_move = pivot_rotate - pivot
# calculate the upper left origin of the rotated image
origin = (self.pos[0] - self.pivot[0] + min_x - pivot_move[0], self.pos[1] - self.pivot[1] - min_y + pivot_move[1])
# get a rotated image
self.image = pygame.transform.rotate(self.original_image, self.angle)
self.rect = self.image.get_rect(topleft = (round(origin[0]), round(origin[1])))
self.angle += 10
pygame.init()
size = (400,400)
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
boomerang = SpriteRotate('boomerang64.png', (200, 200), (48, 21))
all_sprites = pygame.sprite.Group(boomerang)
frame = 0
done = False
while not done:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pos = (200 + math.cos(frame * 0.05)*100, 200 + math.sin(frame * 0.05)*50)
boomerang.pos = pos
all_sprites.update()
screen.fill(0)
all_sprites.draw(screen)
pygame.display.flip()
frame += 1
pygame.quit()
Run Code Online (Sandbox Code Playgroud)
如何使用 Pygame 围绕其中心旋转图像?
如何在图像的比例变大时围绕其中心旋转图像(在 Pygame 中)
| 归档时间: |
|
| 查看次数: |
846 次 |
| 最近记录: |