私は pygame でゲームを作っていて、画像を回転させたいと思っていました。pygame.transform.rotate
画像のサイズを増やし続けたので、スプライトが画像の回転に役立つのではないかと考えました。しかし、問題はもっと複雑です。表面のどこかをクリックしたいのですが、画像をその方向に向けたいので、オブジェクトが作成できる回転数は無限にあります。誰かがこれを行う方法について説明してもらえますか?
1 に答える
画像の寸法変更
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())
次に、属性positionとoriginal 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()