# Pygame surface rotation, rect rotation or sprite rotation?

i seem to have a conceptual misunderstanding of the surface and rect object in pygame.

I currently observe these objects this way:

Surface

rect

• the 'hard' representation of the ingame object (sprite). Used for simplifying object moment and collision detection

sprite

• rect and surface grouped together

What i want to do is rotate my sprite. The only available method i found for rotation is pygame.transform.rotate.

How do i rotate the rectangle, or even better, the whole sprite?

Below is the image of how i visualize this problem.

Conceptually you've got it, just think of the rectangle as a helper for you to deal with position and collision detection of your image. To implement it you could use:

  mySprite.image = pygame.transform.rotate(Surface, angle)


This will give you a rotated Surface (image), then you can use:

mySprite.rect = mySprite.image.get_rect()


To give you your new rectangle; this won't be a rotated rectangle, it will be a orthogonal one that is big enough to fit your image in, i.e. its sides will remain vertical and horizontal. This should serve most purposes, and be satisfactory for most collision detection, if it's not some people shrink the rectangle a bit, doing it pixel perfect is a lot more complexed and cpu hungry and often not worth it.

NB:keep a copy of your original image (with no rotation) and do all your rotations from that one, otherwise there is potential for your rectangle to keep getting bigger and bigger.

• Excellent advice for always rotating the original image. I was getting some awful results without it. +1 as soon as i get the reputation to vote up. – TheMeaningfulEngineer Nov 29 '12 at 15:20

Just noticed something which made me almost insane during this whole day of experimenting.

The rect of the image is not the rectangle of the sprite!

In case of this code:

class mySprite(pygame.sprite.Sprite):

def __init__(self, xy):
# initialize the pygame sprite part
pygame.sprite.Sprite.__init__(self)
# set image and rect
self.rect = self.image.get_rect()


the self.rect is a rect for its on, not a reference of to the surface rect. That means that we have s situation like this.

This brings up another important thing i noticed.

The image.get_rect() location is relative to the Sprite rect!

The image explains it better. Gray are the locations of the sprite rect, red is the position of image.get_rect()

Please correct me if I'm wrong, this is just an empirical proof based on a single experience.

• The get_rect() of the image (surface) only returns its dimensions, it's always located at (0,0), it's not located anywere. You should use sprite class to keep track of the image position. – pmoleri Nov 29 '12 at 19:32
• so have a self.position attribute and reset it when you rotate the image: self.rect.center = self.position – ali_goes_oosh Nov 29 '12 at 20:17

I realize this is an old post, but I wanted to chime in with some things that I've found helpful.

Any time you have a sprite image that you're drawing to a rect, you can set the properties of the sprite's rect during the Surface.get_rect() call.

For example, if we have a game object with attributes for its rect and its image, and we can reasonably assume that the image can be consistently centered around the object's rect.center without making it display weirdly, the following is something I've found to be helpful.

for object in things_to_draw:
drawn_image = altered_image(object.image) # altered_image() is whatever changes you're making to the image before it's drawn
image_location = drawn_image.get_rect(center=object.rect.center) #returns the Surface's rect with rect.center set to the center of the object
myDisplay.blit(drawn_image, image_location)


Additionally, you may want to take a look at using the bounding_rect of the image after doing a lot of work with said image. The bounding_rect is the resized rect that a rotated image fits into; if your image is significantly taller than it is wide (or vice versa) this might be more useful for collision detection than a static rect that is set once. One can get this by using Surface.get_bounding_rect(); however, for whatever reason this method cannot be passed the same setters as the previous one, so you'll have to set new values after this rect is created.

image_rect = object.image.get_bounding_rect() #does not take the same args! can't set rect.center until the next line...
image_rect.center = (some_x, some_y) #sets the bounding_rect's center to whatever X/Y you're using


Like I said, I know it's an older post, but this stuff was driving me up a wall at first as well.