Checking when body is NOT colliding

Aug 24, 2008 at 7:35 PM
Hi

Question is dumb, but I can't find answer, so... I need to check when particular body is not colliding with anything. I have code similiar to this:
        public bool onCollide(Geom g1, Geom g2, ContactList contactList)
        {
           player.isColliding = true; //variable used in other functions
           return true;
        }

What I have to do is to set isColliding to false when collision ends. I tried to set isColliding=false in Update() function but that messes up collisions. How can I do it?
Developer
Aug 25, 2008 at 8:25 AM
Edited Aug 25, 2008 at 8:30 AM
If you want to find out which of your players are colliding then put a reference into the tag of the geom.

_playerGeom.Tag = player;

Then you'll know which players are colliding in OnCollide.

public bool onCollide(Geom g1, Geom g2, ContactList contactList)
{
           YourPlayerClass player1 = (YourPlayerClass)g1.Tag;
           YourPlayerClass player2 = (YourPlayerClass)g2.Tag;

           //Your collision logic here.

           return true;
}

This is very simple here to make it as easy understandable as possible. You'll - of course - have to check if the Tag isn't Null or what ever else.
Aug 25, 2008 at 11:34 AM
Maybe I explained wrong. I know how to check when something is colliding, but I need to check when body is NOT colliding with anything, for example flying in the air.
Aug 26, 2008 at 12:19 AM
Edited Aug 26, 2008 at 12:20 AM
make the same construct he mentioned named nonCollide and return false???
Sep 28, 2008 at 10:55 PM
I am also interested to know if there's a way to check if Geom is colliding with nothing.
Coordinator
Sep 28, 2008 at 11:19 PM
hmm, I'm not 100% what is needed here.

I see 2 solutions:

1. Use the Collide event and save the state of the collision in a field (Collides/Collision/IsColliding).

2. This one makes use of the arbiterlist. And this does not need hundreds of event subscriptions. I think this is what you are looking for.

The PhysicsSimulator.ArbiterList contains a list of all the geom pairs that collides. So if 2 geoms collide, an Arbiter would be constructed and put into the list with a reference to the 2 geoms. As soon as the Geom no longer are colliding, the Arbiter is removed from the list.


 

if (PhysicsSimulator.ArbiterList.Count == 0)
collision =
false;
else
{
foreach (Arbiter arbiter in PhysicsSimulator.ArbiterList)
{
if (arbiter.GeometryA == _circleGeom || arbiter.GeometryB == _circleGeom)
{
collision =
true;
}
else
{
collision =
false;
}}}

 

Sep 28, 2008 at 11:41 PM
Edited Sep 29, 2008 at 6:55 PM
@genbox I'll give that a shot, it sounds promising!

EDIT:
@genbox
Grrr...
It's not working.

public

 

bool testLocation(Geom heldGeom, PhysicsSimulator ps)

 

{

 

Geom tempGeom = GeomFactory.Instance.CreateGeom(ps, barrierBody, heldGeom);

 

 

//Geom tempGeom2 = GeomFactory.Instance.CreateGeom(ps, barrierBody, heldGeom);

 

barrierAnimation.CurrentFrameIndex = 3;

setPosition(heldGeom.Position);

 

/*

 

tempGeom.CollidesWith = Enums.CollisionCategories.None;

tempGeom.Collision += new Geom.CollisionEventHandler(testCollision);

 

return isOkay;*/

 

 

bool isClear = true;

 

 

if (ps.ArbiterList.Count == 0)

 

 

return isClear;

 

 

else

 

 

foreach (Arbiter arbiter in ps.ArbiterList)

 

{

 

Console.WriteLine("Testing" + 9);

 

 

if (arbiter.GeomA == tempGeom || arbiter.GeomB == tempGeom)

 

{

 

Console.WriteLine("Why not?");

 

play();

isClear =

false;

 

}

}

tempGeom.Dispose();

 

return isClear;

 

 

}

------------------------------------------------

The commented out code is how I was doing it, and testGeom was picking up Collisions there, so I believe there must be something wrong with the arbiter method you proposed.

Any ideas?

Coordinator
Sep 29, 2008 at 9:58 AM
I changed the Demo2 sample from Farseer to use this. It seems to work fine.

When there is no collision, it will display a circle in the upper left corner like this
But when there is a collision, it will remove the cirle, like this

