Farseer 物理引擎 3.3 中的碰撞检测
对于那些熟悉 Farseer 的人,我有一个关于碰撞检测的问题。我读了很多东西,并观看了 Joran Omark 在 XNAtutorial 上制作的精彩视频教程。不幸的是,他使用了 Farseer 的旧版本(2006 年版本),所以我不得不稍微调整一下才能让我的版本正常工作。现在除了碰撞检测之外一切正常。我似乎无法让它们发挥作用。我决定采用屏幕管理器方法,因此创建漂亮的单独类。
我的 GameplayScreen 看起来像这样
public class GamePlayScreen : GameScreen
{
Texture2D stewieTexture;
Texture2D floorTexture;
Sprite stewie;
Sprite floor;
World world;
public GamePlayScreen()
{
world = new World(new Vector2(0, 9.81F));
EnabledGestures = GestureType.Flick;
}
public override void LoadContent()
{
stewieTexture = ScreenManager.Game.Content.Load<Texture2D>("playerStewie");
floorTexture = ScreenManager.Game.Content.Load<Texture2D>("Floor");
this.stewie = new Sprite();
this.floor = new Sprite();
this.stewie.LoadGraphicsContent(ScreenManager.SpriteBatch, this.stewieTexture, world);
this.floor.LoadGraphicsContent(ScreenManager.SpriteBatch, this.floorTexture, world);
// very ugly unfortunately for now like this.. We need Textures for our sprite that's why
this.stewie.Initialize(world, BodyType.Dynamic ,new Vector2(16000,1500));
this.floor.Initialize(world, BodyType.Static, new Vector2(1500, 16000));
}
public override void HandleInput(InputState input)
{
foreach (GestureSample gesture in input.Gestures)
{
if (gesture.GestureType == GestureType.Flick)
{
stewie.PhysicsBody.ApplyForce(Vector2.Divide(gesture.Delta, 0.5f));
}
}
}
public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
{
world.Step((float)gameTime.ElapsedGameTime.TotalSeconds);
this.stewie.Update(gameTime, world);
this.floor.Update(gameTime, world);
base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
}
public override void Draw(GameTime gameTime)
{
// TODO: Add your drawing code here
ScreenManager.SpriteBatch.Begin();
this.stewie.Draw(gameTime);
this.floor.Draw(gameTime);
ScreenManager.SpriteBatch.End();
base.Draw(gameTime);
}
}
我的 Sprite 类
public class Sprite
{
private Animation graphicsImage;
private Body physicsBody;
//Fixture test
//private Fixture fixtureBody;
private Vector2 _screenCenter;
private float pixelsPerMeter = 50; //needed to convert pixels per meter , because the gesture.position is in meters
public Body PhysicsBody { get { return physicsBody; } }
public Sprite()
{
this.graphicsImage = new Animation();
}
/// <summary>
/// Initialize the sprite sets up position , creates rectangle from bodyfactory
/// </summary>
/// <param name="world"> takes a reference to the worldobject</param>
public void Initialize(World world, BodyType bodyType,Vector2 position)
{
this.graphicsImage.Initialize();
this.physicsBody = BodyFactory.CreateRectangle(world, this.graphicsImage.Size.X / pixelsPerMeter, this.graphicsImage.Size.Y / pixelsPerMeter, 1f);
this.graphicsImage.Position = position / pixelsPerMeter;
this.physicsBody.Position = this.graphicsImage.Position;
this.physicsBody.BodyType = bodyType;
// this.fixtureBody = FixtureFactory.AttachRectangle(this.physicsBody.Position.X / pixelsPerMeter, this.physicsBody.Position.Y / pixelsPerMeter, 3f, new Vector2(100, 100), this.physicsBody);
//this.physicsBody.Restitution = 0.7f;
Debug.WriteLine("Initialize Sprite");
Debug.WriteLine(this.graphicsImage.Position);
}
/// <summary>
/// LoadGraphicsContent for the sprite call this function in the LoadContent ( initialize also works )
/// </summary>
/// <param name="spriteBatch">takes a reference to a spritebatch</param>
/// <param name="texture">takes a reference to texture2D</param>
public void LoadGraphicsContent(SpriteBatch spriteBatch, Texture2D texture, World world)
{
this.graphicsImage.LoadGraphicsContent(spriteBatch, texture);
}
/// <summary>
/// Update sprite for graphicsImage position , and rotation needs to be called in the main Update function of the game
/// </summary>
/// <param name="gameTime">reference to gameTime</param>
/// <param name="world">reference to worldobject</param>
public void Update(GameTime gameTime, World world)
{
this.graphicsImage.Update(gameTime);
this.graphicsImage.Position = this.physicsBody.Position;
this.graphicsImage.Rotation = this.physicsBody.Rotation;
}
/// <summary>
/// Draw sprite method needs to be called in the main Draw function of the game
/// </summary>
/// <param name="gameTime"></param>
public void Draw(GameTime gameTime)
{
this.graphicsImage.Draw(gameTime);
}
}
}
正如我已经说过的,我的碰撞不起作用。我查看了当前使用 Farseer 3.3 的示例(就像我一样)。 例如这里 http://farseerphysicals.codeplex.com/releases/view/64108 和然后是 HelloWorld 示例。 我读过有关以前版本中用于碰撞的 GeomFactory 的内容。然而,随着 Farseer 的新版本,这种情况发生了变化,其中 bodyfactory 可以处理一大堆东西。 那么有人知道为什么我的碰撞不起作用吗?
for those of you familiar with farseer , I have a question regarding collision detection. I´ve read a lot of stuff and watched an excellent video tutorial on XNAtutorial by Joran Omark. Unfortunately he used an older version of farseer( a 2006 version ) , so I had to tweak a little to get mine to work. Now everything works except my collision detection. I just can´t seem to get those to work. I decided to go for the screenmanager approach and therefore create nice seperate classes.
My GameplayScreen looks like this
public class GamePlayScreen : GameScreen
{
Texture2D stewieTexture;
Texture2D floorTexture;
Sprite stewie;
Sprite floor;
World world;
public GamePlayScreen()
{
world = new World(new Vector2(0, 9.81F));
EnabledGestures = GestureType.Flick;
}
public override void LoadContent()
{
stewieTexture = ScreenManager.Game.Content.Load<Texture2D>("playerStewie");
floorTexture = ScreenManager.Game.Content.Load<Texture2D>("Floor");
this.stewie = new Sprite();
this.floor = new Sprite();
this.stewie.LoadGraphicsContent(ScreenManager.SpriteBatch, this.stewieTexture, world);
this.floor.LoadGraphicsContent(ScreenManager.SpriteBatch, this.floorTexture, world);
// very ugly unfortunately for now like this.. We need Textures for our sprite that's why
this.stewie.Initialize(world, BodyType.Dynamic ,new Vector2(16000,1500));
this.floor.Initialize(world, BodyType.Static, new Vector2(1500, 16000));
}
public override void HandleInput(InputState input)
{
foreach (GestureSample gesture in input.Gestures)
{
if (gesture.GestureType == GestureType.Flick)
{
stewie.PhysicsBody.ApplyForce(Vector2.Divide(gesture.Delta, 0.5f));
}
}
}
public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
{
world.Step((float)gameTime.ElapsedGameTime.TotalSeconds);
this.stewie.Update(gameTime, world);
this.floor.Update(gameTime, world);
base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
}
public override void Draw(GameTime gameTime)
{
// TODO: Add your drawing code here
ScreenManager.SpriteBatch.Begin();
this.stewie.Draw(gameTime);
this.floor.Draw(gameTime);
ScreenManager.SpriteBatch.End();
base.Draw(gameTime);
}
}
And my Sprite class
public class Sprite
{
private Animation graphicsImage;
private Body physicsBody;
//Fixture test
//private Fixture fixtureBody;
private Vector2 _screenCenter;
private float pixelsPerMeter = 50; //needed to convert pixels per meter , because the gesture.position is in meters
public Body PhysicsBody { get { return physicsBody; } }
public Sprite()
{
this.graphicsImage = new Animation();
}
/// <summary>
/// Initialize the sprite sets up position , creates rectangle from bodyfactory
/// </summary>
/// <param name="world"> takes a reference to the worldobject</param>
public void Initialize(World world, BodyType bodyType,Vector2 position)
{
this.graphicsImage.Initialize();
this.physicsBody = BodyFactory.CreateRectangle(world, this.graphicsImage.Size.X / pixelsPerMeter, this.graphicsImage.Size.Y / pixelsPerMeter, 1f);
this.graphicsImage.Position = position / pixelsPerMeter;
this.physicsBody.Position = this.graphicsImage.Position;
this.physicsBody.BodyType = bodyType;
// this.fixtureBody = FixtureFactory.AttachRectangle(this.physicsBody.Position.X / pixelsPerMeter, this.physicsBody.Position.Y / pixelsPerMeter, 3f, new Vector2(100, 100), this.physicsBody);
//this.physicsBody.Restitution = 0.7f;
Debug.WriteLine("Initialize Sprite");
Debug.WriteLine(this.graphicsImage.Position);
}
/// <summary>
/// LoadGraphicsContent for the sprite call this function in the LoadContent ( initialize also works )
/// </summary>
/// <param name="spriteBatch">takes a reference to a spritebatch</param>
/// <param name="texture">takes a reference to texture2D</param>
public void LoadGraphicsContent(SpriteBatch spriteBatch, Texture2D texture, World world)
{
this.graphicsImage.LoadGraphicsContent(spriteBatch, texture);
}
/// <summary>
/// Update sprite for graphicsImage position , and rotation needs to be called in the main Update function of the game
/// </summary>
/// <param name="gameTime">reference to gameTime</param>
/// <param name="world">reference to worldobject</param>
public void Update(GameTime gameTime, World world)
{
this.graphicsImage.Update(gameTime);
this.graphicsImage.Position = this.physicsBody.Position;
this.graphicsImage.Rotation = this.physicsBody.Rotation;
}
/// <summary>
/// Draw sprite method needs to be called in the main Draw function of the game
/// </summary>
/// <param name="gameTime"></param>
public void Draw(GameTime gameTime)
{
this.graphicsImage.Draw(gameTime);
}
}
}
As I already stated, is that my collision isn´t working. I´ve looked at the current samples that use Farseer 3.3 (just like I do).
For instance here http://farseerphysics.codeplex.com/releases/view/64108 and then the HelloWorld example.
I´ve read the stuff about the GeomFactory that was being used in the previous versions for collision. However that has changed with the new version of Farseer where the bodyfactory can handle a whole bunch of stuff.
So does anyone have any idea why my collision isn´t working?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
是的,您的定位已关闭,因为根据我从使用引擎中获得的信息,它使用以米为单位的屏幕坐标。这意味着您的屏幕只能是 10x16 米(480x800 像素),因为这是 Microsoft 的屏幕分辨率上限。因此,当您传入 16000,1500 像素的位置并将其除以 50 时,您实际上将物体放置在 320m 和 30m 处,这距离物体的屏幕很远,但在 Draw 函数的屏幕上,因为它认为这些值以像素为单位。
另外,从我在他们网站上的 HelloWorld 示例中看到的内容来看,您应该使用 64 除以而不是 50。我不确定为什么会这样,但我可以猜测这是因为 64 是 2 的因数,而计算机喜欢因数2 个哈哈,所以如果你使用 50 个,你可能会发生一些碰撞。
Yeah you're positioning is off because from what I have gained from playing around with the engine it uses the screen coordinates in Meters. Which means your screen can only be 10x16(ish) meters (480x800 pixels) because that is what Microsoft has their screen resolution capped at. So when you pass in the positions of 16000,1500 pixels and divide it by 50 you are really putting the bodies at 320m and 30m, which is way off the screen for the bodies but on the screen for the Draw function because it thinks those values are in pixels.
Also from what I saw in the HelloWorld example that is on their site you should be using 64 to divide by not 50. I'm not sure why that is exactly but I can guess it's because 64 is a factor of 2 and computers love factors of 2 lol so if you use 50 you might get some off collision happening.