I have started looking into the Rabbyt library and so far I am really enjoying using it in combination with pyglet.
One thing that does not seem to be implemented in the library is pixel perfect collision detection between sprites. I have two problems in implementing that.
First of all, I am using pyglet to load the textures for the sprites, but I can't understand how to obtain bit masks from the textures (my very limited OpenGL knowledge being the main problem). It seems that the BufferImageMask is obtained from the AbstractImage instance, but not from the texture itself. What is the right way to do that?
Secondly, what are the different ways to implement the actual collision detection algorithm? I am mostly interested if there are any ways/variations, as everything that I have read so far is like this:
Collision Detection Algorithm @ gamedev.net
I am just trying not to miss any crucial information out, the algorithm itself is solid.
Thanks in advance!
P.S. I am coding in Python 2.7 but I would rather implement the actual pixel perfect collision detection algorithm in C and use it as an extension.
I have managed to get pixel perfect collision detection working with non-rotated sprites:
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 and renderable are simply dicts of objects that are associated with the given entity. The algorithm is a modified version of this one : Pyglet pixel perfect collision
While that is pretty good (and fast, even for hacked together code like that) it is useless for rotated sprites(which I need, unless caching about 100 different versions of the same sprite for different angles is a viable option), so I am still looking for a solution to that problem.
Answer to the update
The following pseudo-code might do the trick:
...
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.
...
This SHOULD work, assuming angles are clock-wise and in radians, and that rotations should happen around the middle of each sprite. Basically, it is a bit of vector and matrix math hand-coded. A neater and more maintainable solution would use matrices, but I don't know a lot of Python, so I decided to avoid that.
The math works by, for each point in each image, finding its relative position to the middle, rotating it by multiplying the coordinates with unit-vectors along the new axes of the rotation, and finally adding the middle back to get the non-relative coordinate.