Platformer almost working / box collision help

Topics: Developer Forum, User Forum
May 19, 2011 at 10:09 PM
Edited May 19, 2011 at 10:13 PM

I am new to farseer and need a little help figuring out how to workout the last issue with my platformer code. I am keeping things as simple as possible so I am sticking with fixed rotation rectangles. Even the player is a fixed rotation rectangle.

The test game I'm making is a Bubble Bobble Clone. I am building it because I specifically want to get working the platformer aspects of it.Player movement and jumping through platforms.

Everything is almost working as is. It can detect weather or not the player can jump, and the player can stand underneath a platform and jump up through it to stand on it.

I have ran into two small problems that I have not been able to work out yet and I think they may be inter related.

A running preview is availible here http://www.createdbyx.com/page/Bubble-bobble-clone-not-working.aspx. The red dots you see appearing are the contact points passed via the OnCollision event so I can see where the collision points are actually registering at.

Here is my actor code ... 

    public class Actor : Zider.BaseActor, CBX.Xna.Input.IObjectBinder
    {
        private float direction;
        private bool doJump;
        private bool canJump;
        private Body body;
        private bool isMovingRight;
        private bool isMovingLeft;
        private ZiderFarseerLib.SimulatorComponent simulator;
        private FrameworkElement element;
        float velocityHoriz;
        private bool canMove = true;
        private ContactVisualizer contactVisualizer;


        public Actor()
        {
            this.contactVisualizer = new ContactVisualizer();
            this.contactVisualizer.RemoveOnSeparation = false;
        }

        public ZiderFarseerLib.SimulatorComponent Simulator
        {
            get
            {
                if (this.simulator == null) this.simulator = this.GetProperty<ZiderFarseerLib.SimulatorComponent>("simulator");
                return this.simulator;
            }
            set
            {
                this.SetProperty("simulator", value);
                this.simulator = value;
            }
        }

        public FrameworkElement Element
        {
            get
            {
                if (this.element == null) this.element = this.GetProperty<FrameworkElement>("Element");
                return this.element;
            }
            set
            {
                base.SetProperty("Element", value);
                this.element = value;
                if (this.body != null)
                {
                    this.body.OnCollision -= this.body_OnCollision;
                    this.body.OnSeparation -= this.body_OnSeparation;
                    this.body = null;
                }

                this.body = value.Tag as Body;
                this.contactVisualizer.Body = this.body;
                this.contactVisualizer.Simulator = this.Simulator;
                this.contactVisualizer.Parent = value.Parent as Canvas;

                if (value != null)
                {
                    this.body.OnCollision += this.body_OnCollision;
                    this.body.OnSeparation += this.body_OnSeparation;
                }        
            }
        }

        void body_OnSeparation(Fixture fixtureA, Fixture fixtureB)
        {
            this.canJump = false;
        }

        bool body_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
        {
            // get manifold data
            Vector2 norm;
            FixedArray2<Vector2> pts;
            contact.GetWorldManifold(out norm, out pts);

            // if normal is facing up and vertical velocity is downward we can jump
            this.canJump = norm.Y < 0 && this.body.LinearVelocity.Y >= 0;

            // determine a wall collision to drop horizontal velocity 
            // if I can't jump and the normal is not the same direction as the
            // direction player is moving towards then player cant move (IE: wall collision)
           // this.canMove = !(this.direction != norm.X);  // (not working need better solution)

            // allow jumping through a platform from the bottom
            if (body.LinearVelocity.Y < 0 && norm.Y > 0)    return false;

            return true;
        }

        public void HandleAction(object sender, CBX.Xna.Input.ActionArgs e)
        {
            // var value = e.NormalizedValue() * 0.05f;
            var value = e.NormalizedValue();
            if (e.Name == "moveleft") this.isMovingLeft = value != 0;
            if (e.Name == "moveright") this.isMovingRight = value != 0;
            this.direction = (this.isMovingRight ? 1 : 0) + (this.isMovingLeft ? -1 : 0);

            if (e.Name == "jump" && this.canJump) body.ApplyLinearImpulse(new Vector2(0, -0.225f), body.Position);
        }

        public override void Update(GameTime gameTime)
        {
            var forcePower = 0.15f;
            velocityHoriz = (float)((this.direction * forcePower) * gameTime.ElapsedGameTime.TotalMilliseconds);
            body.LinearVelocity = new Vector2(this.canMove ? velocityHoriz : 0, body.LinearVelocity.Y);
        }
    }

The first problem I have involves the this.canMove boolean. I need to set this to false if I detect that the player is moving into a wall. I need to do this because if I dont then the player will stick to the wall like glue because force from the players linear velovity is holding the player against the wall.

When this.canMove is set to true the players linear velocity is allowed to be applied.

The second problem I am seeing is that if u position th player straddling the edge of a platform. Standing half on half off then jump streight up to the next heigher platform collision detection kicks in and pushes the player off to the side rather then letting the player jump up though the platform.

So my question is am I moving in the right direction using the manifold contact points to determine if I can jump up through a platform etc? And second question how can I acuratley determine if the player is colliding with a wall, but still allow the player to jump up through a playform and then stand on it.

Jun 6, 2011 at 11:32 PM

I'm kind of a newb too but to solve the wall sticking problem just try and turn off friction if the character is colliding with the wall? Try setting the player's coeifficient of friction to 0 while its contact with a wall or something.

Jumping through the platform is tricky. You could try having it just disable gravity when ever your in contact with a platform, and at least the height of the platform its in contact with. Or actually in the OnCollision event of the platform set it to return false normally, but when the contacting fixture is the player (or enemy) and the player/enemy's position is hire than the platform it returns true? Not sure try these things out.

Aug 27, 2011 at 8:06 PM

There is a sample for a one sided platform in the Farseer Testbed  samples give it a try .Also i'm just thinking here but you could do some stuff with ray casting and collision categories.Say ray cast and if theres anything on top the guy when he's jumping shuffle the categories around so he wouldn't collide with the thing over him and ray cast down and if theres something below him shuffle the categories so he would collide with the bodies that are below him .

Also just thinking aloud here you should go and check the one sided platform sample in the testbed thought good luck.