Problem with a simple project of a ball in a frame using Farseer 3.5 and Monogame 3.2

Topics: Developer Forum, User Forum
Aug 31, 2014 at 8:05 PM
Hi,
I'm using VS 2013 Upt 3, Windows 8.1 and I tried to implement a simple example for learning how to use Farseer with Monogame. The example is about a ball in a frame that receives a force from a cue driven by the mouse. The resulting behaviour of the ball is not very real. I don't understand what's wrong in the code.

region Using Statements

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using FarseerPhysics.Collision;
using FarseerPhysics.Dynamics;
using FarseerPhysics;
using FarseerPhysics.Factories;
using FarseerPhysics.Common;
using FarseerPhysics.Controllers;

endregion

namespace BallInAFrame
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public partial class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        public Texture2D WhiteTexture { get; protected set; }

        private KeyboardState keyboard;
        private MouseState ms;

        Vector2 FrameSize = new Vector2(1024, 512);
        Vector2 FramePosition ;
        Vector2 FrameCenter;
        Color FrameColor;

        Body BallBody;

        const int BallsNumber = 1;
        const int CueSize = 5;
        float BallRadius = 20;

        public World _world;

        bool CueOn;
        Vector2 CuePosition;
        Texture2D CueTexture; //base for the line texture
        Texture2D BallTexture;
        Body Frame;


        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            //Create a world without gravity.
            _world = new World(new Vector2(0, 0));
        }


        protected override void Initialize()
        {
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 924;

            FramePosition = new Vector2((graphics.PreferredBackBufferWidth - FrameSize.X) / 2.0f, (graphics.PreferredBackBufferHeight - FrameSize.Y) / 2.0f);
            FrameCenter = new Vector2(graphics.PreferredBackBufferWidth/ 2.0f, graphics.PreferredBackBufferHeight/ 2.0f);

            FrameColor = Color.Black;

            this.WhiteTexture = new Texture2D(this.GraphicsDevice, 1, 1);
            this.WhiteTexture.SetData(new Color[] { Color.White });
            this.IsMouseVisible = true;

            CueOn = false;

            Window.Title = "BallInAFrame";
            graphics.IsFullScreen = false;
            graphics.ApplyChanges();

            base.Initialize();
        }

        protected override void LoadContent()
        {
            // Initialize camera controls

            spriteBatch = new SpriteBatch(graphics.GraphicsDevice);

            BallTexture = Content.Load<Texture2D>("graphics/Ball");

            ConvertUnits.SetDisplayUnitToSimUnitRatio(1024 / 2.40f);
            CreateBorder();

            BallBody = BodyFactory.CreateCircle(_world, ConvertUnits.ToSimUnits(BallRadius), 1f, ConvertUnits.ToSimUnits( FrameCenter));
            BallBody.BodyType = BodyType.Dynamic;
            BallBody.Restitution = 0.7f;

            BallBody.CollisionCategories = Category.All;
            BallBody.CollidesWith = Category.All;
            BallBody.Friction = 0.3f;
            BallBody.IgnoreGravity = true;

            // create 1x1 texture for Cue drawing
            CueTexture = new Texture2D(GraphicsDevice, 1, 1);
            CueTexture.SetData<Color>(new Color[] { Color.White });// fill the texture with white

        }

        public void CreateBorder()
        {
            Vertices borders = new Vertices(4);
            borders.Add(ConvertUnits.ToSimUnits(FramePosition)); ;
            borders.Add(new Vector2(ConvertUnits.ToSimUnits(FramePosition.X + FrameSize.X) , ConvertUnits.ToSimUnits(FramePosition.Y)));
            borders.Add(new Vector2(ConvertUnits.ToSimUnits(FramePosition.X + FrameSize.X) , ConvertUnits.ToSimUnits(FramePosition.Y + FrameSize.Y) ));
            borders.Add(new Vector2(ConvertUnits.ToSimUnits(FramePosition.X ), ConvertUnits.ToSimUnits(FramePosition.Y + FrameSize.Y) ));

            Frame = BodyFactory.CreateLoopShape(_world, borders);
            Frame.IsStatic = true;
            Frame.CollisionCategories = Category.All;
            Frame.CollidesWith = Category.All;
            Frame.Restitution = 0.7f;
            Frame.Friction = 0.1f;

            Frame.IgnoreGravity = true;
        }

        protected override void UnloadContent()
        {

        }

        protected override void Update(GameTime gameTime)
        {
            keyboard = Keyboard.GetState();
            if (keyboard.IsKeyDown(Keys.Escape))
            {
                Exit();
            }

            MouseState ms = Mouse.GetState();
            if (ms.LeftButton == ButtonState.Pressed)
            {
                CueOn = true;
                CuePosition = new Vector2(ms.X, ms.Y);
            }
            else if (CueOn == true)
            {
                CuePosition = new Vector2(ms.X, ms.Y);
                Vector2 Force = new Vector2(BallBody.Position.X - ConvertUnits.ToSimUnits(CuePosition.X) * 1f, ConvertUnits.ToSimUnits(BallBody.Position.Y - CuePosition.Y) * 1f);
                BallBody.ApplyForce(Force);
                CueOn = false;
            }

            //Billiard();
            _world.Step(0.033f);
            base.Update(gameTime);
        }


        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // Draw background texture in a seperate pass


            spriteBatch.Begin();
            DrawRectangle(spriteBatch, new Rectangle((int)FramePosition.X, (int)FramePosition.Y, (int)FrameSize.X, (int)FrameSize.Y), Color.Red, 1);

            spriteBatch.Draw(BallTexture, ConvertUnits.ToDisplayUnits(BallBody.Position)-new Vector2(BallRadius, BallRadius), null, Color.White, 0f, Vector2.Zero, 0.1f, SpriteEffects.None, 0f);

            if (CueOn == true)
                DrawCue(new Vector2(ConvertUnits.ToDisplayUnits( BallBody.Position.X), ConvertUnits.ToDisplayUnits(BallBody.Position.Y )), CuePosition);
            base.Draw(gameTime);
            // End rendering sprites
            spriteBatch.End();
        }

        void DrawCue(Vector2 start, Vector2 end)
        {
            Vector2 edge = end - start;
            // calculate angle to rotate line
            float angle =
                (float)Math.Atan2(edge.Y, edge.X);

            spriteBatch.Draw(CueTexture, new Rectangle((int)start.X,(int)start.Y, (int)edge.Length(), CueSize), null, Color.Red, angle, new Vector2(0, 0), SpriteEffects.None, 0);

        }
        static Texture2D _pointTexture;
        public static void DrawRectangle(SpriteBatch spriteBatch, Rectangle rectangle, Color color, int lineWidth)
        {
            if (_pointTexture == null)
            {
                _pointTexture = new Texture2D(spriteBatch.GraphicsDevice, 1, 1);
                _pointTexture.SetData<Color>(new Color[] { Color.White });
            }

            spriteBatch.Draw(_pointTexture, new Rectangle(rectangle.X, rectangle.Y, lineWidth, rectangle.Height + lineWidth), color);
            spriteBatch.Draw(_pointTexture, new Rectangle(rectangle.X, rectangle.Y, rectangle.Width + lineWidth, lineWidth), color);
            spriteBatch.Draw(_pointTexture, new Rectangle(rectangle.X + rectangle.Width, rectangle.Y, lineWidth, rectangle.Height + lineWidth), color);
            spriteBatch.Draw(_pointTexture, new Rectangle(rectangle.X, rectangle.Y + rectangle.Height, rectangle.Width + lineWidth, lineWidth), color);
        }     
    }
}