Archived

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

apollyon

pixel collision detection help

Recommended Posts

I think I did this right, but I'm not sure... it's reporting a collision at the first time it runs through the loop. OK I AM PUTTING COMMENTS IN FOR MR. I'M TOO GOOD FOR MYSELF. (pardon my debug/test/console stuff)
          
int CWaterPolo::CheckCollision ( CPlayer *Player, CObject *Object )
{
// DDSURFACEDESC TO GET PITCH WHEN I LOCK SURFACE

	DDSURFACEDESC2 ddsdBlank;
	DDRAW_INIT_STRUCT(ddsdBlank);
// RECTS FOR BOUNDING BXES

	RECT rOne, rTwo, rOverlap;
	RECT rOneOverlap, rTwoOverlap;
// WIDHT AND HEIGHT OF OVERLAP

	int overlapWidth, overlapHeight;
// LOOP VARS

	int i, j;
// PIXELS FOR SURFACES

	UINT *pixel1, *pixel2;
// USING THIS TO CHEAT OUT OF THE LOOP

bool iscollision = false;
// WIDTH OF BITMAPS

	int oneWidth, twoWidth;
// USED FOR MAKING THE CODE A LITTLE EASIER TO READ

// X AND Y POSITIONS

	int onex;
	int oney;
	int twox;
	int twoy;
// THE COLOR KEY

	UINT ColorKey = _RGB16BIT565(255, 0, 255);

// FILL IN COMPARISON RECTS

	rOne.left = Player->GetX();
	rTwo.left = Object->GetX();
	rOne.right = Player->GetX() + Player->CurrBitmap->GetWidth();
	rTwo.right = Object->GetX() + Object->GetWidth();
	rOne.top = Player->GetY();
	rTwo.top = Object->GetY();
	rOne.bottom = Player->GetY() + Player->CurrBitmap->GetHeight();
	rTwo.bottom = Object->GetY() + Object->GetHeight();

// TEST IF THE BOUNDING BOXES INTERSECT

	if (IntersectRect(&rOverlap, &rOne, &rTwo))
	{
// FILL IN OVERLAP RECTANGLE INFORMATION

// FIRST ONE

		rOneOverlap.top = rOverlap.top - rOne.top;
		rOneOverlap.bottom = rOverlap.bottom - rOne.top;
		rOneOverlap.left = rOverlap.left - rOne.left;
		rOneOverlap.right = rOverlap.right - rOne.left;
// SECOND ONE

		rTwoOverlap.top = rOverlap.top - rTwo.top;
		rTwoOverlap.bottom = rOverlap.bottom - rTwo.top;
		rTwoOverlap.left = rOverlap.left - rTwo.left;
		rTwoOverlap.right = rOverlap.right - rTwo.left;

// FILL IN WIDTH AND HEIGHT OF OVERLAPPING AREA

		overlapWidth = rOverlap.right - rOverlap.left - 1;
		overlapHeight = rOverlap.bottom - rOverlap.top - 1;

// LOCK SURFACES AND GET THEIR PITCH AND SURFACE

// LOCK SURFACE ONE

		surfaceone = Player->CurrBitmap->GetSurface();
		surfaceone->Lock(&rOneOverlap, &ddsdBlank, DDLOCK_WAIT | DDLOCK_READONLY, 0);
		pixel1 = (UINT *)ddsdBlank.lpSurface;
		int oneWidth = ddsdBlank.lPitch;
// LOCK SURFACE TWO

		surfacetwo = Object->GetSurface();
		DDraw->GetSurface(BACK_BUFFER)->Blt(&temp, surfacetwo, &rTwoOverlap, DDBLT_WAIT | DDBLT_KEYSRC, 0);
		surfacetwo->Lock(&rTwoOverlap, &ddsdBlank, DDLOCK_WAIT | DDLOCK_READONLY, 0);
		pixel2 = (UINT *)ddsdBlank.lpSurface;
		twoWidth = ddsdBlank.lPitch;

// LOOP THROUGH AND COMPARE THEIR PIXEL VALUES TO THE COLORKEY

		for (i = 0; i < overlapWidth; i++)
		{
			for (j = 0; j < overlapHeight; j++)
			{
				if (pixel1[i + onex + (j + oney) * oneWidth] != ColorKey
					&& pixel2[i + twox + (j + twoy) * twoWidth] != ColorKey)
				{
					Console.AddMessage("Collision occurred!");

					iscollision = true;
					break;
				}
			}
			if (iscollision)
				break;
		}
// UNLOCK THE SURFACES

		surfaceone->Unlock(&rOneOverlap);
		surfacetwo->Unlock(&rTwoOverlap);
// THERE IS A COLLISION

		if (iscollision)
			return 1;
	}
// NO COLLISION!

	return 0;
}
          
