Farseer 3.3.1 Collision Handler Problem

Jul 18, 2011 at 1: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
    {
        OnGround,
        InAir
    };

    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.CollisionCategories=Category.Cat1;
            _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);
            //_playerWheelFix.IgnoreCollisionWith(_playerFix);
            _isOnGround = true;

            
                    
        }

        
        public PlayerState State
        {
            get;
            set;
        }


        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);
            //_playerWheel.ApplyAngularImpulse(angular);
        }

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

        public bool IsRun
        {
            get;
            set;
        }


    }

Jul 19, 2011 at 3: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 5: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 7: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.