The extension to the physics simulator view (body count and so on) is from Farseer 2.0. Notice how an Arbiter is created when the 2 geoms collide and the contact of the Geom's is highlighed red.
Sep 29, 2008 at 7:07 PM
@genbox

Nah, I figured out my code works, but only on objects that have been sitting on something previously.

In my code up there, I create the Geom to test for immediately before I test for it.
When I use the same code to test a Geom that has existed for a little while, and is resting on an object, it works fine.

It is important that the geom I test for does not alter the playing field, and that's why I create a new Geom that I dispose of immediately after I use it.

Some sort of sensor would work well. Is there anything like that in the current FarSeer?
Coordinator
Sep 29, 2008 at 7:55 PM
Yes there is.

As i mentioned here you just need to set CollisionResponseEnabled to false and IsStatic to true to use a geom as sensor :)
Sep 30, 2008 at 3:08 AM
@genbox$0$0$0$0I noticed that before, I forgot where. Sorry, but hey now! it works!$0$0It doesn't sense static bodies though.$0
Coordinator
Sep 30, 2008 at 5:23 PM
Since a sensor and a static bodies does not move, they will not be checked for collisions. So a sensor should not detect other static bodies.
Nov 21, 2008 at 2:12 PM
Edited Nov 21, 2008 at 2:13 PM
sorry to drag up an old topic, but I'm running into a similar situation. I want to play a sound on each unique collision with an object, but I have the same problem of the collision event firing thousands of times for the same collision...I've improved the code that genbox posted, and that made things better, but it still needs work. Oranjoose, did you ever find a solution?

code:

public

 

bool OnCollide(Geom g1, Geom g2, ContactList contactList)
{
    if (!collide && !collidingWith.Contains(g2))
    {
       
SoundManager.PlaySound("ship_crash");
        collide =
true;
        collidingWith.Add(g2);
    }
    return true;
}

and then in the Update:

 

collide =

false;
Geom[] colTemp = new Geom[collidingWith.Count];
collidingWith.CopyTo(colTemp);
collidingWith.Clear();
foreach (Arbiter arbiter in physicsSim.ArbiterList)
{
    if (arbiter.GeomA == this.shipGeom)
    {
        if (colTemp.Contains(arbiter.GeomB))
       {
            collide =
true;
            collidingWith.Add(arbiter.GeomB);
        }
    }
}

So it should only play the sound if I experience a collision with a new object...but apparently there's times when the collision is removed from the arbiterlist even though the two objects are still colliding...any thouhgts?

 

 

 

 

 

Coordinator
Nov 21, 2008 at 4:04 PM
There are no collision if there are no arbiters. They are the ones calculating impulses and firing the OnCollision event. If this not the case, geometries would fly into each other.

Could you confirm that there are missing arbiters? I've seen another thread about more tunneling, there could be a bug introduced in 2.0.

Oh, and arbiters are created all the time. Even if it's the same 2 geometries. That may be why you are firing the sound 1000 times.
Nov 21, 2008 at 5:05 PM
Edited Nov 21, 2008 at 5:08 PM
yeah, I expected that the arbiters are being created and updated all the time, the problem I seem to be seeing is that I'll find an arbiter which shows a collision between two objects, lets say p1ship and landa, now what I do is every update loop I check to see if there is an arbiter with these two objects colliding, if not, then I allow it to play the sound again the next time those two objects collide, if the arbiter is there, then I don't allow the sound to play. It should work, but apparently sometimes the arbiter is getting destroyed for 1 or 2 frames and then re-added even though the collision was still existant...it's odd...

I'm going to try and make some changes to the way I do the checks, and add checking for if the arbiter is reversed (with p1ship being object b and landa being object a)...maybe that will fix it... I'll let you know how it goes...

The sound isn't firing 1000 times, it's just firing about ever 3 seconds during a constant collision. it should fire once for that collision and not fire again until the objects are completely seperated and then re-collide...something is odd there.

Oh and for the tunnelling, I was seeing a lot of tunnelling as well until I cranked up the number of verts on my objects...seems that the vert points collide fine, but the vert lines don't...so I assumed it was just a downside of using a vertice insted of one of the predefined shapes...
Nov 22, 2008 at 4:26 PM
checking for the reverse of the arbiter worked...that fixed all my problems. Apparently sometimes when it came through the collision loop it was being reported one way, then the next time through it was changed and the collision order was reversed. All fixed now...Thanks Genbox