Farseer as a character Controller not working

Topics: Developer Forum, Project Management Forum, User Forum
May 8, 2012 at 11:35 PM

so im currently in the process of prototyping my game, its going to be a platformer so im testing methods for basic character movement. Basic physics is working but im having a few issue no matter what values i try.

For instance when i try to "jump" no matter what value i plug into to applyForce (ive also tried applyLinearImpulse same effect) he has a very low jump height and will not jump higher, Ive tried 1000 and he barely hopped  Currently Im using:

test.physicsBody.ApplyForce(new Vector2(0, -100000000000000));

 and he still doesnt jump anywhere near high eneough (I assum because ive reached/passed the size cap for float), so i tried applying force twice in a row and still nothing.

So then i tried changing gravity (even tho he already falls pretty slowly, Gravity is currently 0,15.

So I then tried changing his mass, initially he had a mass of 1, then i tried .5f, then .5f/64 and still no real change.

Another issue im having is that if i try moving in the air (left or right) he stops falling all together until i release the move keys. Ill attach all relevant Code below this point.

 

Physics handler class:

 public static class _physics
    {
        /// <summary>
        /// The Physics world
        /// </summary>
        public static World world;
        /// <summary>
        /// Initialize the World
        /// </summary>
        public static void init(Vector2 gravity)
        {
            //setup the world
            world = new World(gravity);
        }
        /// <summary>
        /// process the world
        /// </summary>
        public static void update()
        {
            world.Step(0.05f);
        }
    }

Physics based sprite functions:

 //animated sprite with phsycis
        public _sprite(ContentManager ContentManager, string path, Vector2 _position, bool _animated,bool physics, int _frameTime, 
            int _frames, int _width , int _height, BodyType physicsType, float density,ref World world,bool rotationLock)
        {
            image = ContentManager.Load<Texture2D>(path);
            position = _position;
            frames = _frames;
            width = _width;
            height = _height;
            animated = true;
            usePhysics = false;
            playing = true;
            onFrame = 0;
            sources = new List<Rectangle>();
            generateFrames();
            timer = 0;
            frameTime = _frameTime;
            //setup the physics
            Vertices box = PolygonTools.CreateRectangle(width / 2, height / 2);
            shape = new PolygonShape(box, density);
            physicsBody = new Body(world);
            physicsBody.BodyType = physicsType;
            physicsBody.Position = _position;
            physicsBody.FixedRotation = rotationLock;
            physicsBody.CreateFixture(shape);
            physicsBody.Friction = 10f;
            usePhysics = true;
        }

public void update()
        {
            if (animated && playing)
            {
                play();
            }
            if (usePhysics)
            {
                position = physicsBody.Position;
                angle = physicsBody.Rotation;
            }
        }
public void draw(ref SpriteBatch batch)
        {
            if (animated && !usePhysics)
            {
                if (!useCamera)
                {
                    batch.Draw(image, position, sources[onFrame], Color.White);
                }
            }
            else
            {
                if (usePhysics && !animated)
                {
                    //draw physics
                    batch.Draw(image, new Rectangle((int)position.X, (int)position.Y, width, height), null, Color.White, angle, new Vector2(0), SpriteEffects.None, 1.0f);
                }
                else
                {
                    //draw animated and physics
                    if (animated && usePhysics)
                    {
//This is the one that is called for my object
                        if (!useCamera)
                        {
                            batch.Draw(image, new Rectangle((int)position.X, (int)position.Y, width, height), sources[onFrame], Color.White, angle, new Vector2(0), SpriteEffects.None, 1.0f);
                        }
                        else
                        {
                            batch.Draw(image, new Rectangle((int)position.X - (int)Maps.MapData.cameraPosition.X, (int)position.Y - (int)Maps.MapData.cameraPosition.Y, width, height), sources[onFrame], Color.White, angle, new Vector2(0), SpriteEffects.None, 1.0f);
                        }
                    }
                    else
                    {
                        //draw normal
                        batch.Draw(image, position, Color.White);
                    }
                }
            }
        }
    }

and finally Engine 

public static void init(ref GraphicsDeviceManager deviceManager)
        {
            _physics.init(new Vector2(0,15));
            //setup the render target
            _presParamaters = deviceManager.GraphicsDevice.PresentationParameters;
            _target = new RenderTarget2D(deviceManager.GraphicsDevice, _presParamaters.BackBufferWidth, _presParamaters.BackBufferHeight,
                false, deviceManager.GraphicsDevice.DisplayMode.Format, DepthFormat.Depth24);            
        }

public static void load(ref GraphicsDeviceManager deviceManager, ContentManager content)
        {
            //load blur shader
            effect = content.Load<Effect>("Shaders/effect");
            Maps.Nelana.JunkHeap.loadJunkHeap(content, deviceManager.GraphicsDevice, ref _physics.world);
            test = new _sprite(content, "SpriteSheets/Player/Chrysanthemum", new Vector2(550, 20), true, true, 5, 6, 50, 50, FarseerPhysics.Dynamics.BodyType.Dynamic, 0.5f/64, ref _physics.world, true);
            test.useCamera = true;

        }
public static void update(ref GraphicsDeviceManager deviceManager, ContentManager content)
        {
            //physics tests
            KeyboardState ks = Keyboard.GetState();
            if (ks.IsKeyDown(Keys.Right))
            {
                test.physicsBody.LinearVelocity = new Vector2(MathHelper.ToRadians(1000000), test.physicsBody.LinearVelocity.Y);
            }
            if(ks.IsKeyDown(Keys.Left))
            {
                test.physicsBody.ApplyForce(new Vector2(-1000000, 0));
            }
            if (ks.IsKeyDown(Keys.Up) && test.physicsBody.LinearVelocity.Y==0)
            {
                test.physicsBody.ApplyForce(new Vector2(0, -100000000000000));
            }
            _physics.update();
            Maps.MapData.update(test.physicsBody.Position);
            test.update();
        }

I am at a Complete loss here, does anyone have any ideas?

May 9, 2012 at 8:03 AM

Hi,

I see quite a few things in your code that are possibly errors so please clarify.

- You are not scaling your physics. You are working in pixels and not meters. See the ConvertUnits.cs class in the samples. The physics engine works in the MKS system and is best tuned in the 0.1-10 range. Unless your character is a cruise ship 50x60 meters...

- Your sprite drawing code is probably incorrect (although I am no expert on that). XNA's rectangle and Farseer's "rectangle shape" are different. One uses a corner as a reference point, the other the geometric center. This affects both position and rotation. See the samples for a system for drawing sprites that you may adapt.

- Your gravity is pointing "up"? Farseer uses a right-handed coordinate system positive Y "up", positive "X" right. A properly set matrix projection decouples that from the drawing logic easily if that's an issue.

- Density of 0.5/64?

- Setting LinearVelocity in radians? 

- The physics update loop. You are not using the delta-time. How often is it actually called? World.step(0.05) means simulate 0.05s of physics, it doesn't know about the passage of time in general (1s might have passed since the last update in real time or 0.01s or 1/60s with the default tendency of XNA to keep a fixed time step). Probably the physics is completely desynchronized. It's a weird update method too with different parameters than the standard one - is it even hooked to the XNA loop?

Hope this helps to clear up the code a bit depending on what your needs are with respect to the engine's needs.