OnCollide and OnSeperation Detection issue

Topics: User Forum
Mar 3, 2010 at 12:16 AM

I am having a collision detection issue. I am designing a Jupiter Lander type of game. I have decided to use Farseer to implement the physics for it. It is being developed in C# on the XNA Framework. I am a hobbiest programmer so my technical skill is modest. Please excuse any Kludge code, and I would appreciate it if you see a Kludge call me on it, in a constructive manner.

The way my lander is setup is with 3 physics Bodies, and 3 physics Geoms that are connected by 3 pin joints that connect each body to one another. It forms a triangle. With the larger body being the fuselage, and the 2 same size smaller bodies being thrusters.

I am tring to detect when my Lander has landed on a Landing pad. The pad is just a basic rectangle Geom. I use the events OnCollision and OnSeperation to set a vairables for the Left and Right Thrusters ( this._isCollided[index] ). Then I query a Property that returns true when Left and Right Thrusters varible isCollied[index] are true and the Lander Y Velocity is 0.

This works fine when  there are no terrain objects around the landing pad. I found that if a terrain object has a cresent shape ( concave ) and any part of the terrain overhangs or underhangs the landing pad the OnSeperation Event will fire, even though my lander is in contact with the Landing Pad. The Terrain has Geom created by the GeomFactory using a list of Vertices. I have discovered that the Broad Phase bounding box and the thruster bound box cause a Collision event fire, since they are not actually touching a Seperation Event Fires. The code for the seperation even would set the isCollide for that thruster to false. (the IsLanded Property is suppose to be oblivious to the object that it is landing on.)

I have solved the issue but I feel like it is not the proper or most effiecent way to solve the issue. I was wondering if anyone can help me with this or tell me if I have the best solution. I use a Linklist to push all Collision Geoms through the OnCollide Event into for the individual thrusters. Then OnSeperation check 2nd Geoms to see if linklist contains that geom. if it does it removes that Geom from the list. Now I check to see if the list contains any geoms if it does it has to be landed. Here is the code.

 

public enum Lunar
        {
            FUSELAGE = 0,
            L_THRUSTER = 1,
            R_THRUSTER = 2
        };


Fields used in Class:
      
private bool[] _isCollided;
private Body[] _bodyObjects;
private Geom[] _geomObjects;
private PinJoint[] _jointObjects;
public LinkedList<Geom>[] _collisions;

Constructor setup code:


_isCollided = new bool[3];
_isCollided[0] = false;
_isCollided[1] = false;
_isCollided[2] = false;

_geomObjects[(int)Lunar.FUSELAGE].OnSeparation += OnFSeperation;
_geomObjects[(int)Lunar.L_THRUSTER].OnSeparation += OnLTSeperation;
_geomObjects[(int)Lunar.R_THRUSTER].OnSeparation += OnRTSeperation;

_geomObjects[(int)Lunar.FUSELAGE].OnCollision += OnFCollision;
_geomObjects[(int)Lunar.L_THRUSTER].OnCollision += OnLTCollision;
_geomObjects[(int)Lunar.R_THRUSTER].OnCollision += OnRTCollision;

_collisions[(int)Lunar.FUSELAGE] = new LinkedList();
_collisions[(int)Lunar.L_THRUSTER] = new LinkedList();
_collisions[(int)Lunar.R_THRUSTER] = new LinkedList();

Properties Used in Code:

public bool isLanded
        {
            get
            {
                return RT_Collide && LT_Collide && (int)_bodyObjects[(int)Lunar.FUSELAGE].LinearVelocity.Y == 0;
            }
        }

public bool F_Collide
        {
            get { return _isCollided[(int)Lunar.FUSELAGE]; }
        }

public bool LT_Collide
        {
            get { return _isCollided[(int)Lunar.L_THRUSTER]; }
        }

public bool RT_Collide
        {
            get { return _isCollided[(int)Lunar.R_THRUSTER]; }
        }


Methods Used in Code:

( the other two OnCollision methods are the same except for index on arrays )
private bool OnLTCollision(Geom geometry1, Geom geometry2, ContactList contactList)
        {
            _isCollided[(int)Lunar.L_THRUSTER] = true;
            int yVelocity = Math.Abs((int)_bodyObjects[(int)Lunar.L_THRUSTER].LinearVelocity.Y);
            int xVelocity = Math.Abs((int)_bodyObjects[(int)Lunar.L_THRUSTER].LinearVelocity.X);
            
            // Only add the Geometery to the list if it is not already in the list.
            if (!_collisions[(int)Lunar.L_THRUSTER].Contains(geometry2))
            {
                _collisions[(int)Lunar.L_THRUSTER].AddLast(geometry2);
            }

            if (yVelocity > 200)
            {
                currentHealth -= yVelocity - 200;
            }
            if (xVelocity > 200)
            {
                currentHealth -= xVelocity - 200;
            }
            if (yVelocity > 400)
            {
                currentHealth = -1;
            }
            if (xVelocity > 400)
            {
                currentHealth = -1;
            }
            return true;
        }


( the other two OnSeperation methods are the same except for index on arrays )
private void OnLTSeperation(Geom geometry1, Geom geometry2)
        {
            if (_collisions[(int)Lunar.L_THRUSTER].Contains(geometry2))
            {
                _collisions[(int)Lunar.L_THRUSTER].Remove(geometry2);
            }

            if (_collisions[(int)Lunar.L_THRUSTER].Count <= 0)
            {
                _isCollided[(int)Lunar.L_THRUSTER] = false;
            }
        }

Mar 3, 2010 at 12:46 AM

I thought I should add:

I am using Farseer 2.1.3

I did not change any of the default setting in the simulator.

I have a gravity vector of ( 0.0f, 200.0f )

I have not changed any of the Distance Grid Settings, and I am not using SAT.