4

I've been looking for solutions on how to make my image rotate around a single point but from what I've found nothing has really worked.

What I know

  • I can rotate using pygame.transform.rotate(surface, angle)

  • I need to constantly reset the center so the image does not rotate on its rotated self.

  • Need to update image to eliminate distortion

At first the image looks like this Pygame screen

Then when I rotate it a couple times it looks like this Pygame screen 2

Here's my code

import pygame


class pyGameSetup:

def __init__(self, title, width, height):

    # initialize pygame library
    pygame.init()

    # set up specific display properties
    self.game_display = pygame.display.set_mode((width, height))
    pygame.display.set_caption(title)

    # update display
    pygame.display.update()

    # create new global variables for the class
    # game state
    self.running = True

    # colors, only main
    # TODO: implement more color RGB values, if updated, update corresponding method
    self.white = (255, 255, 255)
    self.black = (0, 0, 0)
    self.grey = (128, 128, 128)
    self.pink = (255, 102, 178)
    self.blue = (0, 0, 255)
    self.red = (255, 0, 0)
    self.green = (0, 255, 0)
    self.purple = (127, 0, 255)
    self.yellow = (255, 255, 0)
    self.teal = (0, 204, 204)
    self.orange = (255, 128, 0)

    # player coordinates and properties
    self.player_x = int(width / 2)
    self.player_y = int(height / 2)
    self.player_width = 100
    self.player_height = 50
    self.player_speed_x = 0
    self.player_speed_y = 0
    self.move_speed = 5

    # FPS controllers (note start speed should always be 60 / 5 so, 1 / 300
    self.clock = pygame.time.Clock()
    self.fps = 60

    # screen values
    self.width = width
    self.height = height

    # rotation for car
    self.angle = 200

    # car image
    self.car1 = pygame.image.load("Images\\Car1.png")
    self.update_size()
    self.car_rect = self.car1.get_rect()
    self.car_rect.center = (self.player_x, self.player_y)


def exit(self):
    pygame.quit()
    self.running = False
    quit()

def game_loop(self):
    while self.running:
        for event in pygame.event.get():
            self.event_handler(event)

        # update player position
        # self.player_x += self.player_speed_x
        self.angle = self.player_speed_x
        self.player_y += self.player_speed_y

        # check to make sure it's in bounds
        self.check_valid_move()

        # reprint canvas
        self.game_display.fill(self.white)

        # update angle
        self.update_angle()

        # print player
        self.game_display.blit(self.car1, (self.player_x, self.player_y, self.player_width,
                                           self.player_height))

        # update display
        pygame.display.update()

        # FPS
        self.clock.tick(self.fps)

def event_handler(self, e):
    if e.type == pygame.QUIT:
        self.exit()
    if e.type == pygame.KEYDOWN:
            if e.key == pygame.K_LEFT:
                self.player_speed_x = -self.move_speed
            if e.key == pygame.K_RIGHT:
                self.player_speed_x = self.move_speed
            if e.key == pygame.K_UP:
                self.player_speed_y = -self.move_speed
            if e.key == pygame.K_DOWN:
                self.player_speed_y = self.move_speed
    if e.type == pygame.KEYUP:
            if e.key == pygame.K_LEFT:
                self.player_speed_x = 0
            if e.key == pygame.K_RIGHT:
                self.player_speed_x = 0
            if e.key == pygame.K_UP:
                self.player_speed_y = 0
            if e.key == pygame.K_DOWN:
                self.player_speed_y = 0

def check_valid_move(self):
    if self.player_x <= 0:
        self.player_x = 0
    if self.player_x >= self.width - self.player_width:
        self.player_x = self.width - self.player_width
    if self.player_y <= 0:
        self.player_y = 0
    if self.player_y >= self.height - self.player_height:
        self.player_y = self.height - self.player_height

def update_size(self):
    self.car1 = pygame.transform.scale(self.car1, (self.player_width, self.player_height))
    self.car1 = pygame.transform.rotate(self.car1, -90)

def update_angle(self):
    old_center = self.car_rect.center
    self.car1 = pygame.transform.rotate(self.car1, self.angle)
    self.car_rect.center = old_center

x = pyGameSetup('Game', 800, 600)
x.game_loop()

The error is in update_angle where I honestly am completely lost and do not even know what it's doing. Thanks in advance.

JGerulskis
  • 800
  • 2
  • 10
  • 24
  • 1
    I get this problem all the time, but I don't know the problem. Perhaps it is something pertaining only to images with transparency. – Malik Brahimi Feb 12 '15 at 23:48

2 Answers2

4

Your problem is that you are rotating a rotated image. Thus, the image is looking skewed, which would be expected. Instead, have two variables, one for the original variable, one for the most recent rotation.

So instead of:

car1 = original_image_rect
car1 = pygame.transform.rotate(car1, 10)
car1 = pygame.transform.rotate(car1, 10)
...

You would do:

car1 = original_image_rect
car2 = pygame.transform.rotate(car1, 10)
car2 = pygame.transform.rotate(car1, 20)
...
A.J. Uppal
  • 19,117
  • 6
  • 45
  • 76
2

This result seems to be pretty normal for the image of low resolution rotated several times without antialiasing. What you should do is:

  • Use the source image exactly 2x bigger, if possible. Rotate it FIRST and then scale down exactly 2x - if possible, during blit, so you don't need to scale it as a separate step.
  • Don't rotate rotated image. I.e. don't rotate it 3 times by 5 degrees, but every time copy the original image and rotate it by 5, 10, 15 degrees. This way you will keed distortion to the minimum and also won't have to re-assign the center.
Andrei Nikolaenko
  • 1,022
  • 1
  • 7
  • 13
  • It worked! The only problem is the image is not rotating around the center – JGerulskis Feb 13 '15 at 00:35
  • you mean there is still a problem? can you print the actual values of `self.car_rect` and `self.car_rect.center`? – Andrei Nikolaenko Feb 13 '15 at 01:00
  • Well yes there is a problem but it wasn't directly related to what I asked. It was just kind of a side question. And I've actually elimanated the `self.car_rect.center` all i have is `car_rect = self.car1, car2 = pygame.transform.rotate(self.car1, self.angle), self.car1 = car_rect, return car2` Sorry for the format. Where do I add the whole center logic – JGerulskis Feb 13 '15 at 01:08
  • 1
    I'm not quite familiar with these Python objects and rules, but it seems that your self.car1 has an inherent rect object which in turn has center property. Since you don't change self.car1 you just need to set its center before rotation `car_rect = self.car1.get_rect() self.car_rect.center = (self.player_x, self.player_y) car2 = pygame.transform.rotate(self.car1, self.angle)` Also I'm not quite sure if center should be at (player_x, player_y), maybe this is more proper: `car_rect = self.car1.get_rect() car_rect.center = (car_rect.left + car_rect.w/2, car_rect.top + car_rect.h/2)` – Andrei Nikolaenko Feb 13 '15 at 07:25