Object automatically sliding against surface

Topics: Developer Forum, User Forum
Mar 14, 2010 at 7:15 AM
Edited Mar 14, 2010 at 7:22 AM

Hi all,

First off, thanks for bringing out and maintaining such a great little physics engine - its a real boon to people who aren't very savvy with complex Math/Physics like myself :P

Ok, now down to my problem: I'm using Farseer alongwith the FlatRedBall XNA Game Engine to build a simple 2D physics-based game. The player gets to control a bowling
ball and navigate through physics-based levels.

I'm creating classes for each game object to make it easier to setup levels later on. So far, I've got a class for a ball and a crate object. I decided to test them out, and that's
when I noticed a rather strange problem.
First, my scene/setup: Ball at the top of the screen, a line of 12 crates at the bottom close together, almost like one continuous ground. Gravity is set to (0.0f, -9.8f).
Left and right arrow keys move the ball left or right by applying a constant force amount. Very simple.
Now, the problem: The ball falls downwards at the start, bounces a few times on the crates, and gradually comes to a rest. That's fine. BUT - if I give it a slight nudge with
the left or right arrows, it continues sliding/moving atop the line of crates in that direction infinitely, until it falls off and out of view. To prevent it from falling, I'd have to press
the opposite arrow key, but then it starts sliding that way. No amount of values for either the ball or the crate FrictionCoefficient seems to change this behaviour. I even tried
setting the LinearDragCoefficient to zero, but no go. Granted that the ball would obviously roll a little bit if you press left or right arrows, but I wouldn't expect it to go on
and on continuously. Totally weird...

Here's the bits of relevant code that might help:

Init() & Update() methods

    public class ObjectTest : Screen
    {

        // ***************************************************************
        // Class-scope Variables
        // ***************************************************************

        private PhysicsSimulator physicsSimulator;
        private Player bowlingBall;
        Vector2 ballJump;
        
        private Crate[] myCrates;
        private int numCrates;
        private float crateXPos;
        

        // ***************************************************************
        // ObjectTest()
        //  - Default constructor.
        // ***************************************************************

        public ObjectTest()
            : base("ObjectTest")
        {

        }


        // ***************************************************************
        // Initialize()
        //  - Perform one-time setup for this Screen.
        // ***************************************************************

        public override void Initialize()
        {

            // Initialise the physics engine
            physicsSimulator = new PhysicsSimulator(new Vector2(0.0f, -9.8f));
                        
            // Create the ball character
            bowlingBall = new Player(physicsSimulator, 5.0f, 12.0f, "Content/Sprites/Objects/BowlingBall");
            bowlingBall.physicsBody.Position = new Vector2(0.1f, 12.0f);
            bowlingBall.physicsGeometry.RestitutionCoefficient = 0.75f;
            bowlingBall.physicsGeometry.FrictionCoefficient = 1.0f;
            ballJump = new Vector2(0.0f, 20.0f);
            
            // Create a line of 12 crates
            numCrates = 12;
            myCrates = new Crate[numCrates];
            crateXPos = -17.0f;
            for(int i = 0; i < numCrates; i++)
            {
                myCrates[i] = new Crate(physicsSimulator, 10.0f, 1000.0f, "Content/Sprites/Objects/Crate");
                myCrates[i].physicsBody.Position = new Vector2(crateXPos, -14.0f);
                myCrates[i].physicsBody.IsStatic = true;
                myCrates[i].physicsGeometry.FrictionCoefficient = 1.0f;
                crateXPos += (myCrates[i].graphicsObject.ScaleX * 2.0f);
            }
                        
            // Add all objects to the managed lists
            AddObjectsToManagedList();

            base.Initialize();

        }


        // ***************************************************************
        // Activity()
        //  - The update loop for this Screen.
        // ***************************************************************

        public override void Activity(bool firstTimeCalled)
        {

            const float forceAmount = 25.0f;
            Vector2 force = Vector2.Zero;
            force.Y = -force.Y;
            ///bowlingBall.physicsBody.ClearImpulse();
            ///bowlingBall.physicsBody.ClearForce();
            ///bowlingBall.physicsBody.LinearDragCoefficient = 0.0f;
            
            // Control the ball using the keyboard

            // Move right
            if (InputManager.Keyboard.KeyDown(Keys.Right))
            {
                force += new Vector2(forceAmount, 0.0f);                
            }
            // Move left
            if (InputManager.Keyboard.KeyDown(Keys.Left))
            {
                force -= new Vector2(forceAmount, 0.0f);                
            }
            // Jump
            if (InputManager.Keyboard.KeyPushed(Keys.Space))
            {
                bowlingBall.physicsBody.ApplyImpulse(ballJump);
            }

            // Apply all forces according to input
            bowlingBall.physicsBody.ApplyForce(force);

            // Update the physics engine
            physicsSimulator.Update(TimeManager.SecondDifference);
            
            // Update all graphics objects based on physics
            bowlingBall.graphicsObject.X = bowlingBall.physicsBody.Position.X;
            bowlingBall.graphicsObject.Y = bowlingBall.physicsBody.Position.Y;
            for (int i = 0; i < numCrates; i++)
            {
                myCrates[i].graphicsObject.X = myCrates[i].physicsBody.Position.X;
                myCrates[i].graphicsObject.Y = myCrates[i].physicsBody.Position.Y;
            }

            base.Activity(firstTimeCalled);

        }


        // ***************************************************************
        // Destroy()
        //  - Clean up all elements of this Screen.
        // ***************************************************************

        public override void Destroy()
        {

            base.Destroy();

        }
}

