How do I detect a rigid body was involved in a collision?

Jan 7, 2008 at 3:52 PM
Hi,

I manage to get the integration to work correctly. I am just wondering

1) How do I know that an entity was involved in a collision
2) When should I check for that event?
3) How does an entity know which other entity it has collided into?

Thanks in advance!
Coordinator
Jan 7, 2008 at 5:11 PM
Edited Jan 7, 2008 at 5:13 PM
Hi extrakun!

1 and 2) Take a look at this thread - https://www.codeplex.com/Thread/View.aspx?ProjectName=OopsFramework&ThreadId=18595. Essentially, you need to implement the ICollisionCallback interface like the MainMenuScreen.cs does. The main thing to know is that the methods of this interface get called for every contact, not just collisions. So, resting contacts will notify the callback as well. There are hints in the thread above about filtering out those types of contacts.

3) The callback methods give you the collision shapes involved in the collision, so you can get to the CollisionShape instances, the RigidBody instances (via the CollisionShape.RigidBody property) or any user defined object, such as your entity class (via the CollisionShape.RigidBody.Tag property).
Jan 8, 2008 at 4:54 PM
Edited Jan 8, 2008 at 4:56 PM
Hi FretboardOfFury,

I took a look at the thread you have recommended, and at the sample code, but still have some doubts.

1) And I right in assuming that RigidBody.Tag is a generic object reference, and hence i can use it to 'point' to my entity?
2) In MainMenuScreen.cs, the OnCollided(Collisonshape x, Collisionshape y, Collision collision) -- I am not really sure what do with this, as it i is just a return true in the demo.

I assume you mean by 'resting contacts' you are referring to rigid bodies resting on the ground plane?

I am also wondering how you manage to achieve the effect of the various shapes in the samples changing colors when the sphere touched them, but yet they are not using ICollisionCallback :-D

Would it be too much of a bother to ask you to give an example on how to use OnCollided(CollisionShape x, CollisionShape y, Collision) ?
Coordinator
Jan 8, 2008 at 8:41 PM
1) You are correct. You can assign anything to the Tag property of the RigidBody.

2) There are two OnCollided methods that must be implemented from the ICollisionCallback interface - CollisionShape vs. CollisionPlane and CollisionShape vs. ColisionShape. In MainMenuScreen.cs, for the CollisionShape vs. CollisionPlane version, every time a collision occurs I change the position, velocity and rotation of the CollisionShape and return false, meaning that I don't want a collision processed. In either method, if you return false, the collision is cancelled. But, you can also use these methods to do other things, such as play a "collision" sound or set some flag on your "entity" class.

In the sample code below, I'm changing an associated entity's color and time it should remain that color based on if a collision occurred with a boulder (I'm conveniently assuming an Entity class exists with the properties needed to demonstrate this):

		#region ICollisionCallback Members
 
		bool ICollisionCallback.OnCollided(CollisionShape shape, CollisionPlane plane, Collision collision)
		{
			// Allow all collisions between shapes and planes.
			return true;
		}
 
		bool ICollisionCallback.OnCollided(CollisionShape x, CollisionShape y, Collision collision)
		{
			// Get the associated entity instances.
			Entity entity1 = x.RigidBody.Tag as Entity;
			Entity entity2 = y.RigidBody.Tag as Entity;
 
			if (entity1 != null && entity2 != null)
			{
				// Determine if a player collided with a boulder.
				if (entity1.EntityType == EntityType.Player && entity2.EntityType == EntityType.Boulder)
				{
					// Change the player's status and color.
					entity1.Status = EntityStatus.Hit;
					entity1.Color = Color.Red;
					entity1.ColorTime = TimeSpan.FromSeconds(0.5f);
 
					// Change the boulder's status.
					entity2.Status = EntityStatus.Kill;
 
					// If the boulder is small, don't let the collision affect the player.
					if (entity2.Size < 5)
					{
						return false;
					}
				}
				else if (entity2.EntityType == EntityType.Player && entity1.EntityType == EntityType.Boulder)
				{
					// Change the player's status and color.
					entity2.Status = EntityStatus.Hit;
					entity2.Color = Color.Red;
					entity2.ColorTime = TimeSpan.FromSeconds(0.5f);
 
					// Change the boulder's status.
					entity1.Status = EntityStatus.Kill;
 
					// If the boulder is small, don't let the collision affect the player.
					if (entity1.Size < 5)
					{
						return false;
					}
				}
			}
			
			// Allow all collisions between shapes.
			return true;
		}
 
		#endregion

Resting contacts are Collisions that are generated to keep two bodies at rest, such as the example you gave - a rigid body resting on a plane. Even if the rigid body is not moving, gravity moves the rigid body into the plane, causing a collision. This is a resting contact. This collision keeps the rigid body and plane apart.

I'm changing colors based on if the Disabled flag is set on the rigid body. All the rigid body's in the example are set to auto disable if the momentum of said rigid body is under a certain threshold. See the end of RigidBody.Integrate. The drawing code is in ExampleScreen.Draw - I'm just changing the light color based on the rigid body's Disable status.