使用精灵在pygame中旋转图像

时间:2016-07-29 21:25:03

标签: pygame sprite pygame-surface

我在pygame中制作游戏,我想旋转图像。 pygame.transform.rotate不断增加图像尺寸,所以我想也许精灵可以帮助我旋转图像。但问题更复杂,我想点击表面上的某个地方,我希望图像转向那个方向,因此对象可以进行无限次的旋转。有人可以帮我解释一下如何做到这一点吗?

1 个答案:

答案 0 :(得分:2)

图像更改尺寸

pygame中的曲面无法旋转;它们都具有水平宽度和垂直高度。加载图像时,pygame会创建一个Surface,其水平宽度和垂直高度等于图像。旋转图像时,45度pygame必须创建一个原始图像适合的新Surface。新Surface的水平宽度和垂直高度必须是能够适合图像的图像。

这应该是。如果您遇到的问题是碰撞检测,我建议您尝试其他形式的碰撞检测,如圆形,或继续使用矩形但最小化它的大小。

向特定方向旋转

您可能应该使用矢量将图像转到您单击的位置。我通常创建自己的矢量类,但pygame has its own Vector classes除非你想为学习目的创建自己的矢量类,否则应该使用它。如果您不了解add, subtract, scalar multiplynormalizecalculate angle between向量,可能需要阅读它们,否则可能会有点复杂。无论如何,这只是基本矢量类的一小部分:

import math

class Vector2D(object):

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Vector2D(self.x + other.x, self.y + other.y)

    def __sub__(self, other):
        return Vector2D(self.x - other.x, self.y - other.y)

    def __mul__(self, other):
        if isinstance(other, Vector2D):
            # Vector multiplication
            return self.x * other.x + self.y * other.y
        else:
            # Scalar multiplication
            return Vector2D(self.x * other, self.y * other)

    __radd__ = __add__
    __rsub__ = __sub__
    __rmul__ = __mul__

    def length(self):
        return (self.x ** 2 + self.y ** 2) ** (1/2)

    def angle_to(self, other, radians=False):
        """Will return the angle between this vector and the other vector."""
        if self.length() == 0 or other.length() == 0:
            return 0
        if not radians:
            return (360 / (2 * math.pi)) * (math.atan2(other.y, other.x) - math.atan2(self.y, self.x))
        else:
            return math.atan2(other.y, other.x) - math.atan2(self.y, self.x)

    def normalize(self):
        if self.length() == 0:
            return Vector2D(0, 0)
        return Vector2D(self.x / self.length(), self.y / self.length())

然后我要做的是为图像创建一个具有位置原始图像属性的类。当您旋转图像时,pygame会创建一个旋转的新图像。通过这样做,您的图像会丢失一些信息,从而失去一些质量这就是为什么你总是应该旋转原始图像而不是旋转副本。

class Player(pygame.sprite.Sprite):

    def __init__(self, image_path, pos=(0, 0)):
        super(Player, self).__init__()
        self.original_image = pygame.image.load(image_path).convert()  # REMEMBER TO CONVERT!
        self.image = self.original_image  # This will reference our rotated copy.
        self.rect  = self.image.get_rect()
        self.position = Vector2D(*pos)


    def update(self):
        """Updates the player's orientation."""

        # Create a vector pointing at the mouse position.
        mouse_position = Vector2D(*pygame.mouse.get_pos())

        # Create a vector pointing from the image towards the mouse position.
        relative_mouse_position = mouse_position - self.position  

        # Calculate the angle between the y_axis and the vector pointing from the image towards the mouse position.
        y_axis = Vector2D(0, -1)
        angle = -y_axis.get_angle(relative_mouse_position)  # Negating because pygame rotates counter-clockwise.

        # Create the rotated copy.
        self.image = pygame.transform.rotate(self.original, angle).convert()  # Angle is absolute value!

        # Make sure your rect represent the actual Surface.
        self.rect = self.image.get_rect()

        # Since the dimension probably changed you should move its center back to where it was.
        self.rect.center = self.position.x, self.position.y

一个简短的例子

import pygame
pygame.init()

BACKGROUND_COLOR = (0, 0, 0)


class Player(pygame.sprite.Sprite):

    def __init__(self, position=(0, 0)):
        super(Player, self).__init__()
        self.original_image = pygame.Surface((32, 32))
        pygame.draw.lines(self.original_image, (255, 255, 255), True, [(16, 0), (0, 31), (31, 31)])
        self.image = self.original_image  # This will reference our rotated copy.
        self.rect  = self.image.get_rect()
        self.position = pygame.math.Vector2(*position)

    def update(self):
        """Updates the players orientation."""
        # Create a vector pointing at the mouse position.
        mouse_position = pygame.math.Vector2(*pygame.mouse.get_pos())

        # Create a vector pointing from the image towards the mouse position.
        relative_mouse_position = mouse_position - self.position

        # Calculate the angle between the y_axis and the vector pointing from the image towards the mouse position.
        y_axis = pygame.math.Vector2(0, -1)
        angle  = -y_axis.angle_to(relative_mouse_position )  # Subtracting because pygame rotates counter-clockwise.

        # Create the rotated copy.
        self.image = pygame.transform.rotate(self.original_image, angle).convert()  # Angle is absolute value!

        # Make sure your rect represent the actual Surface.
        self.rect = self.image.get_rect()

        # Since the dimension probably changed you should move its center back to where it was.
        self.rect.center = self.position.x, self.position.y


screen = pygame.display.set_mode((720, 480))
player = Player(position=(300, 250))

while True:
    # Handle events
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            quit()

    # Update
    player.update()

    # Render
    screen.fill(BACKGROUND_COLOR)
    screen.blit(player.image, player.rect)
    pygame.display.update()