在Python/Pygame中寻找给定角度的适当的X/Y坐标修正值

3

我试图使精灵直接向鼠标移动,利用它们之间的角度。这个角度是通过 atan2 函数找到的。虽然这个角度可以很好地将精灵旋转到鼠标的方向,但是根据给定角度的象限不同,精灵移动的方向会出现问题。有时它会在一个象限中冻结,或者直接朝着鼠标相反的方向移动。

我使用基本的 Trig 函数来找到角度,并计算精灵的 X 和 Y 变量的适当增量。还需要注意的是,我计算的角度,虽然不能用于移动,但对于旋转完全有效。奇怪的是,我传递了两个点之间的 X 差异,然后是 Y 差异,这与反正切函数应该处理的方式相反。因此,我甚至不确定这个角度是如何使旋转正确工作的。

我尝试将 Y 差异和 X 差异(按顺序)传递到 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)

类代码(与战斗员类相关)

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

期望输出:精灵应该直接朝着鼠标移动。

实际行为:精灵移动方向错误,其行为会根据计算出的角度所在象限而显示出不同的模式。

编辑: 我更改了程序,使精灵的X和Y变量存储在与rect对象不同的变量中。这可以防止小数截断。我还在旋转代码完成后重新计算了精灵和鼠标指针之间的角度。在重新计算中,将X和Y差值参数交换以匹配反正切函数,而不是反余切函数。这个重新计算的角度用于角运动,而第一个角度,以X差值为先,用于旋转。重要的是要注意,在使用重新计算的角度(Y差值为先)计算出changeX和changeY变量之后,我将它们乘以-1,否则精灵将远离鼠标指针。

1个回答

2
我不能百分之百确定,但我认为问题在于pygame.Rect将位置存储为整数,因为它应该以像素为单位存储坐标和尺寸,当然你不能绘制半个像素。
由于涉及任意角度和三角函数,你最终得到的是浮点数,当你执行以下操作时会被截断:
def set_x(self,value):
    self.rect.x = value

这里,如果value是1.4,那么self.rect.x就变成了1。因此,你失去了"准确性"。
这种精度损失会在主循环(每帧)的每次迭代中传播,导致意外的运动方向。
最好的解决方案是将所有值存储在单独的数据结构中,并仅在屏幕绘制时更新rect属性。
最初的回答:如果value为1.4,则self.rect.x变为1,因此您会失去“准确性”。这种精度误差会在主循环(每一帧)的每次迭代中传播,导致意外的运动方向。最佳解决方案是将所有值存储在单独的数据结构中,仅在屏幕绘制时更新rect属性。

看起来这是问题的一部分。我停止在矩形中存储我的坐标值,这提高了准确性。另一个问题是,虽然atan2函数计算的角度在旋转方面很好用,但当我将精灵向鼠标移动时会出现问题。这是因为我按照余切函数的参数顺序传递了X和Y参数。旋转代码完成后,我只需使用交换参数重新计算角度,就可以正常工作了。但是,我确实必须将changex和changey乘以-1。 - Woody Chelton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接