I am trying to make a sprite move directly towards the mouse, utilizing the angle between them. This angle is found via the atan2
function. While this angle works fine for rotating the sprite towards the mouse, the sprite moves in the wrong directions depending on the quadrant of the given angle. It will sometimes freeze up in one quadrant, or move directly opposite the mouse.
I am using basic Trig
functions to find the angle, and calculate proper additions to the X and Y variables of the sprite. It is also important to note that the angle I calculate, while it doesn't work for movement, does work perfectly for rotation. What's odd is that I pass the X-difference between the two spots, and THEN the Y-difference, which is the opposite of how the inverse tangent function is supposed to be handled. Therefore, I'm not even sure how this angle has been making rotation work correctly.
I've attempted to pass the Y-difference and the X-difference (in that order) into the atan2
function. However, this causes the rotation on my sprite to be wrong, pointing me towards the idea that the angle as a whole is also incorrect. I've also tried following along with numerous other programs, all of which use the same formulas as me. However, these don't work, even when I change the order of the arguments to the atan2
function to match the example programs.
def main():
ExitLoop = False
image = IMAGELOADER.AllImages["Fighter1"]
image2 = IMAGELOADER.AllImages["Fighter2"]
Fighter1 = FighterClass.Fighter(image,(700,700))
Fighter2 = FighterClass.Fighter(image2,(300,300))
while not ExitLoop:
ScreenController.Refresh()
mouse_pos = pygame.mouse.get_pos()
Fighter2.set_x(mouse_pos[0]-32)
Fighter2.set_y(mouse_pos[1]-32)
angle = math.atan2(Fighter1.get_x()-mouse_pos[0]+32, Fighter1.get_y()-mouse_pos[1]+32)
degrees_angle = math.degrees(angle)
Fighter1.rotate(degrees_angle)
xval = Fighter1.get_x()
yval = Fighter1.get_y()
speed = Fighter1.get_speed()
changex = (speed*math.cos(angle))
changey = (speed*math.sin(angle))
Fighter1.set_x(xval+changex)
Fighter1.set_y(yval+changey)
for event in pygame.event.get():
if event.type == pygame.QUIT:
ExitLoop = True
ScreenController.Draw(Fighter1.get_image(),Fighter1.get_rect(),False)
ScreenController.Draw(Fighter2.get_image(),Fighter2.get_rect(),False)
ScreenController.DisplayUpdate()
clock.tick(60)
import pygame
import WoodysFunctions
class Fighter(pygame.sprite.Sprite):
def __init__(self,image,XnY):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.__image_source = image
self.rect = self.image.get_rect()
self.__mask = pygame.mask.from_surface(self.image)
self.rect.x = XnY[0]
self.rect.y = XnY[1]
self.__speed = 1
def get_image(self):
return self.image
def get_rect(self):
return self.rect
def get_mask(self):
return self.__mask
def get_x(self):
return self.rect.x
def get_y(self):
return self.rect.y
def get_speed(self):
return self.__speed
def set_image(self,value):
self.image = value
def set_rect(self,value):
self.__rect = value
def set_mask(self,value):
self.__mask = value
def set_x(self,value):
self.rect.x = value
def set_y(self,value):
self.rect.y = value
def set_speed(self,value):
self.__speed = value
def rotate(self,angle):
old_center = self.rect.center
self.image = pygame.transform.rotate(self.__image_source,angle)
self.rect = self.image.get_rect()
self.rect.center = old_center
Expected output: Sprite moves straight towards the mouse
Actual behavior: Sprite moves in wrong directions, with behavior showing patterns depending on quadrant of calculated angle.
Edit: I changed the program so that the X and Y variables of the sprite are stored in variables separate from the rect object. This prevents decimal truncation. I also recalculated the angle between the sprite and the mouse pointer after the rotation code is finished. In the recalculation, the X and Y difference parameters are swapped to match the inverse tangent function instead of the inverse cotangent function. This recalculated angle is used for angular movement, and the first angle, with the X difference passed first, is used for rotation. It is important to note that after I calculated the changeX and changeY variables using the recalculated angle (with the Y difference passed first), I multiplied them by -1, as otherwise the sprite will move away from the mouse pointer.
I cannot be 100% sure, but I think the problem is that pygame.Rect
stores position as integers, because it's supposed to store coordinates and dimensions in pixel unit, and of course you cannot paint half pixel.
Since you are dealing with any angle and trigonometric functions, you end with floats which are truncated when you do:
def set_x(self,value):
self.rect.x = value
Here, if value
is 1.4, self.rect.x
becomes 1. So you lose "accuracy."
This loss of accuracy is propagated each iteration of the main loop (each frame), resulting in an unexpected motion direction.
The best solution is to store all your value in a separate data structure and update the rect
attribute only for drawing in the screen.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.