1

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

4

1 回答 1

2

图像改变尺寸

pygame 中的表面不能旋转;它们都有水平宽度和垂直高度。当您加载图像时,pygame 会创建一个水平宽度和垂直高度等于图像的 Surface。当您将图像旋转 45 度时,pygame 必须创建一个适合原始图像的新 Surface。新 Surface 的水平宽度和垂直高度必须是图像假设才能适合图像。

这应该是。如果您遇到的问题与碰撞检测有关,我建议您尝试其他形式的碰撞检测,例如圆形,或者继续使用矩形,但将其尺寸最小化。

向特定方向旋转

您可能应该使用矢量使图像转向您单击的位置。我通常创建自己的向量类,但pygame 有自己的向量类,除非你想创建自己的用于学习目的,否则应该使用它们。如果您不知道如何加、减、标量乘法归一化计算向量之间的角度,您可能需要阅读它,否则可能会有点复杂。无论如何,这是基本向量类的一小部分:

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())

然后我要做的是为您的图像创建一个具有属性positionoriginal image的类。当您旋转图像时,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()
于 2016-07-30T11:54:30.460 回答