Ericson Willians Ericson Willians - 1 month ago 20
Python Question

How to rotate an image without losing pixel data? (Pygame)

Here's my code (Python 3.5):

import sys
import pygame
pygame.init()

screen_width = 640
screen_height = 480
screen = pygame.display.set_mode((screen_width, screen_height))
running = True

class Actor:

def __init__(self, x, y, w, h):
self.x = x
self.y = y
self.w = w
self.h = h
self.surface = pygame.image.load("GFX/player.bmp")

def draw(self):
screen.blit(self.surface, (self.x, self.y))

class Player(Actor):

def __init__(self):
Actor.__init__(self, 0, 0, 32, 32)
self.directions = [False, False, False, False]
self.speed = 0.1

def update(self):
if self.directions[0]:
self.y -= self.speed
if self.directions[1]:
self.y += self.speed
if self.directions[2]:
self.x -= self.speed
if self.directions[3]:
self.x += self.speed

player = Player()

def rot_center(image, angle):
orig_rect = image.get_rect()
rot_image = pygame.transform.rotate(image, angle)
rot_rect = orig_rect.copy()
rot_rect.center = rot_image.get_rect().center
rot_image = rot_image.subsurface(rot_rect).copy()
return rot_image

def redraw():
screen.fill((75, 0, 0))
player.draw()
player.update()
pygame.display.flip()

while (running):
for e in pygame.event.get():
if e.type == pygame.QUIT:
sys.exit()
elif e.type == pygame.KEYDOWN:
if e.key == pygame.K_ESCAPE:
sys.exit()
if e.key == pygame.K_w:
player.directions[0] = True
if e.key == pygame.K_s:
player.directions[1] = True
if e.key == pygame.K_a:
player.directions[2] = True
if e.key == pygame.K_d:
player.directions[3] = True
elif e.type == pygame.KEYUP:
if e.key == pygame.K_w:
player.directions[0] = False
if e.key == pygame.K_s:
player.directions[1] = False
if e.key == pygame.K_a:
player.directions[2] = False
if e.key == pygame.K_d:
player.directions[3] = False
elif e.type == pygame.MOUSEMOTION:
player.surface = rot_center(player.surface, pygame.mouse.get_pos()[0] / 64)

redraw()


Pretty straightforward pygame code. I have a player with a simple image that I've created on mspaint, and I've used this function to rotate the image without causing out of memory issues. I'm rotating the image with the mouse (Considering a player that "aims" somewhere). Here's the original image:

enter image description here

And here's the extremely ugly result after moving the mouse a little:

enter image description here

I know I'd have better precision using OpenGL (Pyglet, for example), but in that case the rotation function from pygame would be completely useless. What am I missing? What am I doing wrong?

Answer

Keep in mind that Surfaces in Python are just grids of pixels, not mathematically perfect vector graphics. Rotating an image will cause slight destruction of quality. Continually doing so will eventually garble the image beyond recognition as you can see in your picture. Maintain a reference to the original image and never overwrite it. When you call rotate, make sure you are rotating the original picture with the cumulative angle with respect to the original, not a previously and incrementally rotated version.