DebugViewXNA not lining up with body

Topics: Developer Forum, User Forum
Aug 21, 2011 at 6:06 PM

I can't for the life of me figure out how to get the DebugViewXNA's outline of the box2d body to line up correctly with the actual body. I'm certain I have something wrong in the Draw() method but I can't figure out what.

Any help would be greatly appreciated. 

This is what it is doing: http://dl.dropbox.com/u/186383/box2d_debugviewxna.png

Here is the code:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;
using FarseerPhysics.Collision.Shapes;
using DebugViews;
using FarseerPhysics;
namespace Box2d_One
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        private GraphicsDeviceManager mGraphics;
        private SpriteBatch mSpriteBatch;
        private ContentManager mContentManager;
        private World mWorld;
        protected DebugViewXNA mDebugView;

        private Body _circleBody;
        private Texture2D _circleSprite;
        private Vector2 _screenCenter;
        private Matrix _view;
        private Vector2 _cameraPosition;

        private const float MeterInPixels = 64f;

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

            mContentManager = new ContentManager(this.Services);

            mGraphics.PreferredBackBufferWidth = 800;
            mGraphics.PreferredBackBufferHeight = 480;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            IsFixedTimeStep = true;
            TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 10);

            mWorld = new World(new Vector2(0f, 0f));
            Services.AddService(typeof(World), mWorld);

            mDebugView = new DebugViewXNA(mWorld);
            mDebugView.LoadContent(GraphicsDevice, mContentManager);

            mDebugView.AppendFlags(DebugViewFlags.Shape);
            mDebugView.AppendFlags(DebugViewFlags.Joint);
            mDebugView.AppendFlags(DebugViewFlags.DebugPanel);
            mDebugView.AppendFlags(DebugViewFlags.ContactPoints);
            mDebugView.AppendFlags(DebugViewFlags.AABB);
            mDebugView.AppendFlags(DebugViewFlags.PerformanceGraph);
            mDebugView.AppendFlags(DebugViewFlags.PolygonPoints);
            mDebugView.AppendFlags(DebugViewFlags.CenterOfMass);
            mDebugView.DefaultShapeColor = Color.LightGray;
            mDebugView.SleepingShapeColor = Color.Orange;

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            _view = Matrix.Identity;
            _cameraPosition = Vector2.Zero;
            _screenCenter = new Vector2(mGraphics.GraphicsDevice.Viewport.Width / 2f,
                                                mGraphics.GraphicsDevice.Viewport.Height / 2f);

            mSpriteBatch = new SpriteBatch(GraphicsDevice); 

            Services.AddService(typeof(SpriteBatch), mSpriteBatch);

            _circleSprite = Content.Load<Texture2D>("circleSprite"); //  96px x 96px => 1.5m x 1.5m

            Vector2 circlePosition = (_screenCenter / MeterInPixels) + new Vector2(0, -1.5f);

            _circleBody = BodyFactory.CreateCircle(mWorld, 96f / (2f * MeterInPixels), 1f, circlePosition);
            _circleBody.BodyType = BodyType.Dynamic;
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            Content.Unload();
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            if (Keyboard.GetState().IsKeyDown(Keys.Home))
            {
                mDebugView.RemoveFlags(DebugViewFlags.Shape);
                mDebugView.RemoveFlags(DebugViewFlags.Joint);
                mDebugView.RemoveFlags(DebugViewFlags.DebugPanel);
                mDebugView.RemoveFlags(DebugViewFlags.ContactPoints);
                mDebugView.RemoveFlags(DebugViewFlags.AABB);
                mDebugView.RemoveFlags(DebugViewFlags.PerformanceGraph);
                mDebugView.RemoveFlags(DebugViewFlags.PolygonPoints);
                mDebugView.RemoveFlags(DebugViewFlags.CenterOfMass);
            }
            else if (Keyboard.GetState().IsKeyDown(Keys.End))
            {
                mDebugView.AppendFlags(DebugViewFlags.Shape);
                mDebugView.AppendFlags(DebugViewFlags.Joint);
                mDebugView.AppendFlags(DebugViewFlags.DebugPanel);
                mDebugView.AppendFlags(DebugViewFlags.ContactPoints);
                mDebugView.AppendFlags(DebugViewFlags.AABB);
                mDebugView.AppendFlags(DebugViewFlags.PerformanceGraph);
                mDebugView.AppendFlags(DebugViewFlags.PolygonPoints);
                mDebugView.AppendFlags(DebugViewFlags.CenterOfMass);
            }

            HandleInput(gameTime);

            //step the simulator. must convert the value of dt to seconds
            mWorld.Step(gameTime.ElapsedGameTime.Milliseconds * 0.001f);

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            Matrix proj = Matrix.CreateOrthographic(
                mGraphics.PreferredBackBufferWidth / 1f / 100.0f,
                -mGraphics.PreferredBackBufferHeight / 1f / 100.0f, 0, 1000000);
            Matrix view = Matrix.Identity;

            Vector2 circlePos = _circleBody.Position * MeterInPixels;
            float circleRotation = _circleBody.Rotation;

            Vector2 circleOrigin = new Vector2(_circleSprite.Width / 2f, _circleSprite.Height / 2f);

            mSpriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, _view);

            mSpriteBatch.Draw(_circleSprite, circlePos, null, Color.White, circleRotation, circleOrigin, 1f, SpriteEffects.None, 0f);
            mDebugView.RenderDebugData(ref proj, ref view);

            mSpriteBatch.End();

            base.Draw(gameTime);
        }

        float mForce = 5f;

        protected virtual void HandleInput(GameTime gameTime)
        {
            KeyboardState keyState = Keyboard.GetState();

            Vector2 force = Vector2.Zero;
            float forceAmount = mForce * 0.6f;

            if (keyState.IsKeyDown(Keys.Left))
            {
                force += new Vector2(-forceAmount, 0);
            }
            if (keyState.IsKeyDown(Keys.Right))
            {
                force += new Vector2(forceAmount, 0);
            }
            if (keyState.IsKeyDown(Keys.Up))
            {
                force += new Vector2(0, -forceAmount);
            }
            if (keyState.IsKeyDown(Keys.Down))
            {
                force += new Vector2(0, forceAmount);
            }

            _circleBody.FixtureList[0].Body.ApplyForce(ref force);
        }
    }
}

