如何在Pygame中使子弹正确地朝向光标

时间:2015-12-16 20:03:22

标签: python math pygame

嘿,我刚开始制作游戏和编程,我试图在Pygame做一个小游戏,包括一个家伙射击子弹和东西。但是,我无法让射击机制正确。我有这样的代码

class Projectile():
    def __init__(self, surface, color, start_pos, end_pos, move_speed):
        super().__init__()

        # Shooter and target positions
        self.start_pos = start_pos
        self.end_pos = end_pos

        # Trigonometry stuffs and like
        self.dx = self.end_pos[0] - self.start_pos[0]
        self.dy = self.end_pos[1] - self.start_pos[1]
        self.rads = atan2(-self.dy,self.dx)
        self.rads %= 2*pi
        self.degs = degrees(self.rads)

        # More stuff I dont understand but it works nearly well.
        self.quarter = self.get_quarter(self.degs)
        # Change the way rel_x and rel_y are calculated so stuff works fair enough
        if self.quarter == 1:
            self.rel_x = -self.end_pos[0] + self.start_pos[0]
            self.rel_y = -self.end_pos[1] + self.start_pos[1]
        elif self.quarter == 2:
            self.rel_x = self.end_pos[0] - self.start_pos[0]
            self.rel_y = -self.end_pos[1] + self.start_pos[1]
        elif self.quarter == 3:
            self.rel_x = -self.end_pos[0] + self.start_pos[0]
            self.rel_y = self.end_pos[1] - self.start_pos[1]
        elif self.quarter == 4:
            self.rel_x = self.end_pos[0] - self.start_pos[0]
            self.rel_y = self.end_pos[1] - self.start_pos[1]

        self.d = (self.rel_x**2 + self.rel_y**2)**0.5
        self.angle_x = ((self.rel_x * cos(self.rads)) / self.d) * move_speed
        self.angle_y = ((self.rel_y * -sin(self.rads)) / self.d) * move_speed

    def move(self):
        self.leftover_x += self.angle_x
        self.leftover_y += self.angle_y
        self.rect.x += int(self.leftover_x)
        self.rect.y += int(self.leftover_y)
        self.leftover_x = (self.leftover_x % 1)
        self.leftover_y = (self.leftover_y % 1)

Move是这样编写的,因为Pygame不允许你移动像素的1.337,所以我将东西移动1,然后保存.337,当保存的数字结尾超过1时,它们也会被添加

结果,我得到类似Image of the bug

的子弹

使用数字我标记了在init中的if语句中使用的屏幕四分之一。

你可以看到,有点不起作用。我希望子弹制作一个圆圈。我该怎么办。

我会承认,我不知道三角学。我还没在学校学习,一年就会有。因此,我希望有人尽可能简单地向我解释。并告诉我一个更好的方法来实现这一目标,而不是使用这个季度的东西。

2 个答案:

答案 0 :(得分:2)

恭喜!你已经为自己发现了sin()和cos()。

拉出一张纸并标记两个点:一个用于光标位置(=目标),另一个用于子弹的当前(起始?)位置。

现在在它们之间画一条线。该行的长度是你的代码的.d(对于距离,我认为)。

然后从其中一个点绘制一条水平线,足够远,使其正好在另一个点的上方或下方。这个长度是你的rel_x(在微积分中你称之为“dx”)。

然后绘制垂直线以完成一个三角形 - 该长度是你的rel_y(或“dy”)。

我不确定为什么你需要你称之为angle_x和angle_y的变量。一旦射击,角度总是相同的,就像一颗子弹(除非目标正在移动,你正在飞行追击过程,就像一个寻的导弹;做一个“纯粹的追求”你只需重新计算每回合的路线,所以它总是指向目标在那个时间的位置)。

接下来需要的是移动距离。那将是d的一部分。如果您的速度大于d,则覆盖所有d并到达;否则你只能覆盖d的一小部分。所以你需要这样的东西:

if(speed> d):fraction_of_d = 1    else:fraction_of_d = speed / d

现在您需要注意的是,如果您要前往目标的1 / n,您还将覆盖x和y距离的1 / n(更长时间地凝视纸张)如果你没有看到这一点)。

但是你已经有了x和y的总距离(rel_x和rel_y)。所以你只需将每个乘以fraction_of_d,然后告诉你沿着那个方向移动多远。然后按这些金额更新项目符号的位置。

你将在trig中学习sin()只是“对立”(三角形的垂直边)的长度除以斜边(d)的长度。 cos()只是“相邻”(水平面)的长度除以斜边的长度。所以你已经有效地计算了正弦和余弦。

希望更清楚。

-Steve

答案 1 :(得分:1)

好。我自己找到了解决方案。子弹仍然有点不完全与第2和第3季的光标不同,但它会形成一个圆圈。

事实证明,我有sin()和cos()函数的事实存在问题。我刚删除它们以使代码成为

self.angle_x = (self.rel_x / self.d) * move_speed
self.angle_y = (self.rel_y / self.d) * move_speed

现在可以使用了。我也可以删除这个季度检测的东西,它现在没有它。最终代码如下所示:

class Projectile():
    def __init__(self, surface, color, start_pos, end_pos, move_speed):
        super().__init__()

        # Shooter and target positions
        self.start_pos = start_pos
        self.end_pos = end_pos

        # Trigonometry stuffs and like
        # NOW REDUNDANT
        # self.dx = self.end_pos[0] - self.start_pos[0]
        # self.dy = self.end_pos[1] - self.start_pos[1]
        # self.rads = atan2(-self.dy,self.dx)
        # self.rads %= 2*pi
        # self.degs = degrees(self.rads)

        # More stuff I dont understand but it works nearly well.
        # self.quarter = self.get_quarter(self.degs)
        self.rel_x = self.end_pos[0] - self.start_pos[0]
        self.rel_y = self.end_pos[1] - self.start_pos[1]

        self.d = (self.rel_x**2 + self.rel_y**2)**0.5
        self.angle_x = (self.rel_x / self.d) * move_speed
        self.angle_y = (self.rel_y) / self.d) * move_speed

结果如下:
A nice circle that looks okay.

尽管如此,有人应该发布一个更好的答案,这个答案也解决了子弹不能完全转到鼠标点击位置的问题。