Having Troubles with my Per Pixel Collision Function :(

Started by
4 comments, last by BeerNutts 12 years, 3 months ago
Hello I'm working on a function that does per pixel collision and I have the idea of having 2 surfaces as parameters for this function.

Then basically create integer variables for each side of the 2 surfaces.

And then cleanly analyse them if the first surface of one of the 4 sides is by pixel in collision with the second surface by one of the second surface 4 sides then do something.

The problem is I don't know how to analyse each side aka *integer variables* for pixel collisions for the first and second surface any tips or solutions would be helpful.


Here is my Code Below


bool PerPixelCollision(SDL_Surface *image,SDL_Surface *Intersection_area)
{
int left_image, left_intersection_area;
int right_image, right_intersection_area;
int top_image, top_intersection_area;
int botttom_image, bottom_intersection_area;


}
Advertisement
Anyone with solutions or tips?
or ideasss?
well, you could AND two bit-wise masks together and if you get any true's that would be a collision detect. Perhaps there is a more efficient way to do that via the alpha channels, but i cant say for sure.
Here is a tutorial (in c#), but it should translate well: http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series2D/Coll_Detection_Overview.php
I did per-pixel collision in a game long ago (2000/2001) using C and DirectX. I'll post the code below, but, I don't feel like explaining everything.

The basic idea is, when I load an image, I scan it, recording if the color is transparent or not (I used 0 as transparent). I would then store every pixel in a bit-map array; if it's a color, it was 1, if it was transparent, I used 0. I stored this in a hash-table list, with the address of the image as the key

During collision check, I 1st check if the rectangle intersect, if they do, I then find the overlapping rectangles, and then check each bit if, and if any of them are both 1's (AND'ing), then they collide.

Good Luck!

Code when loading image. pucBuffer is a IDirectDrawSurface7, but I get the raw bitmap stored in puwPointer (16-bit colors). pulCopyPointer is the bit-mask'd bitmap array.


void SetObjectDefinition(UCHAR *pucBuffer)
{
UWORD *puwPointer;
IDirectDrawSurface7 *pdds1;
DDSURFACEDESC2 ddsd1;
ULONG *pulCopyPointer;
ULONG ulX, ulY;
tStringHash Hash;
ULONG ulCount = 0;

// cast
pdds1 = (IDirectDrawSurface7 *)pucBuffer;

// setup surface descriptions
ZeroMemory(&ddsd1, sizeof(ddsd1));
ddsd1.dwSize = sizeof(ddsd1);
ddsd1.dwFlags = DDSD_PITCH | DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_LPSURFACE;

// now get the surface
pdds1->Lock(NULL, &ddsd1, DDLOCK_WAIT | DDLOCK_READONLY, NULL);

puwPointer = (UWORD *)ddsd1.lpSurface;

/* allocate the memory, zero, and copy it into it */
pulCopyPointer = (ULONG *)malloc(((ddsd1.dwHeight * ddsd1.dwWidth)/8) + 4);
memset((void *)pulCopyPointer, 0, ((ddsd1.dwHeight * ddsd1.dwWidth)/8) + 4);

for (ulY = 0; ulY < ddsd1.dwHeight; ulY++)
{
for (ulX = 0; ulX < ddsd1.dwWidth; ulX++)
{
// If it's not zero, set bit
if(*(puwPointer + ulX + (ulY * ddsd1.lPitch/2)))
{
SET(*(pulCopyPointer + (ulCount/32)), (ulCount%32));
}
ulCount++;
}
}

// unlock
pdds1->Unlock(NULL);

/* now put in hash table, and then in a list */
Hash.cName = (CHAR *)pucBuffer;
Hash.ulNumber = (ULONG)pulCopyPointer;

// now make list
pPixelList = AddToList(pPixelList, CreateNode((void *)&Hash, sizeof(Hash)));

} /* endof SetObjectDefinition() */


Code for getting the bitmask'd bitmap (what I called an Object Definition)

ULONG *GetObjectDefinition(UCHAR *pucBuffer)
{
ULONG ulIndex;
tStringHash *pHash;

// loop list looking for this buffer
LOOP_LIST(ulIndex, pHash, tStringHash, pPixelList)
{
if (pHash->cName == (CHAR *)pucBuffer)
{
// found it
return ((ULONG *)pHash->ulNumber);
}
}

// Not suppose to be here!
LOG_ERROR("GetObjectDefinition: Bad buffer!\n"));
FLUSH;

return (NULL);

} /* endof GetObjectDefinition() */


