Как правильно отобразить объект вращения с помощью pytmx? - PullRequest
0 голосов
/ 29 июня 2019

После многих исследований я не нашел ответа, когда я пытаюсь отобразить объект в pygame с pytmx, результат полностью искажается, потому что x, y изменяются с вращением.Я пытался использовать вращение матрицы, но для этого мне нужно знать исходный центр.Я не знаю, как его найти, потому что Tiled отправляет мне x, y после поворота ...

Поэтому моя цель - просто отобразить плитку объекта в pygame с помощью pytmx.

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 для объекта плитки:

image of the error

Ответы [ 2 ]

0 голосов
/ 29 июня 2019

Хорошо, я нашел решение, если кому-то нужно:

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))
0 голосов
/ 29 июня 2019

Я думаю, что вы делаете какую-то ошибку при прохождении позиции x и y объекта после вращения.Я никогда не использовал карту тайлов, поэтому не знаю специфики, но в pygame, когда вы передаете позицию в blit, вы должны передать координаты верхнего левого угла.Верхний левый угол Surface будет в этих координатах.

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

Здесь я не знаю, какие именно координаты object.x и object.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 извлечет координаты из прямоугольника.

Обратите внимание, что вращение выполняется в центре поверхности.После поворота, если угол не кратен 90 °, Поверхность увеличивается, так как квадрат Поверхности должен быть выровнен по экрану.Если есть альфа-канал, это не проблема, лишние пиксели прозрачны, но верхний левый угол изменится.

...