Python Version: 3.4
I've recently started using Pygame and I have then started to use the module pyganim to handle animation of sprites. http://inventwithpython.com/pyganim/
I have run into an issue when I try to rotate the animation. It has a strange effect, such as shown in this example https://i.stack.imgur.com/KOgGZ.gif, from this issue:
Weird shifting when using pygame.transform.rotate()
I have tried multiple fixes, such as finding the center of the image etc but as it is a pyganim object, I am blitting to my surface like: (where screen is my surface)
player.blit(screen, playerpos)
Changing the center of it seems to have no effect.
I have also tried swapping the image I'm using for a full black square, and I've still had no luck in debugging it.
I assume it is due to the fact I am blitting the pyganim object to my surface, and that I need to maybe blit it to another surface and rotate that? <- speculation!
The issue I believe lies here,
# Set player position and rotation
position = pygame.mouse.get_pos()
angle = math.atan2(position[1]-(playerpos[1]),position[0]-(playerpos[0]))
player.clearTransforms()
player.rotate((360-angle*57.29)-90)
playerpos1 = (playerpos[0]-(player.getRect().width/2), playerpos[1]-(player.getRect().height/2))
player.blit(screen, playerpos1)
As the actual rect of the Pyganim object doesn't change, no matter what rotation is put against it (I have some on screen logging that I verified this with). I think the standard methods for correction are void.
If anyone with some experience using Pyganim could shed some light it would be awesome!
Here is the code in full...
# Import modules
import pygame
from pygame.locals import *
import pyganim
import math
# Initialise
pygame.init()
width, height = 640, 480
screen=pygame.display.set_mode((width, height))
keys = [False, False, False, False]
playerpos=[100,100]
# Load images
player = pyganim.PygAnimation([('resources/images/tdt/p1.png', 0.3), ('resources/images/tdt/p2.png', 0.3), ('resources/images/tdt/p3.png', 0.3), ('resources/images/tdt/p2.png', 0.3)])
player.play()
grass = pygame.image.load("resources/images/tdt/bg.png")
grasswidth = grass.get_width()
grassheight = grass.get_height()
myfont = pygame.font.SysFont("monospace", 20)
# loop
while 1:
# clear the screen before re-drawing
screen.fill(0)
# draw the screen elements
for x in range(width//grasswidth+1):
for y in range(height//grassheight+1):
screen.blit(grass,(x*100,y*100))
# Set player position and rotation
position = pygame.mouse.get_pos()
angle = math.atan2(position[1]-(playerpos[1]),position[0]-(playerpos[0]))
player.clearTransforms()
player.rotate((360-angle*57.29)-90)
playerpos1 = (playerpos[0]-(player.getRect().width/2), playerpos[1]-(player.getRect().height/2))
player.blit(screen, playerpos1)
# render text
label = myfont.render("X pos: "+str(playerpos[0])+"| Y pos: "+str(playerpos[1]), 1, (255,255,0))
screen.blit(label, (20, 20))
# Update the screen
pygame.display.flip()
# loop through the events
for event in pygame.event.get():
#check if the event is the X button
if event.type==pygame.QUIT:
##if it is, quit the game
pygame.quit()
exit(0)
if event.type == pygame.KEYDOWN:
if event.key==K_w:
keys[0]=True
elif event.key==K_a:
keys[1]=True
elif event.key==K_s:
keys[2]=True
elif event.key==K_d:
keys[3]=True
if event.type == pygame.KEYUP:
if event.key==pygame.K_w:
keys[0]=False
elif event.key==pygame.K_a:
keys[1]=False
elif event.key==pygame.K_s:
keys[2]=False
elif event.key==pygame.K_d:
keys[3]=False
# Move player
if keys[0]: # W
playerpos[1]-=2
elif keys[2]: # S
playerpos[1]+=2
if keys[1]: # A
playerpos[0]-=2
elif keys[3]: # D
playerpos[0]+=2
OK
I have made some progress on this... The code I have written right now is basic and works for the shape in question, as it is easily divisible by 4! :D However, I will re-write it to be able to handle all eventualities, however, it may be that the boxes have to be square: here is the code now:
playerpos1 = rMoveAmount(playerpos,angle, 44)
player.blit(screen, playerpos1)
With rMoveAmount being:
def rMoveAmount(position, degrees, picsize):
#MOVE A BOX DEPENDING ON THE AMOUNT ROTATED
degTest = int(((360-degrees*57.29)-180)%90)
#Has to be split up into two sections, before the half 90 degree rotation
if degTest < 45:
t = int((((360-angle*57.29)-180)%45)//4)
nPos = (position[0] - t , position[1] - t )
#And after
if degTest > 44:
t = int((((360-angle*57.29)-180)%45)//4)
nPos = (position[0] + t - 11, position[1] + t - 11)
return nPos
So It takes 1/4 of the angle (which would be between 0 - 11) Then it uses that as the offset (as my pic is 44px and will always need to be shifted by 1/4)
As you can see, the pic size isn't currently used. And I think it was just luck that my picture size was 44 and fit so snugly into the middle of a half 90 degree rotation, and could also be divided by 11. However, I will work on being able to use this with more flexible sizes and update.
Edit 3:
Ok, this one should now work for all square images, it will also center the cursor correctly. I will just show the changes made, not the whole code again:
# 3 - Load images
player = pyganim.PygAnimation([('resources/images/tdt/p1.png', 0.3), ('resources/images/tdt/p2.png', 0.3), ('resources/images/tdt/p3.png', 0.3), ('resources/images/tdt/p2.png', 0.3)])
player.play()
playerSize = player.getRect().width
# 6.1 - Set player position and rotation
position = pygame.mouse.get_pos()
angle = math.atan2(position[1]-(playerpos[1]+(playerSize/2)),position[0]-(playerpos[0]+(playerSize/2)))
player.clearTransforms()
player.rotate((360-angle*57.29)-90)
playerpos1 = rMoveAmount(playerpos,angle, playerSize)
player.blit(screen, playerpos1)
And the method rMoveAmount changes:
def rMoveAmount(position, degrees, picsize):
#MOVE A BOX DEPENDING ON THE AMOUNT ROTATED
degTest = int(((360-degrees*57.29)-180)%90)
quartsize = picsize / 4
#Has to be split up into two sections, before the half 90 degree rotation
if degTest < 45:
#t = int((((360-angle*57.29)-180)%45)//4)
jump = (quartsize / 44)
nPos = (position[0] - (jump * degTest) , position[1] - (jump * degTest) )
#And after
if degTest > 44:
jump = (quartsize / 44)
nPos = (position[0] + (jump * degTest) - (picsize/2) , position[1] + (jump * degTest) - (picsize/2))
return nPos
Will now work with any square images.