简体   繁体   English

在Python / Pygame中找到具有给定角度的正确X / Y坐标修改器

[英]Finding proper X/Y coordinate modifiers with given angle in Python/Pygame

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. 该角度通过atan2函数找到。 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. 我正在使用基本的Trig函数来查找角度,并计算精灵的X和Y变量的正确添加。 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. 奇怪的是,我传递了两个点之间的X差异,然后是Y差异,这与应该如何处理反正切函数相反。 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. 我试图将Y差异和X差异( atan2顺序)传递给atan2函数。 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. 但是,即使我将参数的顺序更改为atan2函数以匹配示例程序,这些也不起作用。

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)

Class Code (Relevant to the fighter class) 类别代码(与战斗机类相关)

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 预期输出:Sprite直接朝向鼠标移动

Actual behavior: Sprite moves in wrong directions, with behavior showing patterns depending on quadrant of calculated angle. 实际行为:Sprite在错误的方向上移动,行为显示取决于计算角度的象限的模式。

Edit: I changed the program so that the X and Y variables of the sprite are stored in variables separate from the rect object. 编辑:我更改了程序,以便精灵的X和Y变量存储在与rect对象分开的变量中。 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. 在重新计算中,交换X和Y差分参数以匹配反正切函数而不是反余切函数。 This recalculated angle is used for angular movement, and the first angle, with the X difference passed first, is used for rotation. 该重新计算的角度用于角度移动,并且第一角度(首先通过X差异)用于旋转。 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. 重要的是要注意,在我使用重新计算的角度(首先传递Y差值)计算changeX和changeY变量后,我将它们乘以-1,否则精灵将远离鼠标指针。

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. 我不能100%肯定,但我认为问题是pygame.Rect将位置存储为整数,因为它应该以像素为单位存储坐标和尺寸,当然你不能绘制半像素。

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." 在这里,如果value 1.4,则self.rect.x变为1.因此您将失去“准确性”。

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. 最佳解决方案是将所有值存储在单独的数据结构中,并仅更新rect属性以在屏幕中绘制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM