This code was already posted in a thread started by Damo about pixel collision. It peaked my interested and I started the task myself and inadvertently hijacked his thread. But he didn't get a chance to posting any code before he disappeared again so all is good. I'm reposting it here in code snippets so hopefully others can find it more easily.
Currently, this works on any non-rotated sprites. I've posted the library code you need to include as well as a small demo. The general concept of my method is from blink0k's idea. I've written a short tutorial explaining the method and how it works. In short, a bit mask is created for each sprite (non-animated for now). It detects the overlapping area of the two sprites being checked and looks to see if any pixels in the bitmasks match up. If both pixels are a 1 in the mask at the overlapping position, then they've touched. The bitmask is just an array of simplified pixel data of the alpha channel; 0 is transparent, 1 is anything with an alpha value greater than 0. As we only need a single bit to represent each pixel in the mask, we store 32 pixels of information into a single integer. This cuts down big time on the memory usage and allows this method to be much more viable.
I'm currently working on rotation, so hopefully that will be an added feature in the near future.
Tutorial
http://purpletoken.com/pixelscollision.pdf
Demo:
#include 'PixelMagic.agc'
dude1 as pixelMagic_PixelSprite
dude2 as pixelMagic_PixelSprite
dude1 = pixelMagic_createPixelSprite(createSprite(loadImage("dude1.png")))
dude2 = pixelMagic_createPixelSprite(createSprite(loadImage("dude2.png")))
setSpritePosition(dude1.spriteId, 300, 200)
setClearColor(92,92,92)
do
setSpritePosition(dude2.spriteId, getRawMouseX(), getRawMouseY())
result = pixelMagic_spriteHit(dude1, dude2)
print(result)
Print( ScreenFPS() )
Sync()
loop
PixelMagic.agc
Type pixelMagic_Rectangle
x as integer
y as integer
width as integer
height as integer
EndType
Type pixelMagic_PixelSprite
spriteId as integer
mask as integer[]
EndType
function pixelMagic_spriteHit(a as pixelMagic_PixelSprite, b as pixelMagic_PixelSprite)
x1 = getSpriteX(a.spriteId)
y1 = getSpriteY(a.spriteId)
x2 = x1 + getSpriteWidth(a.spriteId)
y2 = y1 + getSpriteHeight(a.spriteId)
x3 = getSpriteX(b.spriteId)
y3 = getSpriteY(b.spriteId)
x4 = x3 + getSpriteWidth(b.spriteId)
y4 = y3 + getSpriteHeight(b.spriteId)
// check bounding box overlap
if x3 < x2 and x4 > x1 and y3 < y2 and y4 > y1
// Get intersecting rectangle
r as pixelMagic_Rectangle
r = pixelMagic_getIntersection(x1,y1,x2,y2, x3,y3,x4,y4)
x1 = r.x-x1
y1 = r.y-y1
x3 = r.x - x3
y3 = r.y - y3
aWidth = getSpriteWidth(a.spriteId)
bWidth = getSpriteWidth(b.spriteId)
// check for collision
for y = 0 to r.height-1
for x = 0 to r.width-1
aPos = (y1+y)*aWidth + x1+x
bPos = (y3+y)*bWidth + x3+x
if pixelMagic_getPixelMaskValue(a, aPos)=1 and pixelMagic_getPixelMaskValue(b, bPos)=1 then exitfunction 1
next x
next y
endif
endfunction 0
function pixelMagic_createPixelSprite(sprite as integer)
p as pixelMagic_PixelSprite
p.spriteId = sprite
img = getSpriteImageID(sprite)
maskSize = ceil((getImageWidth(img) * getImageHeight(img)) / 32)
p.mask.length = maskSize
m = createMemblockFromImage(img)
bit = 0
for i = 12 to getMemblockSize(m)-4 step 4
if getMemblockByte(m, i+3) > 0
pixelMagic_setPixelMaskValue(p, bit, 1)
endif
inc bit
next i
deleteMemblock(m)
endfunction p
function pixelMagic_setPixelMaskValue(p ref as pixelMagic_PixelSprite, bit, bool)
i = floor(bit / 32)
b = bit - i*32
p.mask[i] = p.mask[i] || (1 << b)
endfunction
function pixelMagic_getPixelMaskValue(p as pixelMagic_PixelSprite, bit)
i = floor(bit / 32)
b = bit - i*32
value = (p.mask[i] >> b) && 1
endfunction value
function pixelMagic_getIntersection(ax1 as integer, ay1 as integer, ax2 as integer, ay2 as integer, bx1 as integer, by1 as integer, bx2 as integer, by2 as integer)
left = pixelMagic_max(ax1, bx1)
top = pixelMagic_max(ay1, by1)
right = pixelMagic_min(ax2, bx2)
bottom = pixelMagic_min(ay2, by2)
r as pixelMagic_Rectangle
r.x = left
r.y = top
r.width = 0
r.height = 0
if right > left then r.width = right - left
if bottom > top then r.height = bottom - top
endfunction r
function pixelMagic_max(a as integer, b as integer)
if a > b then exitfunction a
endfunction b
function pixelMagic_min(a as integer, b as integer)
if a < b then exitfunction a
endfunction b
Whole package with example sprites:
Download
"I like offending people, because I think people who get offended should be offended." - Linus Torvalds