[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
Re: [pygame] Rotation question
On 6/19/06, Kamilche <klachemin@xxxxxxxxxxx> wrote:
Andre Roberge wrote:
> Ok, here's a quick stab at it...
I couldn't get that to work. Maybe it's something else.
If you have a moment, this code rotates a box on the screen and shows
what point I'm interested in tracking. Can you see what I'm doing wrong?
[snip]
I'd rather be lazy.... Here's something I wrote a while ago when I was
thinking of writing a pygame tutorial that could be of interest (to
you and others). I strongly suspect it will take care of what you
want (and more). Let me know if I'm wrong, and I'll have another look
at your code.
André
===========
# test_new_image.py
# Author: Andre Roberge
# You are free to use this code as you see fit.
import sys
import pygame
from pygame.locals import *
from toolbox import new_image, rotate_about
import math
pygame.init()
screen = pygame.display.set_mode((500, 300))
pygame.display.set_caption("Testing rotating image")
red = 255, 0, 0
blue = 0, 0, 255
black = 0, 0, 0
white = 255, 255, 255
green = 0, 255, 0
yellow = 255, 255, 0
deg2rad = math.pi/180
angle = 0
surf_c = pygame.Surface((64, 64))
pygame.draw.circle(surf_c, red, (32, 32), 32, 1)
pygame.draw.arc(surf_c, blue, (0, 0, 64, 64), 0, 90*deg2rad, 31)
surf_ref = pygame.Surface((64, 64))
pygame.draw.rect(surf_ref, white, (0, 0, 64, 64), 1)
surf_ref.set_colorkey(black)
surf_tr = pygame.Surface((64, 64))
pygame.draw.rect(surf_tr, red, (0, 0, 64, 64), 1)
surf_tr.set_colorkey(black)
surf_tl = pygame.Surface((64, 64))
pygame.draw.rect(surf_tl, blue, (0, 0, 64, 64), 1)
surf_tl.set_colorkey(black)
surf_bl = pygame.Surface((64, 64))
pygame.draw.rect(surf_bl, green, (0, 0, 64, 64), 1)
surf_bl.set_colorkey(black)
surf_br = pygame.Surface((64, 64))
pygame.draw.rect(surf_br, yellow, (0, 0, 64, 64), 1)
surf_br.set_colorkey(black)
surf_arbitrary = pygame.Surface((64, 64))
f_p = (15, 15)
pygame.draw.rect(surf_arbitrary, white, (1, 1, 63, 32))
pygame.draw.circle(surf_arbitrary, red, (15, 15), 2)
surf_arbitrary.set_colorkey(black)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.fill(black)
s_c, position = rotate_about(surf_c, angle)
x = position[0]
y = position[1]
screen.blit(s_c, (x+100, y+100))
s_tr, position = rotate_about(surf_tr, angle, fixed_point="top_right")
x = position[0]
y = position[1]
screen.blit(s_tr, (x+100, y+100))
s_tl, position = rotate_about(surf_tl, angle, fixed_point="top_left")
x = position[0]
y = position[1]
screen.blit(s_tl, (x+100, y+100))
s_bl, position = rotate_about(surf_bl, angle, fixed_point="bottom_left")
x = position[0]
y = position[1]
screen.blit(s_bl, (x+100, y+100))
s_br, position = rotate_about(surf_br, angle, fixed_point="bottom_right")
x = position[0]
y = position[1]
screen.blit(s_br, (x+100, y+100))
s_arb, position = rotate_about(surf_arbitrary, angle, fixed_point=f_p)
x = position[0]
y = position[1]
screen.blit(s_arb, (x+300, y+100))
screen.blit(surf_ref, (100, 100))
pygame.display.flip()
angle += 1
======================
# toolbox.py
# Author: Andre Roberge
# You are free to use this code as you see fit.
import os
import pygame
from pygame.locals import *
import math
def new_image(filename, path=None, convert=True, key_pixel=None):
''' new_image() loads an image from a file, with the option of setting
a given colour as being transparent.
arguments:
filename: name of the file containing the source image
optional arguments:
path: relative path (from the program to the image location)
convert: set to None (or False) if you do not want the resulting
pygame Surface to have its pixel format converted.
key_pixel: tuple of the form (x, y) specifying the
pixel location of a transparent colour
returns:
a tuple: pygame Surface object, pygame rect object
'''
if path:
filename = os.path.join(path, filename)
image = pygame.image.load(filename)
if convert:
image.convert()
if key_pixel:
colorkey = image.get_at(key_pixel)
image.set_colorkey(colorkey, RLEACCEL)
return image, image.get_rect()
def rotate_about(surf, angle, fixed_point="center"):
''' rotate_about() rotates a surface counterclockwise, about a fixed point.
arguments:
surf: pygame Surface object
angle: rotation angle, expressed in degrees
optional arguments:
fixed_point: "center" (default value), "top_left", "top_right",
"bottom_left", "bottom_right"
returns:
a tuple: pygame Surface object, position tuple
The position tuple is to be used as an argument in a blit operation.
For example:
rotated, position = rotate_about(surf, angle)
screen.blit(rotated, position)
will rotate the Surface "surf" about its center.
'''
rotated_surf = pygame.transform.rotate(surf, angle)
# To maintain a fixed point, we need to make use of geometric and
# trigonometric transformations, which are too complicated to
# explain here in details
w, h = surf.get_size()
x = w/2
y = h/2
# trigonometric values with angle conversion
deg2rad = math.pi/180
rad_angle = angle*deg2rad
cos = math.cos(rad_angle)
sin = math.sin(rad_angle)
# rotation of coordinates
X1 = x*cos + y*sin
Y1 = -x*sin + y*cos
X2 = x*cos - y*sin
Y2 = x*sin + y*cos
X = max(abs(X1), abs(X2)) # 2*X, 2*Y == rotated_surf.get_size() !!
Y = max(abs(Y1), abs(Y2))
if fixed_point=="center":
blit_shift = (int(x-X), int(y-Y))
elif fixed_point =="top_left":
blit_shift = (int(X1-X), int(Y1-Y))
elif fixed_point =="top_right":
blit_shift = (int(-X2+2*x-X), int(Y2-Y))
elif fixed_point =="bottom_left":
blit_shift = (int(X2-X), int(-Y2+2*y-Y))
elif fixed_point =="bottom_right":
blit_shift = (int(-X1+2*x-X), int(-Y1+2*y-Y))
else:
try:
xx, yy = fixed_point
xx -= x
yy -= y
X1 = xx*cos + yy*sin
Y1 = -xx*sin + yy*cos
blit_shift = (int(xx-X1-X), int(yy-Y1-Y))
return rotated_surf, blit_shift
except:
return rotated_surf, (0, 0)
return rotated_surf, blit_shift