[ODE] Collision callback pattern

Nate W coding at natew.com
Mon Sep 1 23:19:01 2003


On Tue, 2 Sep 2003, Dave Lloyd wrote:

> Seems like a good strategy then would be to blend the materials 
> empirically according to 'typical physics' (i.e., best guess) and 
> provide escape mechanisms for unusual material combinations. An 
> alternative would be to provide a rule for each pair of surface types - 
> admittedly more awkward to introduce new surfaces as each combination 
> must be considered but I suspect in many cases there won't be that many 
> surface types.

Ok, so... thinking out loud, for a racing game...

// Enumerate material types, with the last item in the enum being the
// number of material types
enum MaterialType
{
	kDirt = 0, 
	kAsphalt, 
	kIce,
	kTire, 
	kBodywork, 
	kMaterialTypes
}

// Pointer to a function that sets properties for a contact, given the
// two materials that are colliding.
typedef void (*ContactPropertiesProc) (dContact *pContact,
		Material *pM1, Material *pM2);

void Default (dContact *pContact,
		Material *pM1, Material *pM2);

{
	// use "best guess" method, based on the two material types
}

void TireAndAsphalt (dContact *pContact,
		Material *pM1, Material *pM2);
{
	// Use more sophisticated method for tire-asphalt contacts
	// The two material type parameters could be ignored, or maybe it
	// could be asserted that one material is "tire" and the other is
	// "asphalt."
}

void TireAndDirt (dContact *pContact,
		Material *pM1, Material *pM2);
{
	// Use different method for tire-dirt contacts
}

// 2D array of those function pointers
ContactPropertiesProc PropertySetters[kMaterialTypes][kMaterialTypes];

void InitContactPropertySetterArray ()
{
	// Fill the array with the default function pointer
	for (int i = 0; i < nMaterials; i++)
		for (int j = 0; j < nMaterials; j++)
			PropertySetters[i][j] = Default;

	// Set the 'special case' contact property functions
	PropertySetters[kTire][kAsphalt] = TireAndAsphalt;
	PropertySetters[kAsphalt][kTire] = TireAndAsphalt;

	PropertySetters[kTire][kDirt] = TireAndDirt;
	PropertySetters[kDirt][kTire] = TireAndDirt;
}


// This function is slightly abridged...
void CollisionCallback (dGeomID o1, dGeomID o2)
{
	// Get the materials and their enums
	Material* pM1 = GetMaterial (o1);
	Material* pM2 = GetMaterial (o2);
	MaterialType mt1 = GetMaterialType (pM1);
	MaterialType mt2 = GetMaterialType (pM2);

	// Get the property setter for this material combination
	ContactPropertiesProc PropertySetter = PropertySetters[mt1][mt2];

	dContact Contact[ODE_MAX_CONTACTS];
	
	int iCount = dCollide (o1, o2, iContacts, 
		&Contact[0].geom, sizeof (dContact));

	for (int iContact = 0; iContact < iMax; iContact++)
	{
		// Set the contact properties with the property setter
		PropertySetter (Contact[iContact], pM1, pM2)
	
		// Create the contact joint as usual
		dJointID ContactJoint = dJointCreateContact (WorldID,
			CollisionJointGroup, &Contact[iContact]);
	}
}

--

I think it'd work, but I'm not promising. :-)

--

Nate Waddoups
Redmond WA USA
http://www.natew.com