3

我已经开始研究 Rabbyt 库,到目前为止,我真的很喜欢将它与 pyglet 结合使用。

库中似乎没有实现的一件事是精灵之间的像素完美碰撞检测。我在实施时有两个问题。

首先,我正在使用 pyglet 加载精灵的纹理,但我不明白如何从纹理中获取位掩码(我非常有限的 OpenGL 知识是主要问题)。似乎 BufferImageMask 是从 AbstractImage 实例获得的,而不是从纹理本身获得的。这样做的正确方法是什么?

其次,实现实际的碰撞检测算法有哪些不同的方法?如果有任何方法/变化,我最感兴趣,因为到目前为止我读过的所有内容都是这样的:

碰撞检测算法@gamedev.net

我只是尽量不要错过任何重要信息,算法本身是可靠的。

提前致谢!

PS 我在 Python 2.7 中编码,但我宁愿在 C 中实现实际的像素完美碰撞检测算法并将其用作扩展。

更新

我已经设法使用非旋转精灵进行像素完美碰撞检测:

    r1 = collision[entity1].aabb
    r2 = collision[entity2].aabb
    sprite1 = renderable[entity1].sprite
    sprite2 = renderable[entity2].sprite
    ri = r1.intersect(r2)


    offx1, offy1 = int(ri.left - r1.left), int(ri.top - r1.top)
    offx2, offy2 = int(ri.left - r2.left), int(ri.top - r2.top)

    d1 = sprite1.texture.get_image_data().get_data('A', sprite1.texture.width)
    d2 = sprite2.texture.get_image_data().get_data('A', sprite2.texture.width)

    p1 = cast(d1, POINTER(c_ubyte))
    p2 = cast(d2, POINTER(c_ubyte))

    for i in range(0, int(ri.width)):
        for j in range(0, int(ri.height)):
            c1, c2 = 0, 0
            x1 = offx1+i
            y1 = (j+offy1)*sprite1.texture.width
            x2 = offx2+i
            y2 = (offy2+j)*sprite2.texture.width

            if x1 >= 0 and y1 >= 0:
                c1 = p1[x1 + y1]

            if x2 >= 0 and y2 >= 0:
                c2 = p2[x2 + y2]

            if c1>0 and c2 >0:
                pairs.add(pair)
                break

碰撞和可渲染只是与给定实体相关联的对象的字典。该算法是这个算法的修改版本:Pyglet 像素完美碰撞

虽然这非常好(而且速度很快,即使对于像这样被破解的代码也是如此)它对旋转的精灵没有用(我需要,除非为不同角度缓存大约 100 个不同版本的相同精灵是一个可行的选择),所以我是仍在寻找解决该问题的方法。

4

2 回答 2

1

虽然我无法回答关于 pyglet、纹理和图像的第一个问题(我在在线 API 的 Texture 中找到了一个名为“get_image_data”的方法;也许可以使用?),我可以回答第二个问题。

除了您在链接中提供的方法之外,我至少知道另外两种方法:第一种是使用 OpenGL,将图像绘制到缓冲区,并检查它们是否重叠。我不知道这有多快,但我可以想象它很慢。但是,它确实支持旋转和缩放。

第二个和你给出的有点相似;但是不是找到两个轴对齐的边界框的交点并且只检查交点内部,而是找到并检查两个凸包的交点。这样做的一个优点是凸包通常提供更好的拟合,另一个优点是凸包可以旋转,而轴对齐的边界框不能。主要缺点是凸包相交比轴对齐边界框相交复杂得多,因此难以实现。

我编写了一个使用第二种方法的库;你可以在PoxelColl找到它。它应该比其他像素完美的碰撞检测库更快,尤其是对于旋转和缩放。我不知道你是否可以从 Python 中使用它;如果您使用 Jython,则有一个 Scala 版本,还有一个您可以在 Python 中绑定的 C++ 版本,但这可能是相当多的额外工作。因此,如果您不需要缩放或旋转,最好简单地实现您已经找到的版本并测试它是否足够快。

于 2012-05-14T17:21:48.637 回答
1

回答更新

以下伪代码可能会解决问题:

...

middleX1 = sprite1.texture.width/2
middleY1 = sprite1.texture.height/2

middleX2 = sprite2.texture.width/2
middleY2 = sprite2.texture.height/2

angle1 = ?   #Radians.
vX11 = -cos(angle1)
vY11 = -sin(angle1)
vX12 = -cos(angle1 + math.pi/2)
vY12 = -sin(angle1 + math.pi/2)

angle2 = ?   #Radians.
vX21 = -cos(angle2)
vY21 = -sin(angle2)
vX22 = -cos(angle2 + math.pi/2)
vY22 = -sin(angle2 + math.pi/2)

for ...
    for ...

        ...

        aX1 = x1 - middleX1
        aY1 = j+offy1 - middleY1
        aX2 = x2 - middleX2
        aY2 = j+offy2 - middleY2

        tX1 = vX11*aX1 + vY11*aY1 + middleX1
        tY1 = vX12*aX1 + vY12*aX1 + middleY1

        tX2 = vX21*aX2 + vY21*aY2 + middleX2
        tY2 = vX22*aX2 + vY22*aX2 + middleY2

        #Use tX* and tY* for indexing. Remember to multiply tY* with width.

        ...

这应该有效,假设角度是顺时针和弧度,并且旋转应该发生在每个精灵的中间。基本上,它是一些手工编码的向量和矩阵数学。一个更整洁、更易于维护的解决方案将使用矩阵,但我不太了解 Python,所以我决定避免使用矩阵。

数学的工作原理是,对于每个图像中的每个点,找到它与中间的相对位置,通过将坐标与沿新旋转轴的单位向量相乘来旋转它,最后将中间加回以获得非相对协调。

于 2012-05-18T18:06:37.637 回答