Posted: 18th Apr 2017 21:53
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:
+ Code Snippet
#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
+ Code Snippet
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