Forgotten_tea
Forgotten_tea

Reputation: 75

How do I make smooth movement + rotation in pygame?

I am trying to make a spaceship move towards the mouse pointer, rotating to follow the pointer if it moves around. Currently, the rotation works fine and the linear movement works fine, but for some reason if the ship rotates and moves simultaneously, it sort of shakes in place while rotating and doesn't move forward any more. Here is a gif of my problem for clarification. Below I have the relevant code.

EDIT: I just posted the entire class to hopefully make things less confusing.

class player():
    def __init__(self, x_position, y_position, length, height):
        self.x = x_position
        self.y = y_position
        self.l = length
        self.h = height
        self.player_ship = pygame.transform.scale(ships[0], (128, 128))
        self.angle = 0
    def draw(self, win):
        cx, cy = pygame.mouse.get_pos()
        img_copy = pygame.transform.rotate(self.player_ship, math.atan2(self.x - cx, self.y - cy)*57.2957795)
        win.blit(img_copy, (self.x - int(img_copy.get_width() / 2), self.y - int(img_copy.get_height() / 2)))
    def move(self, speed):
        cx, cy = pygame.mouse.get_pos()
        self.angle = math.atan2(cx - self.x, cy - self.y)*57.2957795
        movement_x = math.cos(self.angle) * speed
        movement_y = math.sin(self.angle) * speed
        self.x -= movement_x
        self.y += movement_y

I read somewhere that I should not store my location as integers but I'm not completely sure how else to track location. I greatly appreciate any tips or pointer anyone has to offer.

Upvotes: 4

Views: 1748

Answers (1)

Rabbid76
Rabbid76

Reputation: 210909

The issue is caused by the code which rotates the sprite.

Rotate the image, and get a pygame.Rect of the coated image. Set the center of the rectangle by the position of the object. Use the rectangle to blit the image.
See How do I rotate an image around its center using Pygame?.

img_copy = pygame.transform.rotate(self.player_ship, self.angle)
rotated_rect = img_copy.get_rect(center = (round(self.x), round(self.y)))

To rotate the image it is sufficient to compute the unit direction vector [See Unit vector.)] from the current position to the mouse position. Scale the vector by the speed and add it to the position:

cx, cy = pygame.mouse.get_pos()
dx, dy = cx - self.x, cy - self.y
if abs(dx) > 0 or abs(dy) > 0:
    dist = math.hypot(dx, dy)
    self.x += min(dist, speed) * dx/dist
    self.y += min(dist, speed) * dy/dist

See the example

class player():
    def __init__(self, x_position, y_position, length, height):
        self.x = x_position
        self.y = y_position
        self.l = length
        self.h = height
        self.player_ship = pygame.transform.scale(ships[0], (128, 128))
        self.angle = 0
    
    def draw(self, win):
     
        cx, cy = pygame.mouse.get_pos()
        dx, dy = cx - self.x, cy - self.y
        if abs(dx) > 0 or abs(dy) > 0:
            self.angle = math.atan2(-dx, -dy)*57.2957795

        img_copy = pygame.transform.rotate(self.player_ship, self.angle)
        rotated_rect = img_copy.get_rect(center = (round(self.x), round(self.y)))
        
        win.blit(img_copy, rotated_rect)
    
    def move(self, speed):
        cx, cy = pygame.mouse.get_pos()
        dx, dy = cx - self.x, cy - self.y
        if abs(dx) > 0 or abs(dy) > 0:
            dist = math.hypot(dx, dy)
            self.x += min(dist, speed) * dx/dist
            self.y += min(dist, speed) * dy/dist

Upvotes: 2

Related Questions