How To Rotate An Image Around Its Center

Image Rotation

In a previous tutorial I talked about scaling and rotating images using the transform() method.

In this guide I’ll look at a practical application of the rotate method in a game as well as some of the pitfalls.

I’ll build a small demo that includes a turret image (below), which is rotated to point towards the mouse.

The starter code is below:

				
					import pygame

pygame.init()

#define screen size
SCREEN_WIDTH = 1000
SCREEN_HEIGHT = 600

#create game window
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Rotating Objects")

#define colours
BG = (255, 255, 255)
BLACK = (0, 0, 0)

turret_original = pygame.image.load("turret.png").convert_alpha()
x = 400
y = 25500

#game loop
run = True
while run:
  
  #update background
  screen.fill(BG)

  #rotate turret
  turret = pygame.transform.rotate(turret_original, 0)

  #draw image
  screen.blit(turret, (x, y))

  #event handler
  for event in pygame.event.get():
    #quit program
    if event.type == pygame.QUIT:
      run = False

  #update display
  pygame.display.flip()

pygame.quit()
				
			

In the code above we’ll begin by loading the image in on line 17, making sure to keep the original image in a separate variable to the rotated one.

Lines 18 and 19 define the x and y coordinates for blitting the image on the screen.

On line 29 we create a rotated version of the original turret image and on line 32 we blit the new image on the screen at the predefined x and y coordinates.

The result is a static turret positioned roughly in the middle of the screen.

Calculating The Angle

In order to calculate the required rotation angle, we need to apply a little bit of trigonometry.

The coordinates of the turret image are known and the mouse cursor coordinates can be obtained.

We can calculate the horizontal and vertical distances between the two points and using those distances, calculate the rotation angle.

First we will get the mouse coordinates. This needs to go in the main loop as we will need to readjust every time the mouse moves.

				
					  #get mouse position
  pos = pygame.mouse.get_pos()
				
			

Next we calculate the x and y distances and use those to work out the angle of rotation. This requires the math module so make sure to import that.

				
					  #calculate turret angle
  x_dist = pos[0] - x
  y_dist = -(pos[1] - y)#-ve because pygame y coordinates increase down the screen
  angle = math.degrees(math.atan2(y_dist, x_dist))
				
			

Finally, we update the rotate method from before, to use the angle variable.

The turret image is facing up by default, but using our calculations above, when the mouse is directly above the turret, the calculated angle would be 90 degrees. So we need to account for this difference by subtracting 90 from the calculated angle.

This will vary depending on the orientation of the image you use.

				
					  #rotate turret
  turret = pygame.transform.rotate(turret_original, angle - 90)
				
			

The result however does not seem quite right. The calculations are correct, and the image does rotate but it seems to move around rather than staying still.

To visualise what is happening here, we need to show the image’s background, which is currently transparent.

To do this, we temporarily change convert_alpha() to convert().

				
					turret_original = pygame.image.load("turret.png").convert()
				
			

Now you can see what is going on a bit more clearly. As the image rotates, it gets bigger and this is what gives the impression of the turret moving around.

In reality, the turret is staying in the center of the image, but as the image gets bigger, it looks like the turret moves.

Notice that the top left corner of the image doesn’t change. That is the coordinate that we are passing into the blit method.

To resolve this, we need to change the way the image is drawn on the screen. Rather than drawing it from the top left corner, we want to draw it from the center.

				
					  #rotate turret
  turret = pygame.transform.rotate(turret_original, angle - 90)
  turret_rect = turret.get_rect(center = (x, y))

  #draw image
  screen.blit(turret, turret_rect)
				
			

In the above code, line 3 creates a rectangle from the rotated image and positions it with the center at the x and y coordinates.

Line 6 is modified to blit the image at the position of the rectangle.

				
					x = 500
y = 300
				
			

We can also update the original x and y coordinates to move the image closer to the middle of the window.

Now the turret is staying in the middle as it rotates around the screen. You can still see the black background getting bigger and smaller, but since the image is being drawn from the middle rather than the corner, it doesn’t affect the turret positioning.

We can now hide the black background by changing the convert() method back to convert_alpha().

And now you have a turret correctly following the mouse cursor.

The final code is:

				
					import pygame
import math

pygame.init()

#define screen size
SCREEN_WIDTH = 1000
SCREEN_HEIGHT = 600

#create game window
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Rotating Objects")

#define colours
BG = (255, 255, 255)
BLACK = (0, 0, 0)

turret_original = pygame.image.load("turret.png").convert_alpha()
x = 500
y = 300

#game loop
run = True
while run:
  
  #update background
  screen.fill(BG)

  #get mouse position
  pos = pygame.mouse.get_pos()

  #calculate turret angle
  x_dist = pos[0] - x
  y_dist = -(pos[1] - y)#-ve because pygame y coordinates increase down the screen
  angle = math.degrees(math.atan2(y_dist, x_dist))

  #rotate turret
  turret = pygame.transform.rotate(turret_original, angle - 90)
  turret_rect = turret.get_rect(center = (x, y))

  #draw image
  screen.blit(turret, turret_rect)

  #event handler
  for event in pygame.event.get():
    #quit program
    if event.type == pygame.QUIT:
      run = False

  #update display
  pygame.display.flip()

pygame.quit()
				
			

Related Posts

3 thoughts on “How To Rotate An Image Around Its Center

  1. great but how to make it work with sprites? since sprite has its own draw(). I cant figure out how to make it blit the image at the center.

Leave a Reply

Your email address will not be published. Required fields are marked *