Aug 24, 2011 at 9:24 PM

This is what I use.

Matrix Projection = Matrix.CreateOrthographicOffCenter(

0,  Constants.ToFarseer(Device.Viewport.Width),  Constants.ToFarseer(Device.Viewport.Height), 0,    0,      1f);

To Farseer function is your /64. This way you don't have to minus the Y.

 

Also for the view your gonna want set tthe origin for the screen so you do something like.

Matrix View = Matrix.CreateTranslation(new Vector3( - ScreenCenter /64, 0))  Matrix.CreateTranslation(new Vector3(ScreenCenter / 64, 0));

for the ref debug view;

Aug 24, 2011 at 9:25 PM

for the spritebatch view take out the /64

Aug 24, 2011 at 10:00 PM

This is working. 

I really appreciate your help!

 

http://dl.dropbox.com/u/186383/box2d_working.png

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

            Matrix Projection = Matrix.CreateOrthographicOffCenter(0, Constants.ToFarseer(mGraphics.GraphicsDevice.Viewport.Width), Constants.ToFarseer(mGraphics.GraphicsDevice.Viewport.Height), 0, 0, 1f);

            Matrix view = Matrix.Identity;

            Vector2 circlePos = _circleBody.Position * MeterInPixels;
            float circleRotation = _circleBody.Rotation;

            Vector2 circleOrigin = new Vector2(_circleSprite.Width / 2f, _circleSprite.Height / 2f);

            mSpriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, _view);

            mDebugView.RenderDebugData(ref Projection, ref view);
            mSpriteBatch.Draw(_circleSprite, circlePos, null, Color.White, circleRotation, circleOrigin, 1f, SpriteEffects.None, 0f);

            mSpriteBatch.End();

            base.Draw(gameTime);
        }