And, here's the collision check code:

BOOL Intersect(tScreenObject *pScreenObj1, tScreenObject *pScreenObj2)
{
BOOL bReturn = FALSE;
tSizeAndLoc Obj1, Obj2, RectObj1, RectObj2;
LONG lTempX, lTempY;
ULONG *pulPointer1, *pulPointer2;
ULONG ulCount1, ulCount2;

// 07/29/01 (Friday, damnit, what am I doing? Well, not drinking obviously!)
// Update to decide square or circle bounding box

// 09/20/01 Updated to check the actual bitmaps (You knew you'd have to damnit!)

Obj1 = pScreenObj1->SizeAndLoc;
Obj2 = pScreenObj2->SizeAndLoc;

// Check rectangles 1st
// Whew!
if ((Obj1.lLocX + (LONG)Obj1.ulSizeX >= Obj2.lLocX) && (Obj1.lLocX <= Obj2.lLocX + (LONG)Obj2.ulSizeX))
if ((Obj1.lLocY + (LONG)Obj1.ulSizeY >= Obj2.lLocY) && (Obj1.lLocY <= Obj2.lLocY + (LONG)Obj2.ulSizeY))
{
// 1st, check if it's a bomb (ugly, I know!)
if ((((tBullet *)pScreenObj1)->ulType == BOMB) ||
(((tBullet *)pScreenObj2)->ulType == BOMB))
{
// just return!
return (TRUE);
}

// OK, rectangles intersect, so check bitmaps

// find rectangles we should check for each object
// check each side versus other side
if (Obj1.lLocX > Obj2.lLocX)
{
RectObj1.lLocX = 0;
RectObj2.lLocX = Obj1.lLocX - Obj2.lLocX;
}
else
{
RectObj2.lLocX = 0;
RectObj1.lLocX = Obj2.lLocX - Obj1.lLocX;
}
if (GET_RIGHT(Obj1) > GET_RIGHT(Obj2))
{
RectObj1.ulSizeX = GET_RIGHT(Obj2) - MAX(Obj1.lLocX, Obj2.lLocX);
RectObj2.ulSizeX = RectObj1.ulSizeX;
}
else
{
RectObj2.ulSizeX = GET_RIGHT(Obj1) - MAX(Obj1.lLocX, Obj2.lLocX);
RectObj1.ulSizeX = RectObj2.ulSizeX;
}
if (Obj1.lLocY > Obj2.lLocY)
{
RectObj1.lLocY = 0;
RectObj2.lLocY = Obj1.lLocY - Obj2.lLocY;
}
else
{
RectObj2.lLocY = 0;
RectObj1.lLocY = Obj2.lLocY - Obj1.lLocY;
}
if (GET_BOTTOM(Obj1) > GET_BOTTOM(Obj2))
{
RectObj1.ulSizeY = GET_BOTTOM(Obj2) - MAX(Obj1.lLocY, Obj2.lLocY);
RectObj2.ulSizeY = RectObj1.ulSizeY;
}
else
{
RectObj2.ulSizeY = GET_BOTTOM(Obj1) - MAX(Obj1.lLocY, Obj2.lLocY);
RectObj1.ulSizeY = RectObj2.ulSizeY;
}

pulPointer1 = GetObjectDefinition(pScreenObj1->pucBuffer);
pulPointer2 = GetObjectDefinition(pScreenObj2->pucBuffer);


// now loop through one of em, checking the color
for (lTempY = 0; lTempY < (LONG)RectObj1.ulSizeY; lTempY++)
{
// increase count to next line
ulCount1 = (Obj1.ulSizeX * (RectObj1.lLocY + lTempY)) + RectObj1.lLocX;
ulCount2 = (Obj2.ulSizeX * (RectObj2.lLocY + lTempY)) + RectObj2.lLocX;

for (lTempX = 0; lTempX < (LONG)RectObj1.ulSizeX; lTempX++)
{
// check for not 0
if (IS_SET(*(pulPointer1 + (ulCount1/32)), (ulCount1%32)) &&
IS_SET(*(pulPointer2 + (ulCount2/32)), (ulCount2%32)))
{
bReturn = TRUE;
break;
}
ulCount1++;
ulCount2++;
}

if (bReturn)
{
break;
}
}
}

return (bReturn);
}


My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

This topic is closed to new replies.

Advertisement