Game Development Community

Inconsistent OnCollision() Behavior

by Michael Smith · in Torque 2D Beginner · 06/27/2013 (7:25 pm) · 3 replies

The order of the first two parameters of %collisionDetails returned by the OnCollision(%sceneObject, %collisionDetails) callback for scene objects is inconsistent. There is no way to be sure whether the shape index in the first position is for the sceneObject receiving the call or for the other object. The order is different in different collisions. It appears that circular collision shapes and polygon collision shapes tend to have opposite order.

The physics manual specifies the order consistently for Scene's onCollision callback, as follows:

Quote:The format is as a space separated list containing the following items in the specified order:

Collision Shape Index A
Collision Shape Index B
Collision Normal
Contact World Point #1
Collision Normal Impulse #1
Collision Tangent Impulse #1
Contact World Point #2 (Only if two contacts)
Collision Normal Impulse #2 (Only if two contacts)
Collision Tangent Impulse #2 (Only if two contacts)

Apparently when the program pulls out the data to send to the individual scene objects involved it does not make sure to reorder the indexes based on whether the callback is being called for Shape A or Shape B.

Does anyone have a workaround for this?

About the author

Bible translator by day-- game programmer by night


#1
06/27/2013 (8:43 pm)
I modified the collision callback function in scene.cc to fix the index order problem. It re-formats the collision details so that the first index is always for the object whose callback is being activated. The changes start at about line 575.

What this modified function fails to do is flip around the normal vector so that it points in the right direction relative to the object. That is important to do, too, for full consistency, but I was not sure quite how to do it.

void Scene::dispatchBeginContactCallbacks( void )
{
...

        // Is object B allowed to collide with object A?
        if (    (pSceneObjectB->mCollisionGroupMask & pSceneObjectA->mSceneGroupMask) != 0 &&
                (pSceneObjectB->mCollisionLayerMask & pSceneObjectA->mSceneLayerMask) != 0 )
        {
			// Reformat miscellaneous information for object B
			char miscInfoBufferB[128];
			if ( pointCount == 2 )
			{
				dSprintf(miscInfoBufferB, sizeof(miscInfoBufferB),
					"%d %d %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f",
					shapeIndexB, shapeIndexA,
					normal.x, normal.y,
					point1.x, point1.y,
					normalImpulse1,
					tangentImpulse1,
					point2.x, point2.y,
					normalImpulse2,
					tangentImpulse2 );
			}
			else if ( pointCount == 1 )
			{
				dSprintf(miscInfoBufferB, sizeof(miscInfoBufferB),
					"%d %d %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f",
					shapeIndexB, shapeIndexA,
					normal.x, normal.y,
					point1.x, point1.y,
					normalImpulse1,
					tangentImpulse1 );
			}
			else
			{
				dSprintf(miscInfoBufferB, sizeof(miscInfoBufferB),
					"%d %d",
					shapeIndexB, shapeIndexA );
			}

            // Yes, so does it handle the collision callback?
            if ( pSceneObjectB->isMethod("onCollision") )            
            {
                // Yes, so perform the script callback on it.
                Con::executef( pSceneObjectB, 3, "onCollision",
                    sceneObjectABuffer,
                    miscInfoBufferB );
            }
            else
            {
                // No, so call it on its behaviors.
                const char* args[4] = { "onCollision", "", sceneObjectABuffer, miscInfoBufferB };
                pSceneObjectB->callOnBehaviors( 4, args );
            }
        }
    }
}
#2
06/27/2013 (9:04 pm)
And of course Scene::dispatchEndContactCallbacks( void ) needs the analogous change as well.

// Is object B allowed to collide with object A?
        if (    (pSceneObjectB->mCollisionGroupMask & pSceneObjectA->mSceneGroupMask) != 0 &&
                (pSceneObjectB->mCollisionLayerMask & pSceneObjectA->mSceneLayerMask) != 0 )
        {
			// Re-format miscellaneous information.
			char miscInfoBufferB[32];
			dSprintf(miscInfoBufferB, sizeof(miscInfoBufferB), "%d %d", shapeIndexB, shapeIndexA );
            // Yes, so does it handle the collision callback?
            if ( pSceneObjectB->isMethod("onEndCollision") )            
            {
                // Yes, so perform the script callback on it.
                Con::executef( pSceneObjectB, 3, "onEndCollision",
                    sceneObjectABuffer,
                    miscInfoBufferB );
            }
            else
            {
                // No, so call it on its behaviors.
                const char* args[4] = { "onEndCollision", "", sceneObjectABuffer, miscInfoBufferB };
                pSceneObjectB->callOnBehaviors( 4, args );
            }
        }
#3
06/27/2013 (10:41 pm)
I like!

Have you considered submitting your code change as a pull request so that we may test and possibly integrate it in the official repo?