Pixel Perfect Collision problems
Hi all! I'm working on a 2D-engine using SDL.
It's going pretty well, except i don't get my pixel-perfect collision detection
to work properly.
I know that pixel-perfect collision are expensive, and I won't use it for every collision. I still want it to work though.
First I do a simple boundingbox-collision test. If there is a collision, I jump to checkPixelPerfectCollision().
I have the theory straight I think, but the problem seems to be (at least I think) that when I try to get the color value of a certain pixel, it gives me a completely false RGB-value. I guess my algorithm for getting the pixel is wrong.
Here's the code anyway...
please help me :'<
bool CEntity::checkPixelPerfectCollision(CEntity* obj)
{
SDL_Rect A;
A.x = m_X;
A.y = m_Y;
A.w = m_Width;
A.h = m_Height;
SDL_Rect B;
B.x = obj->getX();
B.y = obj->getY();
B.w = obj->getWidth();
B.h = obj->getHeight();
SDL_Rect AB;
if(A.x > B.x) {
AB.x = A.x;
AB.w = (B.x + B.w) - A.x;
} else {
AB.x = B.x;
AB.w = (A.x + A.w) - B.x;
}
if(A.y > B.y) {
AB.y = A.y;
AB.h = (B.y + B.h) - A.y;
} else {
AB.y = B.y;
AB.h = (A.y + A.h) - B.y;
}
int numberOfPixels = AB.w * AB.h;
SDL_Surface* tmpA;
SDL_Surface* tmpB;
tmpA = SDL_CreateRGBSurface(SDL_HWSURFACE, AB.w, AB.h, 32, 0, 0, 0, 0);
tmpB = SDL_CreateRGBSurface(SDL_HWSURFACE, AB.w, AB.h, 32, 0, 0, 0, 0);
SDL_SetColorKey(tmpA, SDL_SRCCOLORKEY, SDL_MapRGB(tmpA->format, 255, 0, 255));
SDL_SetColorKey(tmpB, SDL_SRCCOLORKEY, SDL_MapRGB(tmpB->format, 255, 0, 255));
SDL_BlitSurface(m_Sprite->getBitmap(), &AB, tmpA, NULL);
SDL_BlitSurface(obj->getSprite()->getBitmap(), &AB, tmpB, NULL);
Uint32* transparent = (Uint32*)SDL_MapRGB(tmpA->format, 255, 0, 255);
Uint8 r = 0;
Uint8 g = 0;
Uint8 b = 0;
Uint8 r1 = 0;
Uint8 g1 = 0;
Uint8 b1 = 0;
for(int y = 1; y < numberOfPixels; y++) {
for(int x = 1; x < numberOfPixels; x++) {
//Uint32* pixelA = (Uint32*)(tmpA->pixels + y * tmpA->pitch + x * 2);
Uint32* pixelB = (Uint32*)(tmpB->pixels + y * tmpB->pitch + x * 2);
Uint32* pixelA = (Uint32*)(tmpA->pixels + y * tmpA->pitch + x * 2);
SDL_GetRGB(*pixelA, SDL_GetVideoInfo()->vfmt, &r, &g, &b);
SDL_GetRGB(*pixelB, SDL_GetVideoInfo()->vfmt, &r1, &g1, &b1);
Uint32 *pxA = (Uint32*)SDL_MapRGB(tmpA->format, r, g, b);
Uint32 *pxB = (Uint32*)SDL_MapRGB(tmpB->format, r1, g1, b1);
if(pxA != transparent && pxB != transparent) {
return true;
} else {
return false;
}
}
}
}
Well, for starters, your pixel collision detection code does not take into account the relative position between the two sprites.
Well, take a look at those lines:
SDL_BlitSurface(m_Sprite->getBitmap(), &AB, tmpA, NULL);
SDL_BlitSurface(obj->getSprite()->getBitmap(), &AB, tmpB, NULL);
You draw both sprites at the same position on tmpA and tmpB. You do your calculations as if both sprites' x and y positions are the same - and usually they aren't.
You should do something like this:
SDL_Rect relativeA;
relativeA.x=A.x-AB.x;
relativeA.y=A.y-AB.y;
SDL_Rect relativeB;
relativeB.x=B.x-AB.x;
relativeB.y=B.y-AB.y;
SDL_BlitSurface(m_Sprite->getBitmap(), &relativeA, tmpA, NULL);
SDL_BlitSurface(obj->getSprite()->getBitmap(), &relativeB, tmpB, NULL);
You can use the rects A and B instead of making new ones, but I gave them new names to make it easier to understand.
SDL_BlitSurface(m_Sprite->getBitmap(), &AB, tmpA, NULL);
SDL_BlitSurface(obj->getSprite()->getBitmap(), &AB, tmpB, NULL);
You draw both sprites at the same position on tmpA and tmpB. You do your calculations as if both sprites' x and y positions are the same - and usually they aren't.
You should do something like this:
SDL_Rect relativeA;
relativeA.x=A.x-AB.x;
relativeA.y=A.y-AB.y;
SDL_Rect relativeB;
relativeB.x=B.x-AB.x;
relativeB.y=B.y-AB.y;
SDL_BlitSurface(m_Sprite->getBitmap(), &relativeA, tmpA, NULL);
SDL_BlitSurface(obj->getSprite()->getBitmap(), &relativeB, tmpB, NULL);
You can use the rects A and B instead of making new ones, but I gave them new names to make it easier to understand.
Am I supposed to this in the chain of if:s when setting the AB-values, or after?
I don't really think I understand the idea.
I don't really think I understand the idea.
You do this after the chain of ifs, when the values of AB are already set.
Take a look at this picture:
The right part of the picture is the screen. The green area is the collision are between the bounding boxes of the two sprites, and is represented by AB. You calculate the relative position of A from the AB(notice that in this case, relativeA.x and relativeA.y are negative, because A is located up and left from AB). After that, you draw A to tmpA - the left part of the picture. You draw it at relativeA, so only the section of A that is colliding with B will be drawn to tmpA, and it will be draw at the correct location.
You do the same thing with B, and you'll have two SDL_Surfaces that represent the colliding sections of tmpA and tmpB. You know what to do from here...
Take a look at this picture:
The right part of the picture is the screen. The green area is the collision are between the bounding boxes of the two sprites, and is represented by AB. You calculate the relative position of A from the AB(notice that in this case, relativeA.x and relativeA.y are negative, because A is located up and left from AB). After that, you draw A to tmpA - the left part of the picture. You draw it at relativeA, so only the section of A that is colliding with B will be drawn to tmpA, and it will be draw at the correct location.
You do the same thing with B, and you'll have two SDL_Surfaces that represent the colliding sections of tmpA and tmpB. You know what to do from here...
Allright! I think I understand now why to use these variables.
My other problem is that I allways get a junk value from SDL_GetRGB().
I want r, g and b to take the corresponding values of the currently selected pixel. But i always end up with something like (200, 59, 91). Odd.
Wouldn't it be nice if SDL stored each single pixel as a struct, holding x, y, and SDL_Color. :(
My other problem is that I allways get a junk value from SDL_GetRGB().
I want r, g and b to take the corresponding values of the currently selected pixel. But i always end up with something like (200, 59, 91). Odd.
Wouldn't it be nice if SDL stored each single pixel as a struct, holding x, y, and SDL_Color. :(
You should pass the surface format to SDL_GetRGB:
Or you could use the getpixel/setpixel functions from the SDL documentation.
It is possible to do this without allocating additional surfaces.
Uint32* pixelA = (Uint32*)(tmpA->pixels + y * tmpA->pitch + x * 2);SDL_GetRGB(*pixelA, tmpA->format, &r, &g, &b);
Or you could use the getpixel/setpixel functions from the SDL documentation.
It is possible to do this without allocating additional surfaces.
IMO, pixel perfect collision detection is more trouble than it's worth. Generating a few polygons for each object is easy to code, is much faster to execute, gives you much more information (penetration depth, collision normal) from which to perform collision response, and is almost as accurate.
"IMO, pixel perfect collision detection is more trouble than it's worth. Generating a few polygons for each object is easy to code, is much faster to execute, gives you much more information (penetration depth, collision normal) from which to perform collision response, and is almost as accurate."
Yes, well thanks for the input, but as I mentioned in OP it is not a matter of saving processor-speed. I just want to learn how to make pixel perfect collision testing, because I think that it would be a nice thing to know.
btw, if you would please hand me some info about your way of collision testing I would be glad.
Yes, well thanks for the input, but as I mentioned in OP it is not a matter of saving processor-speed. I just want to learn how to make pixel perfect collision testing, because I think that it would be a nice thing to know.
btw, if you would please hand me some info about your way of collision testing I would be glad.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement