我已经开始研究Rabbyt库了,到目前为止,我真的非常喜欢将它与pyglet结合使用。
在库中似乎没有实现的一件事是精灵之间的像素完美碰撞检测。我在实现它时遇到两个问题。
首先,我使用pyglet加载sprite的纹理,但我无法理解如何从纹理中获取位掩码(我非常有限的OpenGL知识是主要问题)。似乎BufferImageMask是从AbstractImage实例获得的,而不是从纹理本身获得的。这样做的正确方法是什么?
其次,实现实际碰撞检测算法的不同方法有哪些?我最感兴趣的是,如果有任何方式/变化,因为我到目前为止所阅读的所有内容都是这样的:
Collision Detection Algorithm @ gamedev.net
我只是不想错过任何关键信息,算法本身就很可靠。
提前致谢!
P.S。我在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
collision和renderable只是与给定实体关联的对象的dicts。该算法是此算法的修改版本:Pyglet pixel perfect collision
虽然这是非常好的(并且速度很快,即使对于像这样的黑客一起编写的代码),它对于旋转的精灵来说是无用的(我需要,除非在不同的角度缓存大约100个不同版本的相同精灵是可行的选择),所以我仍然在寻找解决这个问题的方法。
答案 0 :(得分:1)
虽然我无法回答关于pyglet,纹理和图像的第一个问题(我在在线API中的Texture中找到了一个名为“get_image_data”的方法;也许可以使用它?), 我可以回答第二个问题。
除了您在链接中提供的方法之外,我至少知道其他两种方法:第一种是使用OpenGL,将图像绘制到缓冲区,并检查它们是否重叠。我不知道这有多快,但我可以想象它很慢。但它确实支持旋转和缩放。
第二个与你给出的有些相似;但是找到并检查两个凸包的交点,而不是找到两个轴对齐的边界框的交点并且仅检查交叉点内部。这样做的一个优点是凸包通常提供更好的配合,另一个优点是凸包可以旋转,而轴对齐的边界框则不能。主要缺点是凸包交叉比轴对齐边界框交叉要复杂得多,因此很难实现。
我写了一个利用第二种方法的库;你可以在PoxelColl找到它。它应该比其他像素完美的碰撞检测库更快,特别是对于旋转和缩放。我不知道你是否可以从Python中使用它;如果您使用Jython,则有一个Scala版本,以及您可能能够在Python中进行绑定的C ++版本,但这可能是相当多的额外工作。因此,如果您不需要缩放或旋转,最好只需实现已经找到的版本,并测试它是否足够快。
答案 1 :(得分: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,所以我决定避免这种情况。
数学的工作原理是,对于每个图像中的每个点,找到它与中间的相对位置,通过将坐标与沿着旋转的新轴的单位向量相乘来旋转它,最后添加中间后面以获得非相对坐标。