处理与静态斜矩形障碍物的精灵碰撞

3
所以我有一个障碍物,我希望我的精灵与之碰撞,并且它处于特定的角度。在这种情况下,我们从正x轴测量到矩形顶部,在这种情况下,相对于正x轴为333.02度或相对于负y轴为63.02度。所以我的问题是如何设置pygame精灵以正确地与角度矩形障碍物碰撞?据我所知,pygame精灵矩形没有旋转属性,我不能只说,“嘿,当我的精灵的右上角与顶部碰撞时”,因为缺乏旋转。我的碰撞在水平甚至垂直表面上运作良好,但我卡在如何与倾斜的障碍物碰撞上。

这是我现在的碰撞代码。它使用向量并独立检查x和y是否有任何东西。下面是我想要在Tile Map Editor中创建的对象的图片。就像我之前提到的那样,它以333.02度的角度放置。我还包括了坐标轴的草图,以防有关联。

    def update(self):
        self.animate()
        self.acc = vec(0, PLAYER_MASS * GRAVITY)
        self.move()

        # Equations of Motion
        self.acc.x += self.vel.x * PLAYER_FRICTION
        self.vel += self.acc

        # Collision check in all 4 directions
        self.pos.x += (
            self.vel.x + 0.5 * self.acc.x * self.game.dt
        )  # Update x component (Frame-independent motion)
        if abs(self.vel.x) < PLAYER_VELX_EPSILON:
            self.vel.x = 0

        self.rect.x = self.pos.x
        hits = pg.sprite.spritecollide(self, self.game.platforms, False)
        for hit in hits:  # Horizontal collision
            if self.vel.x > 0:  # Rightward motion
                self.rect.right = hit.rect.left
            elif self.vel.y < 0:  # Leftward motion
                self.rect.left = hit.rect.right
            self.pos.x = self.rect.x  # Update true postion

        self.pos.y += self.vel.y + 0.5 * self.acc.y * self.game.dt  # Update y component
        self.rect.y = self.pos.y + 5

        # This prevents double jumping
        if self.vel.y > 0:
            self.onGnd = False

        hits = pg.sprite.spritecollide(self, self.game.platforms, False)
        for hit in hits:  # Vertical Collision
            if self.vel.y > 0:  # Downward motion
                self.rect.bottom = hit.rect.top
                self.vel.y = 0
                self.onGnd = True
            elif self.vel.y < 0:  # Upward motion
                self.rect.top = hit.rect.bottom
                self.vel.y = 0
            self.pos.y = self.rect.y  # Update true postion

        # Limit Player's movement
        if self.rect.bottom > HEIGHT:
            self.vel.y = 0
            self.rect.bottom = HEIGHT
            self.pos.y = self.rect.y

This is the invisible object in the Tiled Map Editor that I want to collide with so I can go up this slope. The angle says 333.02 with respect to the positive x axis (to the right when facing the screen).

Rough Drawing of the axis and angles associated.

任何对这个问题的帮助将不胜感激!
2个回答

1
答案是坐标转换。想象一下,旋转的对象有自己的坐标系,其中x沿矩形底部运行,y沿左侧向上运行。然后,如果你能在该坐标系中找到你的精灵的位置,你可以像通常使用未旋转的矩形一样检查碰撞,即如果x >=0且x <=宽度且y >=0且y <=高度,则存在碰撞。
但是如何获得转换后的坐标?答案是矩阵。您可以使用2D变换矩阵来旋转、缩放和平移向量和坐标。不幸的是,我对这些类型的变换的经验是在C#中,而不是python,但是this page提供了示例和解释,使用numpy在python中实现。
请注意,这是2D(和3D)游戏工作的基础 - 矩阵变换随处可见,并且是旋转、缩放和平移对象进行碰撞检测的方法。它们也是精灵移动、旋转等的方式:pygame transform 模块是一个矩阵变换模块。因此,如果代码和解释一开始看起来很吓人,那么值得投入时间去理解它,因为在某个特定的点之后,没有使用它很难编写游戏。
我知道这不是你问题的完整答案,因为我没有给你代码,但它太长了,不能用评论回答,希望能指引你正确的方向。还有this answer提供了一些简单的代码。

编辑:为了添加更多信息,完整的碰撞检测例程将检查每个可碰撞像素的位置与对象的位置是否相交。这可能是您的游戏所需的方法,具体取决于您需要多精确的碰撞检测。这就是我在我的游戏Magnetar (https://www.youtube.com/watch?v=mbgr2XiIR7w)中所做的,它可以在任意位置、比例和旋转下碰撞多个不规则形状的精灵。

然而,我注意到在您的游戏中,如果您只需要与一些倾斜的斜坡进行碰撞检测,那么您可能可以“作弊”。也就是说,您可以有一个数据结构来记录地面的“角落”(它改变角度的点),然后使用简单的几何学来确定一个x、y点是在地面以下还是以上。也就是说,您将获取点的x值并检查它在哪个地面段上。如果它在斜坡地面上,计算出它在斜坡地面的x轴上的距离,然后使用该位置处角度的sin乘以此值来计算斜坡在该位置的y值,如果大于您正在检查的点的y值,则发生碰撞。


谢谢您的建议!我拿出一些草稿纸,为此情况计算出了旋转矩阵。对于这个障碍物参考系,我有[cos(theta),-sin(theta),0;sin(theta),cos(theta),0;0,0,1]。现在我的跟进问题是何时知道将我的坐标变换到本地坐标系?如果我在水平表面上,地板的本地坐标与精灵的全局坐标相同。但是,我的精灵如何“知道”即将出现斜坡,让我将我的坐标转换为它的本地坐标并进行比较。如果这是一个幼稚的问题,对不起,我不知道该怎么说。 - MBA20
您应该在屏幕上拥有一个对象列表,以便检查它们之间的碰撞。请注意,计算自己的转换矩阵可能是不必要的。我相信有Python库可以进行2D变换。您还需要考虑平移(偏移)和旋转。 - see sharper

0

seesharper的回答可能是正确的方法。我没有这方面的经验,但它看起来很有趣,我将不得不去阅读链接并学习一些关于这种方法的知识。然而,在看到他的答案之前,我仍然会提供我的即时反应。

您可以使用pygames mask和掩码碰撞检测例程。创建一个与倾斜矩形/平台形状相同的掩码,并使用该方法检测与其发生的碰撞。

如果在Sprite子类中添加self.mask属性,则精灵将自动在碰撞检测中使用该掩码。


是的,我曾考虑过只使用遮罩,但我担心性能问题,特别是屏幕上常见斜坡的情况下。我认为当精度至关重要时,例如敌人攻击精灵时,我会保留遮罩碰撞。 - MBA20

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