Farseer 3.3.1 Collision Handler Problem

Jul 18, 2011 at 12:39 AM

Every time I enable the OnCollision event I can move a little and then the character gets stuck. When I'm not using the OnCollision this doesn't happen.


Link to a pic of the frozen character.



public enum PlayerState

    public class Player

        private float PlayerWidth = 64f;//64pix
        private float PlayerHeight = 64f;//64pix

        private Vector2 _position;
        private float _playerWidth;
        private float _playerHeight;
        private float _bodyHeight;

        private Body _playerBody;
        private Fixture _playerFixture;

        private Body _playerWheel;
        private CircleShape _playerCir;

        private RevoluteJoint _motorJoint;
        private FixedAngleJoint _fixedAngleJoint;
        private bool _isOnGround;
        private bool isJump;
        private Fixture _playerFix;
        private Fixture _playerWheelFix;

        private int _ticks;
        private int _ticksCollision;

        public Player(World world, Vector2 position)
            _position = ConvertUnits.ToSimUnits(position);
            _playerWidth = ConvertUnits.ToSimUnits(PlayerWidth);
            _playerHeight = ConvertUnits.ToSimUnits(PlayerHeight);
            _bodyHeight = _playerHeight - (_playerWidth / 2);

            _playerBody = BodyFactory.CreateBody(world);//.CreateRectangle(world, _playerWidth/3, _playerHeight, 1f);
            //_playerBody.BodyType = BodyType.Dynamic;
            //_playerBody.Restitution = 0.0f;
            //_playerBody.Friction = 0.0f;
            //_playerBody.Position = _position;// -Vector2.UnitY * (_playerWidth / 4);
            //_playerBody.Awake = true;
            _playerFix = FixtureFactory.AttachRectangle(_playerWidth/3, _playerHeight, 1f, new Vector2(0,0),_playerBody);
            _playerFix.Body.BodyType = BodyType.Dynamic;
            _playerFix.Body.Restitution = 0f;
            _playerFix.Body.Friction = 0f;
            _playerFix.Body.Position = _position;
            _playerFix.CollidesWith = Category.All & ~Category.Cat2;
            _playerFix.Body.BodyType = BodyType.Dynamic;

            _playerWheel = BodyFactory.CreateBody(world); //CreateCircle(world, _playerWidth/6, 1f);
            /*_playerWheel.BodyType = BodyType.Dynamic;
            _playerCir = new CircleShape(_playerWidth / 6, 1);
            _playerWheel.Restitution = 0.0f;
            _playerWheel.Friction = float.MaxValue;
            _playerWheel.Position = _playerBody.Position+Vector2.UnitY*(_playerHeight/2);// +Vector2.UnitY * (_playerHeight / 2);
	    // new Vector2(_position.X, _position.Y - _playerBody.Position.Y);
            _playerWheel.Awake = true;*/
            //_playerWheelFix = _playerWheel.CreateFixture(_playerCir);
            _playerWheelFix = FixtureFactory.AttachCircle(_playerWidth / 6, 1f, _playerWheel);
            _playerWheelFix.Body.BodyType = BodyType.Dynamic;
            _playerWheelFix.Body.Restitution = 0f;
            _playerWheelFix.Body.Friction = float.MaxValue;
            _playerWheelFix.Body.Position = _playerFix.Body.Position + Vector2.UnitY * (_playerHeight / 2);
            _playerWheelFix.CollisionCategories = Category.Cat2;
            _playerWheelFix.CollidesWith = Category.All & ~Category.Cat1;

            _motorJoint = JointFactory.CreateRevoluteJoint(world, _playerFix.Body, _playerWheelFix.Body, Vector2.Zero);
            _motorJoint.MotorEnabled = true;
            _motorJoint.MaxMotorTorque = 1500f;
            _motorJoint.MotorSpeed = 0f;

            _fixedAngleJoint =JointFactory.CreateFixedAngleJoint(world, _playerFix.Body);
            isJump = false;
            _playerWheelFix.OnCollision +=new OnCollisionEventHandler(playerWheelOnCollision);
            _playerWheelFix.OnSeparation += new OnSeparationEventHandler(playerWheelOnSeparation);
            _isOnGround = true;


        public PlayerState State

        public Body PlayerBody
            get { return _playerFix.Body; }

        public Vector2 PlayerPosition
            get { return _playerFix.Body.Position; }

        public Vector2 WheelPosition
            get { return _playerWheelFix.Body.Position; }

        public float PlayerRotation
            get { return _playerBody.Rotation; }

        public float WheelRotation
            get { return _playerWheel.Rotation; }

        public float MotorSpeedP
            get { return _motorJoint.MotorSpeed; }
            set { _motorJoint.MotorSpeed = value; }

        public bool MotorEnabled
            get { return _motorJoint.MotorEnabled; }
            set { _motorJoint.MotorEnabled = value; }

        public bool IsOnGround
            get { return _isOnGround; }
            set { _isOnGround = value; }
        private bool playerWheelOnCollision( Fixture fix1,Fixture fix2, Contact contact)
            _isOnGround = true;
            return true;

        private void playerWheelOnSeparation(Fixture fix1, Fixture fix2)

            _isOnGround = false;

        public void ApplyImpulse( Vector2 impulse, float angular)
            //_playerWheelFix.Body.ApplyLinearImpulse(ref impulse);
            _playerFix.Body.ApplyLinearImpulse(ref impulse);

        public void ApplyForce(ref Vector2 force)
            _playerWheelFix.Body.ApplyForce(ref force);
        public bool IsJump
            get { return isJump; }
            set { isJump = value; }

        public bool IsRun


Jul 19, 2011 at 2:59 PM

At a guess, you're only able to move when you're on the ground. This doesn't really work because as soon as you move against the ground you seperate from it, but only slightly. This means you'll stop moving, then move, then stop moving... It's also possible that if your map is tile based, as you pass over from one tile to another you stop colliding with the previous tile, meaning that you wont be on the ground any more according to your logic.

One way to get around this is decide that when you collide with the ground you are on the ground (as you already have). And you're NOT on the ground if your vertical velocity is greater than a certain point. This means if your character falls or is thrown he wont be on ground. You'll also need to make sure he's not on the ground when he jumps too, as what I just said will mean he can continually jump until he reaches some speed, which in my experience can be problematic.


Hope this helps.

Jul 19, 2011 at 4:39 PM

I seen what you're saying. I will try to fix it so that it has to be a certain y height to be jumping or maybe use rays. Maybe I can put a few rays and as long as one of the rays is touching a floor the character is on the ground?

Thanks for the help.

Jul 19, 2011 at 6:01 PM

The alternative is to count how many contacts the wheel makes. I'm using it for an automatic door just now. So when something collides with the sensor it increments a 'touched' variable and opens the door. When something leaves I decrease that value, if that value is 0, I close the door, if it's not, it means that there's still something near the sensor.

So in terms of what you're doing, as long as your touched variable is greater than 0, you're on the ground (or at least your wheel is touching something).

You'll probably find using rays is a better idea in the long run because your wheel will also be on the ground when it bumps into a wall.