Skip to main content
gamedev.net
🔒 Locked 🎲 GameMaker

Collision detection problems

Started by Prog101 0 replies 1k views
Original Post
Prog101
Prog101
Using DirectX 9 and c++ i am making a car game but my collision detection is playing up on me, I am using OBB collision and what is happening is when the car hits the wall it gets stuck and does not easily come away from the wall. Check out the exe at http://homepage.ntlworld.com/j.power40/html/zipfiles/CarExe.zip Bounding /Box Code


void	CBoundingVolumes::BoundingVolumes_CreateBox(LPDIRECT3DDEVICE9 device, ID3DXMesh* mesh, float scale)
{
	//******************** Compute Bounding Box
	BoundingVolumes_Box_Compute(mesh, &s_BoundingBox);

	s_BoundingBox.Scale = scale;
	s_BoundingBox._max *= s_BoundingBox.Scale;
	s_BoundingBox._min *= s_BoundingBox.Scale;

	D3DXCreateBox(
		device,
		s_BoundingBox._max.x - s_BoundingBox._min.x,
		s_BoundingBox._max.y - s_BoundingBox._min.y,
		s_BoundingBox._max.z  - s_BoundingBox._min.z,
		&BoxMesh,
		0);
}
bool CBoundingVolumes::BoundingVolumes_Box_Compute(ID3DXMesh* mesh, sBoundingBox* box)
{
	HRESULT hr = 0;

	BYTE* pVertices = NULL;
	hr=mesh->LockVertexBuffer(0, (void**)&pVertices);
	if (FAILED(hr))
		return FALSE;
	hr = D3DXComputeBoundingBox(				//D3D Function that calc's the bounding box for a mesh
		(D3DXVECTOR3*)pVertices,				//Vertex position component is stored 1st in the vertex structure we are using
		mesh->GetNumVertices(),					//Get the number of vertices's in the mesh
		D3DXGetFVFVertexSize(mesh->GetFVF()),	//function how many bytes there are between each vertex 
		&box->_min,								//Return the min and max points of the bounding box
		&box->_max);

	mesh->UnlockVertexBuffer();

	if( FAILED(hr) )
		return false;

	return true;
}

sBoundingBox::sBoundingBox()
{
	// infinite small 
	_min.x = INFINITY;
	_min.y = INFINITY;
	_min.z = INFINITY;

	_max.x = -INFINITY;
	_max.y = -INFINITY;
	_max.z = -INFINITY;
}
void CBoundingVolumes::Update_OBB(D3DXMATRIX ObjectMatrix, D3DXVECTOR3 min, D3DXVECTOR3 max)
{
	// We have min and max values, use these to get the 8 corners of the bounding box
	m_objectBounds[0] = D3DXVECTOR3(min.x,min.y,min.z ); // XYZ
	m_objectBounds[1] = D3DXVECTOR3(max.x,min.y,min.z ); // XYZ
	m_objectBounds[2] = D3DXVECTOR3(min.x,max.y,min.z ); // XYZ
	m_objectBounds[3] = D3DXVECTOR3(max.x,max.y,min.z ); // XYZ
	m_objectBounds[4] = D3DXVECTOR3(min.x,min.y,max.z ); // XYZ
	m_objectBounds[5] = D3DXVECTOR3(max.x,min.y,max.z ); // XYZ
	m_objectBounds[6] = D3DXVECTOR3(min.x,max.y,max.z ); // XYZ  
	m_objectBounds[7] = D3DXVECTOR3(max.x,max.y,max.z ); // XYZ

	for( int i = 0; i < 8; i++ )
		D3DXVec3TransformCoord( &worldBounds, &m_objectBounds, &ObjectMatrix );

	this->CalcAABBFromOBB(worldBounds,min,max);
}
/*********************************************************************************
Given the 8 corners of a OBB bounding box in world space, create a AABB bounding box in world space
*********************************************************************************/
void CBoundingVolumes::CalcAABBFromOBB(D3DXVECTOR3 *ObjectBounds,D3DXVECTOR3 min, D3DXVECTOR3 max)
{
	min.x = max.x = ObjectBounds[0].x;
	min.y = max.y = ObjectBounds[0].y;
	min.z = max.z = ObjectBounds[0].z;

	for (int i=1;i<8;i++)
	{
		if (ObjectBounds.x <min.x)min.x = ObjectBounds.x;
		if (ObjectBounds.x >max.x)max.x = ObjectBounds.x;
		if (ObjectBounds.y <min.y)min.y = ObjectBounds.y;
		if (ObjectBounds.y >max.y)max.y = ObjectBounds.y;
		if (ObjectBounds.z <min.z)min.z = ObjectBounds.z;
		if (ObjectBounds.z >max.z)max.z = ObjectBounds.z;
	}
	s_BoundingBox.vMin = min;
	s_BoundingBox.vMax = max;
}