What am I doing wrong? I can see it's checking the correct RECTs and stuff, but it returns the first time through the loop! Help! [edited by - apollyon on June 9, 2002 5:19:26 PM] [edited by - apollyon on June 10, 2002 6:28:36 PM]

Share this post


Link to post
Share on other sites
I don''t think I''m going to waste my time trudging though all that code with out any comments, spaces between the lines, and hardly any modularity.

It will make your life (and others looking at your code) much easier if you add comments while you write, declare all variables at the top of the function (or block atleast), and have some spaces between lines for God''s sake.

Other than that, this problem is a simple logic problem which you should solve yourself instead of asking us to do your work for you.

Breakpoints, Breakpoints, and more Breakpoints.

Nutts

Share this post


Link to post
Share on other sites
Um, yeah, I explained that it the first time it goes through the loop it kills itself. Maybe you should learn to read, moron. I apologize for the lack of comments, but that''s not the case. I determined what the problem is, and I don''t know how to go about fixing it. When I compare the pixel to the color key, it automatically says it''s the same. The hostility you''ve expressed does wonders for your character, dude. You could''ve at least attempted to read it.

Share this post


Link to post
Share on other sites
Wasn''t trying to be hostile, but when you offer up code for people to debug for you, you should try and make it as easy as possible for them to do so.

Besides, I really don''t have the time to look through your code and debug it for you. I can offer 1 suggestion (I''ve done pixel-per-pixel collision too): Don''t Lock and Unlock the surface, it''s too slow. Instead, store seperate masks for each image with one bit-per-pixel. It will do wonders for your speed.

Share this post


Link to post
Share on other sites
Some pixel collision stuff
Bits and pieces from my sprite engine ( 16 bit stuff ).

_____________________________________________________________
// make an array to hold the bitmask
BOOL *source_bitmask;
source_bitmask = new BOOL [ surface_width * surface_height ];

_____________________________________________________________

We have to set up a bitmask for the surface.
The pixel data will be copied onto the above array as BOOL.


  
void SPRITE::Load_Bitmask()
{
int fb_cnt = 0;
USHORT *surf_ptr; // A pointer to the surface


DDSURFACEDESC2 ddsd;

ZeroMemory( &ddsd, sizeof(DDSURFACEDESC2));
ddsd.dwSize = sizeof(ddsd); // Load size


// Lock the surface

( surface ) -> Lock( NULL,
&ddsd,
DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR,
NULL);
// Get a pointer to surface

surf_ptr = (USHORT *)ddsd.lpSurface;

// Load the bitmask looping through the surface

for ( DWORD i = 0 ; i < surface_height ; i++ )
{ for ( DWORD j = 0 ; j < surface_width ; j++ )
{
// Calculate position in array

fb_cnt = ( ( i * surface_width ) + j );
// If the value is not 0, set the BOOL to TRUE

source_bitmask [ fb_cnt ] = ( *surf_ptr != 0 ) ? TRUE : FALSE;
// Increment the surface pointer

surf_ptr++;
}
}

// Unlock the surface

( surface ) -> Unlock(NULL);

}// end Load_Bitmask



_____________________________________________________________


