Game Development Community

Trigger receiving collisions

by And Yet It Moves · in Torque Game Builder · 07/09/2008 (12:19 pm) · 10 replies

Hi,

triggers which receive collisions dont really work together with the contact resolver which is currently implemented in tgb. try this situation: player object with sending collision and sending physics is standing on ground which is receiving collisions. if the player also touches a trigger which receives collision, player will start falling through the ground.

i guess this is cause of how a sending colliders try to solve contacts with receiving colliders in t2dSceneObject::checkCollisionSend. per tick it only solves one collision, even if there are more than one collisions. which collision is resolved is somehow determined by how far the sender is already penetrating the receiver.

so in the case above if player is standing in a trigger it always chooses the trigger to resolve contact. Only when its farer inside the ground than inside the trigger, it will resolve the contact with ground.

as its never neccessary to try to resolve a contact with a trigger, these objects shouldnt be considered at all in there. i tried to hack this to get them out but it somehow messes up the whole contact resolver...

could you give me a hint how to get this working? as we have learned from melvs nice in depth explanations of the collision system its good to avoid unneccessary collision senders, and as we are struggling with performance issues switching all our triggers from send to receive would help alot.

thanks!

#1
07/09/2008 (4:45 pm)
Maybe you didn't used
player.setCollisionMaxIterations(3); // or more than 3 if really needed

?
#2
07/10/2008 (12:20 am)
Yes player has set max iterations to 3 (more isnt possible cause its cut to 3 in the engine), but this doesnt change anything.
the problem seems to be that of 2 occuring collisions (1 with ground and 1 with trigger) during one tick, the trigger is returned in t2dSceneObject::checkCollisionSend for resolving the contact. and with maxIterations set to 3 the trigger is returned 3 times during one tick, because collision with the trigger isnt physically resolved (player still overlaps the trigger after collision as there is no physical interaction).

so as the criteria (which one of multiple simultaneously occuring collisions is returned for resolving) is how much the sender overlaps the receiver, checkCollisionSend will return the trigger as long as the player overlaps the trigger more than the ground. and this is exactly how it looks like.

could you try this out (its really quick to set up) or should i put together an example scene for this?
#3
10/12/2008 (11:08 am)
Has this been resolved yet? I am currently working on an isometric RPG, and if my characters are in a Trigger, they can walk right through each other. I can put any kind of collision within the trigger and the players walk right through it. This is probably part of the problem with Adventure Kits Collision in the Tent, which is similar functionally to what I am trying to do.

I am looking for a fix or alternatives because I need this functionality.
#4
10/13/2008 (2:49 am)
Yes i resolved it, you have to make some changes in the source as triggers are not intended to be used as receive-only objects. if you want i can put together the neccessary changes (if i still can spot them all :))

peter
#5
10/13/2008 (3:02 am)
OK, that explains it. Yeah, if you get some time I would love to see how you did it. Luckily, I did find a way to solve the overall problem yesterday with a second collision set and Graph Group.

Thanks
#6
10/13/2008 (4:20 am)
I just remembered that i didnt really resolve it too, but did some hacks to use them as receiving only objects.
still its isnt possible to have the situation described above: having an object, which is sending physics and sending on a trigger, collide with an object with which it should physically interact AND a trigger at the same time. i just mounted another object to the first one. this mounted one doesnt send physics, and it does the sending on the triggers.
still there were some things to change in the source:

in t2dTrigger::onAdd() i commented out this line:
setCollisionActive(true, true);
cause its a little bit annoying if you try to make them receive only and its overwritten to send&receive...

the other thing is a bug in t2dPhysics::sweptCircleToPolyCollision resp. sweptPolyToCircleCollision: if a circle is completely inside a polygon, there will be no collision detected. so if your sending object has collision detection to FULL or CIRCLE, there will be a leave callback as soon as this object is completely inside.
a little dirty hack to resolve this:

add a variable here:
bool t2dPhysics::polygonCircleIntersect( const t2dVector& spaceXForm, const t2dVector* pVertices, const U32 numVertices, const t2dVector& center, const F32 radiusSqr, cCollisionStatus* pCollisionStatus, bool &isInside ) //AYIM: added isInside
{
and add this after polygonContained is calculated:
isInside = polygonContained; //AYIM

now add this in t2dPhysics::sweptPolyToCircleCollision
bool isInside; //AYIM
// Test if circle intersects at time-zero.
if ( polygonCircleIntersect( srcPosition, srcPolyXFormed, srcPolyCount, dstPosition, dstRadii*dstRadii, pCollisionStatus, isInside ) ) //AYIM: added isIndide
{

and before the function ends and returns false (which means there was no collision) add this:
//AYIM: well do another collision check for triggers to be able to detect if the polygon covers the circle completely
    if (isInside)
    {
          U32 i = 0;
          for ( const t2dVector *vertex = srcPolyXFormed; i < srcPolyCount; vertex++, i++ )
          {
             F32 dist = (dstPhysics.getPosition() - *vertex).len();
             if (dist < dstRadii)
                return false;
          }
          return true;
    }

now do the same in t2dPhysics::sweptPolyToCircleCollision, except the distance check looks like this:
//AYIM: well do another collision check for triggers to be able to detect if the polygon covers the circle completely
    if (isInside)
    {
          U32 i = 0;
          for ( const t2dVector *vertex = dstPolyXFormed; i < dstPolyCount; vertex++, i++ )
          {
             F32 dist = (srcPhysics.getPosition() - *vertex).len();
             if (dist < srcRadii)
                return false;
          }
          return true;
    }

hope this helps!
peter
#7
10/13/2008 (1:49 pm)
This does help a lot. It also should optimize things by getting rid of an unnecessary send. Great resource!

Thanks
#8
10/14/2008 (12:37 am)
Besides helping with performance it also makes the triggers work reliable:
a sending trigger can only interact with one object at the same time correctly. if one object is inside and another object enters, there will be wrong leave callbacks etc, according to which object overlaps more with the trigger.

this has the same reason as discribed above: collision detection is strongly linked to resolving the collision, as a collision with multiple objects is only detected correctly if its also resolved at the same time.

this does only apply for sending objects which actively search for collisions, a receiving object as the passive one can have unresolved collisions with multiple sending objects.

peter
#9
10/14/2008 (12:45 pm)
Now you've really got me excited. I should have time to put this together tomorrow evening. This should really be brought up with Melv to see if this can get fixed for the Non-Pro guys out there beating their heads against the wall. :)
#10
10/15/2008 (1:50 pm)
This is great! I got it up and running, and my total collisions are no longer taking big hits from triggers. Thanks for the help!