MAYA, TUTORIALS, RIGID BODY COLLISION DETECTION

ABOUT
This tutorial shows you how to detect collisions between rigid bodies and how to use the data to drive your animations - welcome to the land of rule based animation. I'll assume you are familiar with the basics of rigid body dynamics (setup, attachment to fields etc.) - if not, please consult the manuals.

Note: While writing the expressions, my main concern was not speed nor size - I know the code could be optimized in these directions but I decided to keep it simple and readable, so someone who is not this familiar with programing can understand what's going on.

PREPARATIONS
Before we can start with the collision detection, let's build ourselfs a rigid body dynamics playground:

Create a simple polygon stair and 3 cubes.
Turn the stair into a passive rigid body, rename the rigidBody node to "rigidBodyPassive"
Turn the cubes into active rigid bodies, rename the respective rB nodes into "rigidBody1-3".
Attach a gravityField to the cubes and place the cubes, so they'll fall down the stairs and collide with each other. - Tweak the scene until you're happy with the animation

An example rigid body setup,
you can download the demo scene here.

((Select the rigidBodySolver and make sure "contactData" is turned on, now))

Now, create a transform node and name it "rb1ContactData", we will use this node to store all the expressions and data for rigidBody1 we'll need later on. Add an integer attribute "EXPR", add the following expression to this attribute:

rb1ContactData.EXPR = 0;

The only purpose of this is to give us access to the expression editor, we will store the real expressions here later on. ( This is a technique I often use, instead of spreading expressions and custom attributes everywhere in my scene I make a simple interface object that stores all the necessary data for easy access - a great helper, especially in complex scenes.)

OBTAINING CONTACT COUNT
Add an integer attribute "contactCount" to "rb1ContactData".
Add these lines to the expression at "EXPR" :

rb1ContactData.EXPR =0;

// variables
string $myRigidBody = "rigidBody1";
int $contactCount;

// get $contactCount
$contactCount = `getAttr($myRigidBody+".contactCount")`;

// set interface attributes
rb1ContactData.contactCount = $contactCount;

Well, still no big deal here, just copying the data from one attribute to our custom. Play the simulation to see how our "contactCount" changes over time (you might need to step forward single frames to spot the exact point in time your rigidBody hits other rigidBodies).
This works fine - however, there are some issues with Mayas rigid body engine, that might produce results you don't want:

A) multiple collisons with the same object in one frame

I guess it attracted your attention that sometimes (very often!) the contactCounter displays a bigger value than the number of objects it actually collides with. This is due to multiple collisions with the same object in one frame. In case you want a uniqueContactCount, we've got to use the other contactData provided by the system. What we will be doing is: Get the names of the objects our rigidBody is currently in contact with (a list of strings), flatten this list to delete all multiple entries of the same name, so the number of remaining items will be the value of unique contacts.
As flattening a string array is not part of the core MEL functions, here is one kindly provided by Julian Love (part of the really useful arrayTools set, download it now at Highend3D ).

// flattenStringArray: by Julian Love, julian.love@sierra.com.
//
// Action: Part of the arrayTools set, this one will return a
//
new array composed only of unique items from the supplied array.
//
// Examples:
// $fatArray = {"blue", "blue", "red", "green", "blue", "green"};
// flattenStringArray $fatArray;
// // Result: blue red green //

global proc string[] flattenStringArray (string $array[])
{
  string $x; string $y;
  string $newArray[];
  int $itemFound = 0;

  $newArray[0] = $array[0];
  for ($x in $array)
  {
    $itemFound = 0;
    for ($y in $newArray)
    {
      if ($x == $y) {$itemFound = 1;}
    }
    if ($itemFound == 0) {$newArray[size($newArray)] = $x;}
  }

  return ($newArray);
}

Source this script. Now add another custom attribute "uniqueContactCount" of type integer to our "rb1ContactData" node, so we can use it in our expression:

rb1ContactData.EXPR =0;

// variables
string $myRigidBody = "rigidBody1";
int $contactCount;
int $uniqueContactCount;

// get $contactCount
$contactCount = `getAttr($myRigidBody+".contactCount")`;

// compute $uniqueContactCount
if ($contactCount > 0)
{
  string $array[] = `rigidBody -q -contactName $myRigidBody`;
  string $flatArray[] = flattenStringArray($array);
  $uniqueContactCount = size($flatArray);
}
else
{
  $uniqueContactCount = 0;
}

// set interface attributes
rb1ContactData.contactCount = $contactCount;
rb1ContactData.uniqueContactCount = $uniqueContactCount;

to be continued...