Question about drawing textures on fixture position

Topics: User Forum
Jan 10, 2011 at 9:47 PM
Edited Jan 10, 2011 at 10:09 PM

Hi,

 

First of, i'm pretty new to XNA so please bear with me.

I searched the discussions and found some half helping answers. I'm using the latest version with Windows Phone 7.

As like a lot of users i have some fixtures in my world. I want to use some textures to display on the positions of these fixtures.

Somehow i'm unable to do this, and i don't understand why, i've spent 2 days on this already and am at a point where i wanna stop using the physics engine. This can't be that hard? I can't get this info from the samples, i can't find it.

 

I'm aware of the fact that textures are drawn in pixels and fixtures are in meters.

Can someone give me the most simple example where a fixture (rectangle or circle or ellipse) is created in the loadcontent method and a texture is drawn in the draw method on the position of the fixture for Windows Phone 7?

That's all i want.

 

Thanks in advance.

Jan 11, 2011 at 9:11 AM

Ok i have found some info.

 

Everyone else facing this, this post is very helpful:

http://farseerphysics.codeplex.com/Thread/View.aspx?ThreadId=224681

 

Developer
Jan 11, 2011 at 11:27 AM

If you are using the spritebatch and work with a fixed resolution you need to define some scale which fits to your game. Farseer likes it's fixtures to be between 1 and 10 meters. So if your main character sprite is e.g. 64x64 pixels you could define 1m to be equal to 64px. The spritebatch origin is in the top left corner and the positive y axis points down. So set your gravity to a positive value (e.g. (0f, 10f), if you want objects to fall to the bottom of the screen.

If you have a resolution of 800x480 your screen center is at (400f, 240f) in spritebatch coordinates. Divide that by your scale (400/64, 240/64) and create a rectangle fixture with a width and height of 1f at (6.25f, 3.75f) which would be the screen center of your choosen physics coordinate system.

When drawing, draw a 64x64px sprite at Body.Position * 64f and rotate it by Body.Rotation. So it all comes down to multiplying or dividing position data with your scale when shifting from sprite coordinates to physics coordinates and vice versa.

If you are not only new to XNA but game programming or graphics in general, it would not hurt though to have a look at transformation matrices and different perspective projections, because this problem is not really physics related. It is tempting to think in pixels only, but it pays of to keep things somewhat resolution independent even for 2D games today. WP7 for instance also scales all your graphics to the devices display resolution, regardless of whether you are using the native resolution or not. And in the future the resolution of different devices may very well vary. With this approach you just have to change your scale factor if you e.g. decide tomorrow that your main character is only 32px tall for a lower resolution version and you don't have to change anything on your physics setup at all.

Coordinator
Jan 11, 2011 at 4:36 PM

A small correction: The fixtures should be between 0.1 and 10 meters. It is possible to have larger, but that is the recommendation for good collisions.

Elsch: On the subject, do you think you could change the Hello World sample to use textures with the spritebatch instead of debugview? Drawing is too cumbersome for new users and a very simple sample with drawing might be useful.

Developer
Jan 11, 2011 at 5:37 PM

Genbox: I am currently working on all the samples and in the process of switching most of the drawing to spritebatch, as most of the questions here revolve around drawing lately :)

Then we have both approaches (spritbatch and primitives) in the demobase and debugview code. Unfortunately I am quite busy at work currently... but I'll have a look at the HelloWorld sample tonight... that shouldn't be too much work.

Jan 12, 2011 at 4:10 AM

@Elsch:

I am a new user who had trouble himself. Using the Information I found scattered throughout this Discussion Board and the rest of the Web I managed to get the Problem solved myself. To a certain degree that is.

In the Process I wrote a minimal Sample which could be easily made into a HelloWorld Sample for using SpriteBatch and DebugView. You can find it here: http://pastebin.com/zf0siEH3

I was yet not able to get Rectangles instead if Circles working for my Physics Representation. Something about my scaling seems to be wrong when I try to use CreateRectangle instead of CreateCircle. I might solve this issue myself in the morning however.

Developer
Jan 12, 2011 at 11:13 AM

I uploaded a new HelloWorld XNA sample to source control tonight, which leaves the default spritebatch coordinate system untouched and does not use any transformation matrices at all (except for the DebugView that is). I tried to comment and explain everything thoroughly, but feel free to give me feedback if some parts could be better explained or if more details are needed.

