问题
I'm confused by the fact that in my code the sprite's coordinates don't seem to change where it is. Putting (200, 200)
would be the same as putting (900, 100000). So basically i cannot coordinate the sprite in a designated position. Can you help?
Turning credits to Ann Zen But the sprite problems on me Pygame sprite not turning accordingly to mouse
My code:
import pygame
from math import atan2, degrees
# tank = pygame.image.load('Sprite0.png')
wn = pygame.display.set_mode((400, 400))
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('Sprite0.png')
self.x = 0
self.y = 0
self.rect = self.image.get_rect()
def point_at(self, x, y):
rotated_image = pygame.transform.rotate(self.image, degrees(atan2(x-self.rect.x, y-self.rect.y)))
new_rect = rotated_image.get_rect(center=self.rect.center)
wn.fill((255, 255, 255))
wn.blit(rotated_image, new_rect.topleft)
player = Player()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == pygame.MOUSEMOTION:
player.point_at(*pygame.mouse.get_pos())
# wn.blit(tank, Player)
pygame.display.update()
回答1:
Please read the answer to How to rotate an image(player) to the mouse direction? carefully. The calculation of the angle
degrees(atan2(x-self.rect.x, y-self.rect.y))
works by chance. It works, because atan2(x, y) == atan2(-y, x)-pi/2
.
The angle of a vector (x, y) is atan2(y, x)
. The y-axis needs to be reversed (-y
) as the y-axis is generally pointing up, but in the PyGame coordinate system the y-axis is pointing down. Most likely your Sprite points upwards and you want to compute:
angle = degrees(atan2(self.rect.y - y, x - self.rect.x)) - 90
respectively
direction = pygame.math.Vector2(x, y) - self.rect.center
angle = direction.angle_to((0, -1))
See also How to know the angle between two points?
The Sprite is drawn at the location stored in rect
attribute. You don't need the x
and y
attribute at all. Just set the location of the rectangle (rect
).
Add x and y arguments to the constructor:
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('Sprite0.png')
self.rect = self.image.get_rect(center = (x, y))
Add a method move
and use pygame.Rect.move_ip to change the position of the Sprite:
class Player(pygame.sprite.Sprite):
# [...]
def move(self, x, y):
self.rect.move_ip(x, y)
Invoke move
, when you want to change the position of the Sprite:
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
player.move(0, -1)
if keys[pygame.K_s]:
player.move(0, 1)
if keys[pygame.K_a]:
player.move(-1, 0)
if keys[pygame.K_d]:
player.move(1, 0)
respectively
keys = pygame.key.get_pressed()
player.move(keys[pygame.K_d]-keys[pygame.K_a], keys[pygame.K_s]-keys[pygame.K_w])
A Sprite should always be contained in a pygame.sprite.Group. See pygame.sprite.Group.draw():
Draws the contained Sprites to the Surface argument. This uses the
Sprite.image
attribute for the source surface, andSprite.rect
for the position.
Add a Group and add the Sprite to the Group:
player = Player(200, 200)
all_sprites = pygame.sprite.Group(player)
Invoke draw
when you want to draw all the Sprites in the Group:
all_sprites.draw(wn)
Ensure that the rotated image is stored in the image
attribute:
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.original_image = pygame.image.load('Sprite0.png')
self.image = self.original_image
self.rect = self.image.get_rect(center = (x, y))
def point_at(self, x, y):
direction = pygame.math.Vector2(x, y) - self.rect.center
angle = direction.angle_to((0, -1))
self.image = pygame.transform.rotate(self.original_image, angle)
self.rect = self.image.get_rect(center=self.rect.center)
# [...]
Minimal example: repl.it/@Rabbid76/PyGame-SpriteRotateToMouse
import pygame
wn = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.original_image = pygame.image.load('Sprite0.png')
self.image = self.original_image
self.rect = self.image.get_rect(center = (x, y))
self.velocity = 5
def point_at(self, x, y):
direction = pygame.math.Vector2(x, y) - self.rect.center
angle = direction.angle_to((0, -1))
self.image = pygame.transform.rotate(self.original_image, angle)
self.rect = self.image.get_rect(center=self.rect.center)
def move(self, x, y):
self.rect.move_ip(x * self.velocity, y * self.velocity)
player = Player(200, 200)
all_sprites = pygame.sprite.Group(player)
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
player.point_at(*pygame.mouse.get_pos())
keys = pygame.key.get_pressed()
player.move(keys[pygame.K_d]-keys[pygame.K_a], keys[pygame.K_s]-keys[pygame.K_w])
wn.fill((255, 255, 255))
all_sprites.draw(wn)
pygame.display.update()
If you want to move the object in the direction of the mouse, then you have to add a direction
and position
attribute of type pygame.math.Vecotr2. The direction is changed in point_at
and the position is changet in move
, dependent on the direction. The rect
attribute has to be updated.
Minimal example: repl.it/@Rabbid76/PyGame-SpriteFollowMouse
import pygame
wn = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.original_image = pygame.image.load('Sprite0.png')
self.image = self.original_image
self.rect = self.image.get_rect(center = (x, y))
self.direction = pygame.math.Vector2((0, -1))
self.velocity = 5
self.position = pygame.math.Vector2(x, y)
def point_at(self, x, y):
self.direction = pygame.math.Vector2(x, y) - self.rect.center
if self.direction.length() > 0:
self.direction = self.direction.normalize()
angle = self.direction.angle_to((0, -1))
self.image = pygame.transform.rotate(self.original_image, angle)
self.rect = self.image.get_rect(center=self.rect.center)
def move(self, x, y):
self.position -= self.direction * y * self.velocity
self.position += pygame.math.Vector2(-self.direction.y, self.direction.x) * x * self.velocity
self.rect.center = round(self.position.x), round(self.position.y)
player = Player(200, 200)
all_sprites = pygame.sprite.Group(player)
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == pygame.MOUSEMOTION:
player.point_at(*event.pos)
keys = pygame.key.get_pressed()
player.move(keys[pygame.K_d]-keys[pygame.K_a], keys[pygame.K_s]-keys[pygame.K_w])
wn.fill((255, 255, 255))
all_sprites.draw(wn)
pygame.display.update()
回答2:
Remove the elif event.type == pygame.MOUSEMOTION:
block, and put the player.point_at(*pygame.mouse.get_pos())
directly into the while
loop.
Create a clock so that the sprite won't zip out of the screen.
Finally, add
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
player.rect.y -= 1
if keys[pygame.K_s]:
player.rect.y += 1
if keys[pygame.K_a]:
player.rect.x -= 1
if keys[pygame.K_d]:
player.rect.x += 1
to control the player.
Example:
import pygame
from math import atan2, degrees
wn = pygame.display.set_mode((400, 400))
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((30, 40), pygame.SRCALPHA)
self.image.fill((255, 0, 0))
self.rect = self.image.get_rect(topleft=(185, 180))
def point_at(self, x, y):
rotated_image = pygame.transform.rotate(self.image, degrees(atan2(x-self.rect.x, y-self.rect.y)))
new_rect = rotated_image.get_rect(center=self.rect.center)
wn.fill((0, 0, 0))
wn.blit(rotated_image, new_rect.topleft)
player = Player()
clock = pygame.time.Clock() # Create the clock
while True:
clock.tick(30) # Use the clock
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
keys = pygame.key.get_pressed() # Get al the pressed keys
if keys[pygame.K_w]:
player.rect.y -= 1
if keys[pygame.K_s]:
player.rect.y += 1
if keys[pygame.K_a]:
player.rect.x -= 1
if keys[pygame.K_d]:
player.rect.x += 1
player.point_at(*pygame.mouse.get_pos()) # Put this here
pygame.display.update()
Output:
来源:https://stackoverflow.com/questions/64805267/how-do-i-rotate-a-sprite-towards-the-mouse-and-move-it