Hey there,

So what I was recently having some trouble with was with Python’s PyGame Rotate function. I was having trouble understanding what some of from the comments found here meant, or were trying to illustrate, let alone the documentation given, so I resolved to figure it out , once and for all, so hopefully this post will be enough to get someone else on track. I think I was getting caught up on the different ways to deal with blitting and surfaces and rects.

When you start off, it can get confusing with all the new terms, so here is a simple example of what you can do to create a rotating 2D polygon:

So right away, there’s just the import initialization you need to do with PyGame that you need, but I have no idea what it does, only that you need to include it in every PyGame application.

import pygame #necessary pygame initializing pygame.init()

This next line is the initialization of the surface that you will be blitting to, and the displaying to the user. In order for something to be seen by the player, it must be blitted to screen first. (400,400) is the Width and Height of the display, and screen surface.

#create a surface that will be seen by the user screen = pygame.display.set_mode((400, 400))

This is just a variable that will be used and manipulated to determine the degrees that the image will be rotated

#create a variable for degrees pf rotation degree = 0

This is the beginning of the main loop. It could probably be changed to something nicer, like a variable or something than changes when the pygame.quit function gets called, but for this example it will do just fine.

while True:

This fills the screen surface with the color with the RGB value of (40,40,40), which is an off black, if my color sense is good enough. Remember the values have to be between 0 – 255.

There are good enough RBG > Hex translators available, but I like to use the ever present YellowPipe one. And, while we’re at it, a great color chooser tool is the Color Scheme Designer 3.

#clear screen at the start of every frame screen.fill((40, 40, 40))

Here a new surface is created, with the size of 100, 100. This surface will be used to draw the shapes onto, and then be rotated. The surface gets filled with (255,255,255) which is white, since it contains all the colors, so you can see what part of the surf-surface is filled or not.

#create new surface with white BG surf = pygame.Surface((100, 100)) surf.fill((255, 255, 255))

The color key is the color that is treated as transparent when the surface gets blitted. An analogue to the color key is the blue or green screen in movies. The color of the background is ignored.

#set a color key for blitting surf.set_colorkey((255, 0, 0))

Here two rect objects are created. All rects are is a collection of values which are used everywhere else in pygame. I think of them as specialized dictionaries.

Rects are created with a minimum of a pair values, called x and y, or left and top, which is the value in pixels of how far along the x or y plane they are, or how far from the left or top side that its top left pixel is. This means that the ‘bigger’ rect here is made at the 0,0 position.

The second pair of vales represents the size of the rect, or width and height. So in the ‘bigger’ rect, the top of the square travels 100px right from 0 on the x plane, and 50px down the y plane.

#create shapes so you can tell rotation is happenning bigger = pygame.Rect(0, 0, 100, 50) smaller = pygame.Rect(25, 50, 50, 50)

Now here is the drawing of the above rects. The draw.rect calls work with a destination surface (here ‘surf’), an RGB color (100,0,0), and either the x,y pair or a rect (I used the ‘bigger’ and ‘smaller’ rects).

Remember that it doesn’t show up on the user’s display just yet, you need to flip the display, which comes later.

#draw those two shapes to that surface pygame.draw.rect(surf, (100, 0, 0), bigger) pygame.draw.rect(surf, (100, 0, 0), smaller)

This is just a x,y pair of co-ordinates where the surf surface will be blitted, or copied, to. Blitting is just the word for copying, or drawing something onto another surface. So it is 200 pixels away from the left side, and 200 pixels away from the top side.

##ORIGINAL UNCHANGED #what coordinates will the static image be placed: where = 200, 200

Here is the blitting of surf to the screen surface, but blittedRect is created, which is simply the rect, which remember is essentially just a collection of coordinates, that represents the coordinates that was blitted onto on the screen surface. That mean that even though the two rects were drawn at 0y and 50y respectively, the new rect represent where those y values are translated on the screen surface, instead of the surf surface.

If it helps, you can add the y co-ordinate from the where tuple to the y co-ordinate from the two rects from earlier.

#draw surf to screen and catch the rect that blit returns blittedRect = screen.blit(surf, where)

Now the center of that newest rect, which was returned by the blit function is saved because you will eventually need to realign a surface that will be the result of rotating surf surface.