collision code

int Game::update(void)
{ 
        pCar->getPosition(LastPosition);

        // UPDATE THE MOVEMENT AND PHYSICS HERE
        // Update the oriented bounding box
        pCar->pBoundingBox->Update_OBB(pCar->finalMatrix,pCar->pBoundingBox->s_BoundingBox._min,pCar->pBoundingBox->s_BoundingBox._max);
	Collisions();
}
/********************************************************************
* collisions: this function handles all the collisions and responces
********************************************************************/
void Game::Collisions(void)
{	
	//* Perform a collision checks for the player and the walls
	for (unsigned int i=0; i<pWall.size();i++)
	{
		pCar->get_BoundingBox(&playerBB);
		pWall->get_BoundingBox(&wallBB);
		if (Collision_BoxCheck(playerBB,wallBB))
		{
			pCar->setPosition(LastPosition);
			break;
		}
		else bCollision = false;
	}
}

bool Collision_BoxCheck(const sBoundingBox& pBox1, const sBoundingBox& pBox2)
{
	/*If the max x position of 1 is less than the min x position of 2 they do not collide 
	If the min x position of 1 is greater than the max x position of 2 they do not collide 
	and the same goes for y and z */
	if (   pBox1.vMax.x < pBox2.vMin.x || pBox1.vMin.x > pBox2.vMax.x
		|| pBox1.vMax.y < pBox2.vMin.y || pBox1.vMin.y > pBox2.vMax.y
		|| pBox1.vMax.z < pBox2.vMin.z || pBox1.vMin.z > pBox2.vMax.z)
		return false;
	else
		return true;
}



[Edited by - Prog101 on April 4, 2007 9:37:23 AM]
bootstrap
bootstrap
I wish I could give you a more useful reply, but I do want to say that I had the exact same problem several years ago when I wrote a PS2 game engine - and much of the first game. I suppose I can laugh now, but at the time it was extremely infuriating! And I remember it took much longer to solve than much more difficult problems. I do not say this to depress you, just to say that whatever the problem was, it was also subtle for me to figure out. At least I will try to raise a few issues in case they help you get un-stuck.

First of all, the reason you get "stuck" is probably because your test for collision is "are you on the opposite side of the barrier than before". This is usually determined by a calculation of the distance from the object to the barrier --- if the *sign* of the distance changed (+ to - or - to +) then this signals a collision. You get "stuck" because the routine that *supposedly* moves the object back to the other side of the wall, actually does not do so. Then, subsequent attempts to move the object away from the barrier are considered collisions, because *they* are moving across the barrier.

The most likely *cause* of this problem is pretty obvious now that I think about it. The code that moves the object each frame is in a different part of your engine --- every moving object is moved in some big loop or something, and *then* you do collision detection (or vice-versa). This can cause the problem in a large number of similar ways. For example, if you detect the collision and move the object on the correct side of the barrier, but then the object is moved the nominal distance (that it has been moving) in a later step, the object is put right back on the wrong side of the barrier again! And it gets stuck there because your next test prohibits moving from one side of the barrier to the other side! Also at issue is exactly where your code sets the nominal distance to move - which more-or-less needs to get "reflected" off the barrier in some way (bounce off the barrier). If the nominal move-distance has not been updated at the right time, the next move puts the object on the wrong side of the barrier. Another possible reason for the problem is forgetting to set the "current" position of the object to the collision-response modified position [at the right moment].

All in all, I suspect my problems were somewhat similar to the above, because they all sound familiar! But these may be some of the issues I considered and checked - but not the one that shafted me. But I do have a feeling it *was* one of these - or similar.

If your code keeps the "previous position" of objects (and/or their bounding spheres/boxes), you probably need to update the "previous positions" *and* the "current position" in the code that does collision response. And you definitely need to notice which comes first each frame, and carefully consider the consequences of the order everything happens. This is probably the problem in some shape or form.

I hope this helps. Sorry I have to little time to inspect your code.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.