0
\$\begingroup\$

I am trying to make a game in which I place a spaceship (its an image I downloaded) in the center and then rotate it on its place. However, when I use pygame.transform.rotate(), it rotates the image and changes its location and keeps on increasing its size. I have tried pygame.transform.rotozoom but even when I used scale 1, it didn't show any difference. And also when it rotates and blits the image onto the screen the image severely loses its quality. Pleaseee helpp!! Picture 1- This is  how it looks like before anything is done to the image! It stays in the centre and does not scale Picture 2- The quality reduces and the picture moves away from the centre(I want it to rotate while it is on the centre.)

\$\endgroup\$
  • 1
    \$\begingroup\$ Could you update the question and add a screenshot or two (i.e. the original image, the effect when it's in the game and the effect when it's rotated), and the relevant part of the code? \$\endgroup\$ – Alexandre Vaillancourt Jul 29 '16 at 14:45
  • \$\begingroup\$ Done mate. Please help me now!! \$\endgroup\$ – Rishi Malhotra Jul 29 '16 at 19:42
3
\$\begingroup\$

Maintaining quality

When you're rotating the image using pygame.transform.rotate(), pygame creates a new Surface with your rotated image on. By doing this your image lose some information and therefore some quality. That's why it's always practical to rotate the original image and not a rotated copy. In code it'll look something like this:

class Player(pygame.sprite.Sprite):

    def __init__(self, pos=(0, 0)):
        super(Player, self).__init__()
        self.original_image = pygame.image.load("My_image.png").convert()
        self.image = self.original_image  # This will reference our rotated image.
        self.rect = self.image.get_rect().move(pos)
        self.angle = 0

    def update(self):
        self.image = pygame.transform.rotate(self.original_image, self.angle)
        self.angle += 1 % 360  # Value will reapeat after 359. This prevents angle to overflow.

Why the image changes size

Surfaces in pygame can't actually be rotated; they have a horizontal width and a vertical height. When you load your image pygame creates a Surface which has a horizontal width and a vertical height equal to your image. When you rotate your image 45 degrees pygame have to create a new Surface where your original image fits. The new Surface's horizontal width and vertical height has to be the images hypothenuse to be able to fit the image.

enter image description here enter image description here

As you see, the Surface is the biggest when the hypothenuse (the turquoise line) is vertical (or horizontal). This is supposed to be, otherwise your image wouldn't fit. If the problem you're having is about collision detection I'd recommend you to try other forms of collision detection like circular, or keep using rectangular but minimize it's size.


Keep the image on the same position

To prevent the image from moving I usually position the image by its center. So after each rotation I move its new center to its previous center.

def update(self):
    self.image = pygame.transform.rotate(self.original_image, self.angle)
    self.angle += 1 % 360  # Value will reapeat after 359. This prevents angle to overflow.
    x, y = self.rect.center  # Save its current center.
    self.rect = self.image.get_rect()  # Replace old rect with new rect.
    self.rect.center = (x, y)  # Put the new rect's center at old center.

Full code

import pygame

class Player(pygame.sprite.Sprite):

    def __init__(self, pos=(0, 0), size=(200, 200)):
        super(Player, self).__init__()
        self.original_image = pygame.Surface(size)
        pygame.draw.line(self.original_image, (255, 0, 255), (size[0] / 2, 0), (size[0] / 2, size[1]), 3)
        pygame.draw.line(self.original_image, (0, 255, 255), (size[1], 0), (0, size[1]), 3)
        self.image = self.original_image
        self.rect = self.image.get_rect()
        self.rect.center = pos
        self.angle = 0

    def update(self):
        self.image = pygame.transform.rotate(self.original_image, self.angle)
        self.angle += 1 % 360  # Value will reapeat after 359. This prevents angle to overflow.
        x, y = self.rect.center  # Save its current center.
        self.rect = self.image.get_rect()  # Replace old rect with new rect.
        self.rect.center = (x, y)  # Put the new rect's center at old center.


def main():
    player = Player(pos=(200, 200))
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                raise SystemExit

        player.update()
        screen.fill((255, 255, 255))
        screen.blit(player.image, player.rect)
        pygame.display.update()

if __name__ == '__main__':
    pygame.init()
    screen = pygame.display.set_mode((400, 400))
    main()
\$\endgroup\$
2
\$\begingroup\$

I don't know pygame, but here are some ways to fix some of your issues.


However, when I use pygame.transform.rotate(), it rotates the image and changes its location and keeps on increasing its size.

This is typically caused because you have other transformations that are applied, i.e. if you have a scale applied before you do the rotation.

Also, reading the documentation:

Unless rotating by 90 degree increments, the image will be padded larger to hold the new size. If the image has pixel alphas, the padded area will be transparent. Otherwise pygame will pick a color that matches the Surface colorkey or the topleft pixel value.


Ultimately, if you can't achieve what you want with the tools offered by the engine, you could create a spritesheet with the image rotated. This would be done in a program like photoshop, and you would change the sprite instead of rotating it in the game. This would give you a better control on the final quality.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.