Aug 25, 2011 at 10:45 PM
Edited Aug 25, 2011 at 10:59 PM

1.) Sorry, can you please tell me what namespace contains Constants class (so i can use Constants.ToFarseer() method from your example)  i can't find it in FarseerPhysics 3.3.1 solution!

I'm totally losing my grip, same thing is happening with  FarseerPhysics.Mathematics namespace, i wanted to use FarseerPhysics.Mathematics.ConvertUnits and i found it at

  http://mail.java2s.com/Open-Source/CSharp/Game/autumn/FarseerGames/FarseerPhysics/Mathematics/ConvertUnits.cs.htm

 and added them, i don't get it, how can this be missing in Farseer solution,

i found this classes used a lot in this topics, am i supposed to use some other methods in 3.3.1?? Please, can u explain this.. :((

 

2.) After i added FarseerPhysics.Mathematics.ConvertUnits into the project, my debug view looks like this, it has an offset and i don't have a clue why..

Here's the current debug view offset link;

http://imageshack.us/photo/my-images/37/debugviewoffset.png/

and here is the code i've used (like i said before, i added method FarseerPhysics.Mathematics.ConvertUnits from the link above..), please tell me what do i need to change?

float projectionWidth =FarseerPhysics.Mathematics.ConvertUnits.ToSimUnits(graphics.PreferredBackBufferWidth - mMeterInPixels); // if i remove - mMeterInPixels (64px = 1meter) offset is even bigger..
float projectionHeight = FarseerPhysics.Mathematics.ConvertUnits.ToSimUnits(graphics.PreferredBackBufferHeight - mMeterInPixels);
Matrix projection = Matrix.CreateOrthographicOffCenter(0, projectionWidth, projectionHeight, 0, 0, 1000000f);

Matrix view = Matrix.Identity;
mDebugView.RenderDebugData(ref projection, ref view);

 

Thank you in advance for the reply.

Aug 25, 2011 at 11:39 PM

I just created the Constants class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Utils
{
    public static class Constants
    {
        public static float ToFarseer(float value)
        {
            return value / 64f;
        }

        public static Vector2 ToFarseer(Vector2 value)
        {
            return (value / 64f);
        }
    }
}

Aug 26, 2011 at 4:58 PM
Edited Aug 26, 2011 at 5:07 PM

Just for fun :)

I haven't test sorry :/ but it should works :D

namespace Utils
{
    class Constants<T>
         where T : float, vector2
    {
        public static T ToFarseer<T>(T value)
        {
            if (typeof(T) == typeof(float))
                return (T)(object)((float)(object)value / 64f);
            else
                return (T)(object)((vector2)(object)value / 64f);
        }
    }
}



        
    
Aug 26, 2011 at 8:53 PM

I first came across the problem with ConvertUnits class, and your class name sounded so generic, i've just thought same thing is happening again,

thx for clearing that up.

 

But still, can you give me some help regarding this part;

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 FarseerPhysics.Mathematics namespace is missing in my Farseer 3.3.1 project, i wanted to use FarseerPhysics.Mathematics.ConvertUnits and i found it at

  http://mail.java2s.com/Open-Source/CSharp/Game/autumn/FarseerGames/FarseerPhysics/Mathematics/ConvertUnits.cs.htm

 and added them, i don't get it, how can this be missing in Farseer solution,

i found this classes used a lot in this topics, am i supposed to use some other methods with equivalent results in version 3.3.1?? Please, can u explain this..

Aug 26, 2011 at 8:55 PM

I used the ConvertUnits from the samples: http://farseerphysics.codeplex.com/SourceControl/changeset/view/90041#1642119