Player (ball) class:

    public class Player
    {

        // ***************************************************************
        // Class-scope Variables
        // ***************************************************************

        private SpriteUtility spriteUtility;

        private Sprite playerSprite;

        private Body playerBody;
        private Geom playerGeom;


        // ***************************************************************
        // Player()
        //  - Default constructor.
        // ***************************************************************

        public Player(PhysicsSimulator physicsSimulator, float mass, float momentOfInertia, string texture)
        {

            // Create a SpriteUtility instance
            spriteUtility = new SpriteUtility();

            // Create the graphics object
            playerSprite = SpriteManager.AddSprite(texture);
            spriteUtility.ScaleSpriteToTextureSize(playerSprite);

            // Create the physics body object
            playerBody = BodyFactory.Instance.CreateBody(physicsSimulator, mass, momentOfInertia);
            
            // Create the physics geometry object
            playerGeom = GeomFactory.Instance.CreateCircleGeom(physicsSimulator, playerBody, 1, 64);

        }


        // ***************************************************************
        // Access functions for each of the object's components
        // ***************************************************************

        public Body physicsBody
        {
            get { return playerBody; }
        }

        public Geom physicsGeometry
        {
            get { return playerGeom; }
        }

        public Sprite graphicsObject
        {
            get { return playerSprite; }
        }

    }
 
Crate class:

public class Crate
    {

        // ***************************************************************
        // Class-scope Variables
        // ***************************************************************

        private SpriteUtility spriteUtility;

        private Sprite crateSprite;

        private Body crateBody;
        private Geom crateGeom;


        // ***************************************************************
        // Crate()
        //  - Default constructor.
        // ***************************************************************

        public Crate(PhysicsSimulator physicsSimulator, float mass, float momentOfInertia, string texture)
        {

            // Create a SpriteUtility instance
            spriteUtility = new SpriteUtility();

            // Create the graphics object
            crateSprite = SpriteManager.AddSprite(texture);
            spriteUtility.ScaleSpriteToTextureSize(crateSprite);

            // Create the physics body object
            crateBody = BodyFactory.Instance.CreateBody(physicsSimulator, mass, momentOfInertia);
            
            // Create the physics geometry object
            crateGeom = GeomFactory.Instance.CreateRectangleGeom(physicsSimulator, crateBody, 2 * crateSprite.ScaleX, 2 * crateSprite.ScaleY);

        }


        // ***************************************************************
        // Access functions for each of the object's components
        // ***************************************************************

        public Body physicsBody
        {
            get { return crateBody; }
        }

        public Geom physicsGeometry
        {
            get { return crateGeom; }
        }

        public Sprite graphicsObject
        {
            get { return crateSprite; }
        }

    }
 
If anyone can figure this out and provide an explanation/solution, I'd be really grateful. Its a bit of a big deal as this is for a Uni. assignment as well, so will be getting marked on the final quality of the product.

Many thanks in advance for all and any help! :-)
 
Mar 15, 2010 at 11:46 AM

*** BUMP ***

Any ideas? Anyone at all? I'd much appreciate any thoughts/insights into this problem.
Many thanks. 

Mar 15, 2010 at 4:45 PM

You should try playing with the RotationalDragCoefficient and perhaps the MomentOfInertia properties on the ball body. I think the friction will come into play when two bodies are sliding against eachother, but won't really affect the rolling behaviour.