Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/hadoop/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使用Pygame围绕图像中心旋转图像?_Python_Rotation_Pygame - Fatal编程技术网

Python 如何使用Pygame围绕图像中心旋转图像?

Python 如何使用Pygame围绕图像中心旋转图像?,python,rotation,pygame,Python,Rotation,Pygame,我一直在尝试使用pygame.transform.rotate()围绕图像中心旋转图像,但它不起作用。具体来说,挂起的部分是rot\u image=rot\u image.subground(rot\u rect.copy()。我得到一个例外: ValueError:表面积外的次表面矩形 以下是用于旋转图像的代码: def rot_center(image, angle): """rotate an image while keeping its center and size"""

我一直在尝试使用
pygame.transform.rotate()
围绕图像中心旋转图像,但它不起作用。具体来说,挂起的部分是
rot\u image=rot\u image.subground(rot\u rect.copy()
。我得到一个例外:

ValueError:表面积外的次表面矩形

以下是用于旋转图像的代码:

def rot_center(image, angle):
    """rotate an image while keeping its center and size"""
    orig_rect = image.get_rect()
    rot_image = pygame.transform.rotate(image, angle)
    rot_rect = orig_rect.copy()
    rot_rect.center = rot_image.get_rect().center
    rot_image = rot_image.subsurface(rot_rect).copy()
    return rot_image

发现问题:示例效果良好,但宽度和高度需要相等的尺寸。修复了图片,效果良好。

您正在删除旋转创建的矩形。您需要保留rect,,因为它在旋转时会改变大小。

如果要保留对象位置,请执行以下操作:
def rot_中心(图像、角度):
“”“旋转曲面,保持位置。”“”
loc=image.get_rect()。未定义中心#rot_图像
rot_sprite=pygame.transform.rotate(图像、角度)
rot_sprite.get_rect().center=loc
返回腐烂精灵
#或返回元组:(Surface,Rect)
#返回rot_sprite,rot_sprite.get_rect()

顶部答案存在一些问题:函数中需要提供上一个rect的位置,以便我们可以将其分配给新的rect,例如:

rect = new_image.get_rect(center=rect.center) 
在另一个答案中,位置是通过从原始图像创建新的rect获得的,但这意味着它将被定位在默认(0,0)坐标处

下面的例子应该可以正常工作。新rect需要旧rect的
中心
位置,因此我们也将其传递给函数。然后旋转图像,调用
get_rect
以获得具有正确大小的新rect,并将旧rect的
center
属性作为
center
参数传递。最后,将旋转后的图像和新的rect作为元组返回,并在主循环中解包

import pygame as pg


def rotate(image, rect, angle):
    """Rotate the image while keeping its center."""
    # Rotate the original image without modifying it.
    new_image = pg.transform.rotate(image, angle)
    # Get a new rect with the center of the old rect.
    rect = new_image.get_rect(center=rect.center)
    return new_image, rect


def main():
    clock = pg.time.Clock()
    screen = pg.display.set_mode((640, 480))
    gray = pg.Color('gray15')
    blue = pg.Color('dodgerblue2')

    image = pg.Surface((320, 200), pg.SRCALPHA)
    pg.draw.polygon(image, blue, ((0, 0), (320, 100), (0, 200)))
    # Keep a reference to the original to preserve the image quality.
    orig_image = image
    rect = image.get_rect(center=(320, 240))
    angle = 0

    done = False
    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True

        angle += 2
        image, rect = rotate(orig_image, rect, angle)

        screen.fill(gray)
        screen.blit(image, rect)
        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()

下面是另一个旋转pygame精灵的示例

import pygame as pg


class Entity(pg.sprite.Sprite):

    def __init__(self, pos):
        super().__init__()
        self.image = pg.Surface((122, 70), pg.SRCALPHA)
        pg.draw.polygon(self.image, pg.Color('dodgerblue1'),
                        ((1, 0), (120, 35), (1, 70)))
        # A reference to the original image to preserve the quality.
        self.orig_image = self.image
        self.rect = self.image.get_rect(center=pos)
        self.angle = 0

    def update(self):
        self.angle += 2
        self.rotate()

    def rotate(self):
        """Rotate the image of the sprite around its center."""
        # `rotozoom` usually looks nicer than `rotate`. Pygame's rotation
        # functions return new images and don't modify the originals.
        self.image = pg.transform.rotozoom(self.orig_image, self.angle, 1)
        # Create a new rect with the center of the old rect.
        self.rect = self.image.get_rect(center=self.rect.center)


def main():
    screen = pg.display.set_mode((640, 480))
    clock = pg.time.Clock()
    all_sprites = pg.sprite.Group(Entity((320, 240)))

    while True:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                return

        all_sprites.update()
        screen.fill((30, 30, 30))
        all_sprites.draw(screen)
        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()
简短答复:

获取原始图像的矩形并设置位置。获取旋转图像的矩形,并通过原始矩形的中心设置中心位置。返回旋转图像和矩形的元组:

def rot_中心(图像、角度、x、y):
旋转的_image=pygame.transform.rotate(图像,角度)
new_rect=rotated_image.get_rect(center=image.get_rect(center=(x,y)).center)
返回旋转的图像,新建
或者编写一个函数,旋转并
。blit
图像:

def blitRotateCenter(冲浪、图像、左上角、角度):
旋转的_image=pygame.transform.rotate(图像,角度)
新建图片=旋转图片。获取图片(中心=图片。获取图片(左上=左上)。中心)
冲浪板(旋转图像,新直线)

长答覆:

对于以下示例和说明,我将使用由渲染文本生成的简单图像:

font=pygame.font.SysFont('Times New Roman',50)
text=font.render('image',False,(255,255,0))
image=pygame.Surface((text.get_width()+1,text.get_height()+1))
pygame.draw.rect(图像,(0,0255),(1,1,*text.get_size())
图像.blit(文本,(1,1))
图像()可以通过旋转进行旋转

如果在循环中逐步进行,则图像会失真并迅速增加:

未完成时:
# [...]
image=pygame.transform.rotate(图1)
屏幕显示(图像、位置)
pygame.display.flip()

这就是原因,因为旋转图像的边界矩形始终大于原始图像的边界矩形(某些旋转是90度的倍数除外)。
图像由于多次复制而失真。每次旋转都会产生一个小误差(不准确)。误差之和在增长,图像在衰减

这可以通过保持原始图像和“blit”图像来修复,该图像由原始图像的单个旋转操作生成

角度=0
虽然没有这样做:
# [...]
旋转的_image=pygame.transform.rotate(图像,角度)
角度+=1
屏幕。blit(旋转图像,位置)
pygame.display.flip()

现在,图像似乎可以任意改变其位置,因为图像的大小随旋转而改变,并且原点始终位于图像边框的左上角

这可以通过比较旋转前和旋转后图像的颜色进行补偿。
对于以下情况,使用了数学。注意:在屏幕坐标中,y点位于屏幕下方,但数学y轴点从底部到顶部。这导致在计算过程中y轴必须“翻转”

设置包含边界框的4个角点的列表:

w,h=image.get_size()
box=[pygame.math.Vector2(p)表示[(0,0),(w,0),(w,-h),(0,-h)]]
通过以下方式将向量旋转到角点:

box_rotate=[p.rotate(角度)表示框中的p]
获取旋转点的最小值和最大值:

min\u box=(min(box\u rotate,key=lambda p:p[0])[0],min(box\u 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\u框[1]
是最小值,因为沿y轴“翻转”:

原点=(位置[0]+最小值框[0],位置[1]-最大值框[1])
旋转的_image=pygame.transform.rotate(图像,角度)
屏幕。blit(旋转图像,原点)

甚至可以在原始图像上定义轴。必须计算枢轴相对于图像左上角的“平移”,并且图像的“blit”位置必须被平移所取代

定义轴,例如在图像中心:

pivot=pygame.math.Vector2(w/2,-h/2)
计算
game_display = pygame.display.set_mode((800, 600))

x = 0
y = 0
angle = 0

img = pygame.image.load("resources/image.png")
img = pygame.transform.scale(img, (50, 50)) # image size

def draw_img(self, image, x, y, angle):
    rotated_image = pygame.transform.rotate(image, angle) 
    game_display.blit(rotated_image, rotated_image.get_rect(center=image.get_rect(topleft=(x, y)).center).topleft)

# run this method with your loop
def tick():
    draw_img(img, x, y, angle)
angle=0
roll = true
while roll:
    # clean surface with your background color
    gameDisplay.fill(color)
    self.image = yourImage
    rotate_image = pygame.transform.rotate(self.image, angle)
    rect = rotate_image.get_rect()
    pos = (((your_surface_width - rect.width)/2),((your_surface_height - rect.height)/2))
    gameDisplay.blit(rotate_image,pos)
    pygame.display.flip()
    angle+=2
    if angle == 360:
        roll=False