@memmaker:

You kind of mix up several approaches in your sample. If you pass a transformation matrix to the spritebatch that should at least include your projection matrix and not only the view. Also you do all the scaling twice, which does not make any sense. Either you should convert your coordinates by hand like you do between spritebatch.Begin() and spritebatch.End(). Or you can pass a transformation matrix to spritebatch.Begin(), which takes then care of the conversion automatically.

On fixture creation you pass the texture hight, but the circle factory expects to get the radius instead of the diameter of a circle.

Also your projection always scales the screen to a fixed range from -50 to 50 on the y axis, regardless of the window size and resolution. Which is fine, but I am not sure if that was your goal. That means your sprite covers always the same portion of the screen but not the same amount of pixels for different resolutions, e.g. if your sprite covers exactly the amount of pixels the original texture has, than it is completly coincidental (I think that was your goal, as you use the texture height for creating your fixture). 

I don't want to be rude here, but your code looks like a lot of trail and error without really knowing what you are doing and makes things a lot more complicated than they are actually. Maybe you should take another look at the new HelloWorld sample. If you are interested in the "passing a transformation matrix to the spritebatch" approach, I could provide some alternative HelloWorld code. I think I am going to put together a little tutorial alongside the SimpleSamples for 3.3 :)

Jan 12, 2011 at 1:30 PM
Edited Jan 12, 2011 at 2:30 PM

@Elsch

just found out about your new HelloWorld Sample which should get some of the confusion out of my code. Which was to that point indeed Trial & Error regarding the Transformation and Scaling.

I also just realized the Radius vs. Diameter thingy in the Constructor. Actually I wanted to have the Screen at a fixed size so that a higher Resolution means you can see more of the World Space. I guess my approach was wrong.

I will rewrite the Physics integration using your new HelloWorld Sample which looked pretty understandable to me.

EDIT:

ok, I managed to replicate the Behavior from the new HelloWorld Sample.

I am currently doing the following:

Fixtures for Sprites are created like this:

float width = s.Asset.Width / TwengineGame.MeterInPx;
float height = s.Asset.Height / TwengineGame.MeterInPx;
if (collisionShape == CollisionShape.Circle)
{
	f = FixtureFactory.CreateCircle(this.pw, width/2, 1f);
}
else if (collisionShape == CollisionShape.Rectangle)
{
	f = FixtureFactory.CreateRectangle(this.pw, width, height, 1.0f);
}

The Camera Class defines this Projection Matrix:

Projection = Matrix.CreateOrthographicOffCenter(0f, _graphics.Viewport.Width / TwengineGame.MeterInPx, _graphics.Viewport.Height / TwengineGame.MeterInPx, 0f, 0f, 1f);

Sprites are Drawn like this then:

Vector2 screenCoords = this.Fixture.Body.Position * TwengineGame.MeterInPx;
Vector2 origin = new Vector2(this.Asset.Width / 2, this.Asset.Height / 2);
sb.Draw(this.Asset, screenCoords, null, this.Color, this.Fixture.Body.Rotation, origin, 1f, SpriteEffects.None, this.LayerDepth);

Passing no View Matrix to the RenderDebugView() and SpriteBatch.Begin() calls this works flawless.

I now tried to use the View Matrix for Camera Control, since that's the common usage as I understand it. So I defined the following View Matrix for the Camera and passed it to RenderDebugView() and SpriteBatch.Begin():

View = Matrix.CreateRotationZ(_rotation) * Matrix.CreateTranslation(-_position.X, -_position.Y, 0) * Matrix.CreateScale(_zoom);

Zooming works fine, but the Translation part seems wrong. As soon as introduce the Translationmatrix and try moving the Camera the DebugView and the Sprites get Offset again. I guess it's because of the Scaling Factor MeterInPx missing somewhere in the Equation. But then again I thought the view Matrix would get applied to both the DebugView Rendering and the SpriteBatch rendering and should thus have the same Effect on both?!

I am a bit confused here, if you could give me a nod in the right direction I would appreciate it.

Developer
Jan 12, 2011 at 7:15 PM

You have to generate an additional view matrix for the debug view and scale the translation accordingly e.g. divide it by MetersInPx. I just added a simple camera to HelloWorld XNA and uploaded it to source control.