Now we have to test for a collision
I made this a global fuction and made it a friend to my sprite class. This is rather bulky code, but it was written for animated and non-animated sprites. I hope you can follow it.



  
short int Sprite_Sprite_Collide( SPRITE *ptr_1, SPRITE *ptr_2 )
{
int sp_width_1 = ptr_1 -> width;
int sp_width_2 = ptr_2 -> width;
RECT frame_1, frame_2;
int frame_offset_1, frame_offset_2;
int over_left, over_right;
int over_top, over_bottom;;
int over_width,over_height;
int i, j;
int y1_offset, y2_offset;
BOOL *P_p1, *P_p2;

// Quick Reject Stuff

if ( ptr_1 -> dest_rect.bottom < ptr_2 -> dest_rect.top ) return(0);
if ( ptr_1 -> dest_rect.top > ptr_2 -> dest_rect.bottom ) return(0);
if ( ptr_1 -> dest_rect.right < ptr_2 -> dest_rect.left ) return(0);
if ( ptr_1 -> dest_rect.left > ptr_2 -> dest_rect.right ) return(0);

// Get the overlapping rectangle

if ( ptr_1 -> dest_rect.bottom > ptr_2 -> dest_rect.bottom )
over_bottom = ptr_2 -> dest_rect.bottom;
else over_bottom = ptr_1 -> dest_rect.bottom;

if ( ptr_1 -> dest_rect.top < ptr_2 -> dest_rect.top )
over_top = ptr_2 -> dest_rect.top;
else over_top = ptr_1 -> dest_rect.top;

if ( ptr_1 -> dest_rect.right > ptr_2 -> dest_rect.right )
over_right = ptr_2 -> dest_rect.right;
else over_right = ptr_1 -> dest_rect.right;

if ( ptr_1 -> dest_rect.left < ptr_2 -> dest_rect.left )
over_left = ptr_2 -> dest_rect.left;
else over_left = ptr_1 -> dest_rect.left;

// Calculate frame offsets for object 1

frame_1.left = ( over_left - (int)ptr_1 -> x_pos );
frame_1.top = ( over_top - (int)ptr_1 -> y_pos );
frame_1.right = ( over_right - (int)ptr_1 -> x_pos );
frame_1.bottom = ( over_bottom - (int)ptr_1 -> y_pos );
frame_offset_1 = ( frame_1.top * sp_width_1 ) + frame_1.left;

if ( ptr_1 -> animated == TRUE )
{ frame_offset_1 += ( ptr_1 -> source_rect.top * sp_width_1 ) +
ptr_1 -> source_rect.left;
}

// Calculate frame offsets for object 2

frame_2.left = ( over_left - (int)ptr_2 -> x_pos );
frame_2.top = ( over_top - (int)ptr_2 -> y_pos );
frame_2.right = ( over_right - (int)ptr_2 -> x_pos );
frame_2.bottom = ( over_bottom - (int)ptr_2 -> y_pos );
frame_offset_2 = ( frame_2.top * sp_width_2 ) + frame_2.left;

if ( ptr_2 -> animated == TRUE )
{ frame_offset_2 += ( ptr_2 -> source_rect.top * sp_width_2 ) +
ptr_2 -> source_rect.left;
}

// The size of the overlapping rectangle

over_width = abs( over_right - over_left );
over_height = abs( over_bottom - over_top );

// Loop through the bitmask checking for TRUE in

// both of the objects bitmasks.

for ( i = 0 ; i < over_height ; i ++ )
{ y1_offset = ( i * sp_width_1 ) + frame_offset_1;
y2_offset = ( i * sp_width_2 ) + frame_offset_2;

P_p1 = &ptr_1 -> source_bitmask [ y1_offset ];
P_p2 = &ptr_2 -> source_bitmask [ y2_offset ];
for ( j = 0 ; j < over_width ; j++, P_p1++, P_p2++ )
{
if ( ( *P_p1 == TRUE ) && ( *P_p2 == TRUE ) )
{ ptr_1 -> pixel_hit = y1_offset + j;
ptr_2 -> pixel_hit = y2_offset + j;
return(1); }
}// end for j

}// end for i


return(0);
}// end Sprite_Sprite_Collide



Well that''s how I did it. I re-wrote John Amatos collision algos with bitmasks. If find the collision detection rather quick.

Guy

Share this post


Link to post
Share on other sites