Archived

This topic is now archived and is closed to further replies.

DeathCheese

pixel perfect collision problem

Recommended Posts

DeathCheese    122
Hey, I''ve been driving myself insane lately to try and get a Pixel Perfect collision detection routine to work for my 2d game using DirectDraw7. I''ve read all the tutorials here, I''ve searched this forum and read as many posts as I could find about PP, and I feel like I am SO close. So let me just say first off, I understand the theory 100% behind it, I am just having trouble getting it to work. Here''s my whole collision function(sorry for the long post) player1 and player2 are members of my own sprite class, containing an array of members "frame" which is a DirectDraw7 surface, representing each different bitmap I load in.

//returns 1 for a collision, 0 for no collision
int Collision()
{
	int AX1 = player1.x;
	int AY1 = player1.y;
	int BX1 = player2.x;
	int BY1 = player2.y;

	int AX2 = AX1 + player1.width;
	int AY2 = AY1 + player1.height;		
	int BX2 = BX1 + player2.width;
	int BY2 = BY1 + player2.height;
	int CX1, CY1, CX2, CY2;	//to hold collision rect
	int aStartX, bStartX, aStartY, bStartY, aEndX, bEndX, aEndY, bEndY;
	int q, r;

	//if any of these four cases are TRUE, no collision can have occured
	if(BY2 < AY1) return(0);
	if(AY2 < BY1) return(0);
	if(BX2 < AX1) return(0);
	if(AX2 < BX1) return(0);

	//collision MIGHT have occured
	if(AX1 < BX1)
	{
		//set the overlapping coords
		CX1 = BX1;
		CX2 = AX2;

		aStartX = CX1 - AX1;
		bStartX = 0;
		aEndX	= 128;
		bEndX	= CX2 - CX1;
	}
	else
	{
		CX1 = AX1;
		CX2 = BX2;

		bStartX = CX1 - BX1;
		aStartX = 0;
		bEndX	= 128;
		aEndX	= CX2 - CX1;
	}

	if(AY1 < BY1)
	{
		CY1 = BY1;
		CY2 = AY2;

		aStartY = CY1 - AY1;
		bStartY = 0;
		aEndY	= 128;
		bEndY	= CY2 - CY1;
	}
	else
	{
		CY1 = AY1;
		CY2 = BY2;

		bStartY = CY1 - BY1;
		aStartY = 0;
		bEndY	= 128;
		aEndY	= CY2 - CY1;
	}

	DDSURFACEDESC2 ddsd1, ddsd2;

	//Clear out the ddsd struct
	memset(&ddsd1, 0, sizeof(ddsd1));
	ddsd1.dwSize = sizeof(ddsd1);

	memset(&ddsd2, 0, sizeof(ddsd2));
	ddsd2.dwSize = sizeof(ddsd2);

	//lock the buffers
	player1.frame[player1.curr_frame]->Lock(NULL, &ddsd1, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
	player2.frame[player2.curr_frame]->Lock(NULL, &ddsd2, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);

	UCHAR *pixel1 = (UCHAR *)ddsd1.lpSurface;
	int pitch1 = ddsd1.lPitch;

	UCHAR *pixel2 = (UCHAR *)ddsd2.lpSurface;
	int pitch2 = ddsd2.lPitch;

	q = bStartX;
	r = bStartY;
	for(int i=aStartY; iUnlock(NULL);
				player2.frame[player2.curr_frame]->Unlock(NULL);

				return 1;
			}
			q++;
		}
		r++;
	}

	player1.frame[player1.curr_frame]->Unlock(NULL);
	player2.frame[player2.curr_frame]->Unlock(NULL);

	return 0;
}
[code]
I hope this makes any sense...
I *believe* my problem is in here:
[code]
	q = bStartX;
	r = bStartY;
	for(int i=aStartY; iUnlock(NULL);
				player2.frame[player2.curr_frame]->Unlock(NULL);

				return 1;
			}
			q++;
		}
		r++;
        }
 
this is where I''m testing each pixel to see if it is NOT my transparent color(219 - i''m using 8bit mode, 219 is the palette index) The function ALWAYS returns before any non-transparent pixels are on top of each other. My brain is fried right now, so if you need more info on my function, please ask. and if anyone can see any stupid mistakes I''m making(as I''m sure I''m making at least one) please help me out. thanks in advance...

Share this post


Link to post
Share on other sites
granat    122
Do you really NEED pixel perfect collision detection ??

Pixel perfect collision detection involving Lock() & UnLock() does not strike me as fast...

But of course if you have enough cycles to spare....

Share this post


Link to post
Share on other sites
level10boy    122
I''ve done PP collision detection with Directx8 and here is what I think is the best way to go about it. First at initialization time, you should pre-process a set of binary collision masks from all your textures/surfaces that are going to be involved in PP collision tests. Doing this means there is no locking and unlocking during run-time of textures/surfaces. The rest should then be obvious. First test for bounding rect collision, if a collision has occured you need to compute the dimensions of the overlapped rect involved in collision. Then using this overlapped rect, you need to compute offsets into each collision mask that represents the current texture/surface being displayed for the two colliding entities. You then perform the overlap test. The whole process is quite involved so be prepared to sit down with a pen a paper and hammer it for a while, but it looks like you''ve already figured the hard part.

Share this post


Link to post
Share on other sites
cybrgeek    122
See my code at http://www.gamedev.net/community/forums/topic.asp?topic_id=69411 this also includes an explination of the code. The code is kinda old because I moved to DirectX8 for graphics, but it should be all you need. It isn''t coded to work with a surface that is drawn flipped, but that''s not too hard to do.

Share this post


Link to post
Share on other sites
BeerNutts    4401
DeathCheese,

I''ve done exactly what you did not too long ago, and went through probably the same progressions. I first tried locking both overlapping surfaces every time they intersected, but that was painfully slow. Then I did what level10boy suggested, and everytime I loaded a new frame, I associated a bitmask with it at load-time, and I now have pixel-perfect collision.

If you want, I''d be glad to share that part of the code with you. It''s done in DX7, and it supports page flipping.

Let me know wwjennings@earthlink.net

Nutts

Share this post


Link to post
Share on other sites
Arion    133

Yea, that''s what I did as well.
Really speeds things up.
I use it for animated and non-animated sprites.

I read John Amato''s article in the Articles and Resources section, and re-adapted the algos with bitmasks. I was really happy with the result.

Guy

Share this post


Link to post
Share on other sites