##ROTATED #get center of surf for later oldCenter = blittedRect.center

Here two things are happening. First PyGame’s rotate transformation function is being called. What this does is create a new surface that has the source surface (surf in our case) rotated by a given amount of degrees ( our variable is called degree, initally set to 0). This slightly distorts the resulting image due to the internal mechanics of the function.

Secondly, it returns that surface which you must assign to a variable, otherwise, there won’t be any visible rotation, since the rotation function does not alter the source image. This surface (rotatedSurf) is later blitted to the screen surface, and then made visible to the user.

#rotate surf by DEGREE amount degrees rotatedSurf = pygame.transform.rotate(surf, degree)

This is where we correct the center of rect object returned by the get_rect function. You need to call get_rect on the surface, because otherwise you would not have any way of getting the positional co-ordinates of it, or it’s width and height.

Once we assign that rect to a name (rotRect) we change its center attribute to the oldCenter we had set earlier.

This is also where it was the most confusing for me, so bear with me if this becomes unclear, feel free to ask for clarification, in the comments, on twitter (@TankorSmash) or on the reddit post that I will create and link.

#get the rect of the rotated surf and set it's center to the oldCenter rotRect = rotatedSurf.get_rect() rotRect.center = oldCenter

Now we blit to the screen surface the rotated surface (rotatedSurf) which came from the rotate function, at the x,y coordinates that the rotRect rect specifies. Remember that the rotRect uses the oldCenter variable as its center instead of the rotated surfaces center, because that center point is distorted.

#draw rotatedSurf with the corrected rect so it gets put in the proper spot screen.blit(rotatedSurf, rotRect)

Here is simple math: add five to the degree variable, if the degree variable has a value greater than 360 (a full circle, for you brainiacs out there) reset it to 0, so as to avoid unnecessary calculations. Why rotate all the way around, then an extra 5 degrees, when just rotating 5 degrees would have the same effect?

#change the degree of rotation degree += 5 if degree > 360: degree = 0

The display.flip function takes the screen surface we created just after the pygame initialization and makes it visible to the user. That’s all it does here, simple enough

#show the screen surface pygame.display.flip()

Finally, this is just a timer so the example doesn’t run so fast that you can’t tell what’s going on. The value represents milliseconds, so here it is a wait of 60ms until the loop is restarted.

#wait 60 ms until loop restart pygame.time.wait(60)

Here is the full example. I was running Python 2.6 on Vista with pyGame 1.9.1. There isn’t anything else imported so there isn’t any other dependancies.\

Again, don’t be afraid to ask for help or clarification, here, on my twitter, or on reddit’s many subreddits.

import pygame #necessary pygame initializing pygame.init() #create a surface that will be seen by the user screen = pygame.display.set_mode((400, 400)) #create a varible for degrees pf rotation degree = 0 while True: #clear screen at the start of every frame screen.fill((40, 40, 40)) #create new surface with white BG surf = pygame.Surface((100, 100)) surf.fill((255, 255, 255)) #set a color key for blitting surf.set_colorkey((255, 0, 0)) #create shapes so you can tell rotation is happenning bigger = pygame.Rect(0, 0, 100, 50) smaller = pygame.Rect(25, 50, 50, 50) #draw those two shapes to that surface pygame.draw.rect(surf, (100, 0, 0), bigger) pygame.draw.rect(surf, (100, 0, 0), smaller) ##ORIGINAL UNCHANGED #what coordinates will the static image be placed: where = 200, 200 #draw surf to screen and catch the rect that blit returns blittedRect = screen.blit(surf, where) ##ROTATED #get center of surf for later oldCenter = blittedRect.center #rotate surf by DEGREE amount degrees rotatedSurf = pygame.transform.rotate(surf, degree) #get the rect of the rotated surf and set it's center to the oldCenter rotRect = rotatedSurf.get_rect() rotRect.center = oldCenter #draw rotatedSurf with the corrected rect so it gets put in the proper spot screen.blit(rotatedSurf, rotRect) #change the degree of rotation degree += 5 if degree > 360: degree = 0 #show the screen surface pygame.display.flip() #wait 60 ms until loop restart pygame.time.wait(60)