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, and Sprite.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()