Pygame 2D : rotation around center not working properly

here is the code I use to rotate an image around its center:

class Square:
def __init__(self) :
self.x, self.y, self.angle = 50, 200, 0
self.image360 = pygame.transform.rotate(self.image, self.angle)
...

def blit(self):
self.image360 = pygame.transform.rotate(self.image, self.angle)
# I made a center() function to calculate the center of an image/rect
self.center360 = center(self.x, self.y, self.image360)
MyScreen.blit(self.image360, self.center360)

mysquare = Square()

while 1:
for e in events:
if e.type == KEYDOWN:
if e.key == K_r:
mysquare.angle += 45


When I run the code and attempt to rotate the square, I notice that the rotation isn't smooth and isn't really around its center though I'm blitting the image360 attribute of the square in its center coordinates.

Btw if I just flip the image by 90°, it will seem to be perfectly rotating around its center.

Here is how I created my center() function :

def center(x, y, rect) :
try:
return (x + rect.get_width() / 2, y + rect.get_height() / 2)
except AttributeError:
return (x + rect.width / 2, y + rect.height / 2)


UPDATE :

Here is an example of what happens when I try to rotate the image (square case) :

rectangular image case : (I modified the GIF as I realized I had made a wrong one before)

• Isn't pygame's blits performed with a top-left origin? Meaning that your blit in the center is actually placing the top-left corner in what you think of as center? Where are you expecting the self.x and self.y coordinates to be? Hard to judge from the images but it sort of seems like the objects are moving by about half of what their size changes by, which would make sense considering the weird center transformation.
– user35344
Commented Jul 26, 2021 at 11:04
• @Tyyppi_77, ahh yeah the blits are performed at the top left, maybe using a rect object as the coordinates will solve the issue. Commented Jul 26, 2021 at 12:40

Finally I solved the issue and it was related to wrong image positioning as @Tyyppi_77 has mentionned in the comments.

The blit method of pygame.Surface turns out to blit a surface in the topleft corner if coordinates are passed to the 2nd parameter.

However, if we pass a Rect object, we would be able to position the image as we want.

Here is what the documentation says :

The dest argument can either be a pair of coordinates representing the position of the upper left corner of the blit or a Rect, where the upper left corner of the rectangle will be used as the position for the blit.

And fortunately, pygame.Surface objects have a get_rect() method using which we can obtain a Rect object that can be centered at a given position.

So what I did to solve the issue is getting and updating the rotated image's rect object while positioning it to the center not to the top left corner like this :

class Square:
def __init__(self):
self.x, self.y, self.angle = 50, 200, 0

@property
def center360(self):
return center(self.x, self.y, self.image)

@property
def image360(self):
return pygame.transform.rotate(self.image, self.angle)

@property
def rect360(self):
return self.image360.get_rect(center=self.center360)

def blit(self):
MyScreen.blit(self.image360, self.rect360)