HelloPeople1 0 Newbie Poster

Hi guys
I'm writing a top down shooter game in pygame and wanted to use sprites for my object. I got a character sprite working fairly well except I have two problems.
1. When I rotate my character the point of rotation is changing. This causes a uneven rotation in my character

2. I have a problem with rotating at the same time as moving. I can rotate after I have moved in a single direction for several seconds, but as soon as change directions, I can no longer rotate until I have waited another several seconds.

Here is my code:

import sys,os,math,random,pygame
from pygame.locals import *
#from engine import *

def distBetween(pointA = (0,0), pointB = (0,0), mode = 'd'):
	a = pointB[0] - pointA[0] # X Displacement
	b = pointB[1] - pointA[1] # Y Displacement
	if mode == 'd': # Distance
		return math.sqrt(a**2 + b**2)
	elif mode == 'v': # Vector
		return (a,b)

def angleBetween(pointA = (0,0), pointB = (0,0), mode = 'd'):
	vector = distBetween(pointA, pointB, 'v')
	radians = math.atan2(vector[1], vector[0])
	if mode == 'd': # Degrees
		return math.degrees(radians) 
	elif mode == 'r': # Radians
		return radians

class Character(pygame.sprite.Sprite):
    def __init__(self,xy):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("box.jpg")
        self.rect = self.image.get_rect()
        self.rect.centerx, self.rect.centery = xy
        self.velx = 0 
        self.vely = 0
        self.angle = 0

    def move_up(self,speed):
        self.vely -= speed
    def move_down(self,speed):
        self.vely += speed
    def move_right(self,speed):
        self.velx += speed
    def move_left(self,speed):
        self.velx -= speed

    def Rotate(self):
        angle = angleBetween((self.rect),pygame.mouse.get_pos(),'d')
        rotated = pygame.transform.rotate(self.image,angle * -1)
        return rotated

    def move(self,dx,dy):
        if self.rect.bottom + dy > 768:
            self.rect.bottom = 768
        elif self.rect.top + dy < 0:
            self.rect.top = 0
        elif self.rect.right + dx > 1024:
            self.rect.right = 1024
        elif self.rect.left + dx < 0:
            self.rect.left = 0
        else:
            self.rect.y += dy
            self.rect.x += dx

    def update(self):
        self.move(self.velx,self.vely)



pygame.init()
screen = pygame.display.set_mode((1024,768))
clock = pygame.time.Clock()
pygame.display.set_caption("In Utterblossomness")
pygame.display.flip()
Player = Character((200,200))
angle = 0
rotated = Player.image


while 1:
    clock.tick(30)
    screen.fill((0,0,0))
    mouse_x,mouse_y = pygame.mouse.get_pos()
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            exit()
        elif event.type == KEYDOWN:
            if event.key == K_ESCAPE:
                    pygame.quit()
                    exit()
            if event.key == K_w:
                Player.move_up(5)
            if event.key == K_s:
                Player.move_down(5)
            if event.key == K_d:
                Player.move_right(5)
            if event.key == K_a:
                Player.move_left(5)             
        elif event.type == KEYUP:
            if event.key == K_w:
                Player.move_down(5)
            if event.key == K_s:
                Player.move_up(5)
            if event.key == K_d:
                Player.move_left(5)
            if event.key == K_a:
                Player.move_right(5)
        
    rotated = Player.Rotate()
    x_pos = Player.rect.x - (Player.image.get_width()/2)
    y_pos = Player.rect.y - (Player.image.get_height()/2)

    Player.update()           
    screen.blit(rotated, (x_pos,y_pos))
    pygame.display.update()

Thanks for your help

Dani AI

Generated

— two separate problems are visible from your description: the rotation pivot drifting, and rotation seeming to “stop” when you change movement. Both come from how the rotated surface and the sprite rect are being handled, and from using the wrong reference point for the angle.

Keep one unmodified copy of the sprite (e.g. self.base_image), compute the angle from the mouse to the sprite’s center (use rect.center), rotate the base image every frame, then replace the sprite image and reset the rect using rotated.get_rect(center=old_center). The pivot jumps because a rotated surface changes size; if you blit by manually subtracting half the original width/height you’ll get offsets. Also avoid rotating an already-rotated surface — always rotate the original image. For the “can’t rotate after changing directions” symptom, handle movement with key state or boolean flags (or pygame.key.get_pressed()) rather than trying to increment/decrement velocity exclusively via KEYDOWN/KEYUP events; inconsistent velocity updates can make the visible sprite position diverge from the point used to compute the angle.

A minimal pattern to follow (place in your sprite class):

# keep original
self.base_image = pygame.image.load("box.png").convert_alpha()
self.image = self.base_image
self.rect = self.image.get_rect(center=xy)

# each frame (in update)
mx, my = pygame.mouse.get_pos()
cx, cy = self.rect.center
angle = math.degrees(math.atan2(my - cy, mx - cx))
self.image = pygame.transform.rotate(self.base_image, -angle)
self.rect = self.image.get_rect(center=(cx, cy))

Checklist: 1) use rect.center for angle math; 2) rotate the original image, not the current self.image; 3) get a new rect with get_rect(center=...) and blit using that rect; 4) prefer key state for movement input. See the pygame.transform.rotate docs for details and performance notes.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.