0

经过多次研究我没有找到答案,当我试图用 pytmx 在 pygame 中显示对象时,结果完全被破坏了,因为 x,y 随旋转而变化。我尝试使用矩阵旋转,但为此,我需要知道原始中心。我不知道怎么找到它,因为 Tiled 在旋转后发送给我,x,y...

所以我的目标只是用 pytmx 在 pygame 中显示对象图块。

import numpy
import math

angle = math.radians(-117.57) #rotation get with tiled, set - for cancel rotation
center_x = 148 #how to get this ?
center_y = 747 #and this
x = 126.82 #get with tiled
y = 679.54 #get with tiled

id_rotation = [ [math.cos(angle), -math.sin(angle)],
                [math.sin(angle), math.cos(angle)] ]
R = numpy.matrix(id_rotation)

id_position = [ [x - center_x],
                [y - center_y] ]
B = numpy.matrix(id_position)

id_center = [ [center_x],
              [center_y] ]
C = numpy.matrix(id_center)

print(numpy.dot(R, B) + C) #return original position before rotation

如果我只使用 pygame.transform.rotate:

if isinstance(layer, pytmx.TiledObjectGroup):
        for object in layer:
            if (object.image):
                assets_surface = pygame.Surface((object.width, object.height), pygame.SRCALPHA)
                assets_surface.blit(object.image, (0, 0))
                assets_surface_rotate = pygame.transform.rotate(assets_surface, -object.rotation)
                rdc.blit(assets_surface_rotate, (object.x, object.y))

对于瓷砖对象,我得到了错误的 x,y 位置:

错误的图像

4

2 回答 2

0

我认为您在旋转后传递对象的 x 和 y 位置时会出错。我从来没有使用过瓦片地图,所以我不知道具体细节,但是在 pygame 中,当您将位置传递给 时blit,您应该传递左上角的坐标。的左上角Surface将在这些坐标处。

rdc.blit(assets_surface_rotate, (object.x, object.y))

在这里我不知道坐标object.xobject.y确切的位置,但我敢打赌它们不是左上角,或者你的代码应该可以工作。

一般来说,要完成这类工作,您可以使用Sprite类或子类,这会很有帮助。

class TMSprite(pygame.sprite.Sprite):
    # Constructor. Create a Surface from a TileMap and set its position
    def __init__(self, tmo, x, y, width, height):
        # Call the parent class (Sprite) constructor
        super(TMSprite, self).__init__()

        # Create the image of the block
        self.image = pygame.Surface((width, height), pygame.SRCALPHA)
        self.image.blit(tmo.image, (0, 0))

        # Fetch the rectangle object that has the dimensions of the image
        # Set its position with the move method
        self.rect = self.image.get_rect().move(x, y)

    def rotate(self, angle):
        # TMSprite rotation on its center of a given angle
        rot_center = self.rect.center
        self.image = pygame.transform.rotate(self.image, angle)
        self.rect = self.image.get_rect()
        self.rect.center = rot_center

这就是您可以使用TMSprite该类重写您的代码段的方式。

if isinstance(layer, pytmx.TiledObjectGroup):
    for tmob in layer:
        if (tmob.image):
            x = tmob.x #x should be that of the top-left corner. Adjust the formula if tmob.x is not the top-left
            y = tmob.y #y should be that of the top-left corner. Adjust the formula if tmob.y is not the top-left
            assets_sprite = TMSprite(tmob, x, y, tmob.width, tmob.height)
            assets_sprite.rotate(-object.rotation)
            rdc.blit(assets_sprite.image, assets_sprite.rect)

在这里,我没有传递左上角坐标,而是将Rect精灵的 传递给blit. 该blit方法将从矩形中提取坐标。

请注意,旋转是在Surface的中心执行的。旋转后,如果角度不是 90° 的倍数,Surface 会被放大,因为 Surface 的正方形必须与屏幕对齐。如果有 alpha 通道没有问题,多余的像素是透明的,但左上角会改变。

于 2019-06-29T15:48:47.460 回答
0

好的,如果有人需要,我已经找到了解决方案:

elif isinstance(layer, pytmx.TiledObjectGroup):
        for Object in layer:
            if (Object.image):
                if Object.rotation != 0:
                    angle = math.radians(-Object.rotation)
                    center_x = Object.centerX
                    center_y = Object.centerY
                    Object_y = Object.y + Object.height

                    id_rotation = [ [math.cos(angle), -math.sin(angle)],
                                    [math.sin(angle), math.cos(angle)] ]
                    R = numpy.matrix(id_rotation)

                    id_position = [ [Object.x - center_x],
                                    [Object_y - center_y] ]
                    P = numpy.matrix(id_position)

                    id_center = [ [center_x],
                                [center_y] ]
                    C = numpy.matrix(id_center)

                    position_without_rotation = numpy.dot(R, P) + C

                    no_rotation_x = position_without_rotation[0]
                    no_rotation_y = position_without_rotation[1] - Object.height #Repere Tiled pas le meme que Pygame

                    Object_surface = pygame.Surface((Object.image.get_rect()[2], Object.image.get_rect()[3]), pygame.SRCALPHA)
                    Object_surface.blit(Object.image, (0, 0))
                    Object_surface_scale = pygame.transform.scale(Object_surface, (round(Object.width), round(Object.height)))
                    Object_surface_rotate = pygame.transform.rotate(Object_surface_scale, -Object.rotation) #Pygame va en anti horaire

                    extra_x = (Object_surface_rotate.get_rect()[2] - Object.width) / 2
                    extra_y = (Object_surface_rotate.get_rect()[3] - Object.height) / 2

                    rdc.blit(Object_surface_rotate, (no_rotation_x - extra_x, no_rotation_y - extra_y))
                else:
                    Object_surface = pygame.Surface((Object.image.get_rect()[2], Object.image.get_rect()[3]), pygame.SRCALPHA)
                    Object_surface.blit(Object.image, (0, 0))
                    Object_surface_scale = pygame.transform.scale(Object_surface, (round(Object.width), round(Object.height)))

                    rdc.blit(Object_surface_scale, (Object.x, Object.y))
于 2019-06-29T19:42:23.753 回答