Обнаружение столкновений в физическом движке Farseer 3.3
Для тех из вас, кто знаком с дальновидным, у меня есть вопрос, касающийся обнаружения столкновений. Я много читаю и смотрю отличный видеоурок по XNAtutorial от Joran Omark. К сожалению, он использовал более старую версию 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);
}
}
И мой класс спрайт
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://farseerphysics.codeplex.com/releases/view/64108 а затем пример HelloWorld. Я читал материал о GeomFactory, который использовался в предыдущих версиях для столкновения. Однако это изменилось с новой версией Farseer, где фабрика по производству кузовов может обрабатывать целую кучу вещей. Так у кого-нибудь есть идеи, почему мое столкновение не работает?
1 ответ
Да, ваше позиционирование отключено, потому что из того, что я получил от игры с движком, он использует координаты экрана в метрах. Это означает, что ваш экран может быть только 10x16(ish) метров (480x800 пикселей), потому что это то, что Microsoft имеет ограниченное разрешение экрана. Поэтому, когда вы передаете позиции в 16000,1500 пикселей и делите его на 50, вы на самом деле помещаете тела на 320 и 30 м, что далеко от экрана для тел, но на экране для функции Draw, потому что она считает эти значения в пикселях.
Также из того, что я видел в примере HelloWorld, который находится на их сайте, вы должны использовать 64, чтобы разделить на 50. Я не уверен, почему это именно так, но я могу предположить, что это потому, что 64 - это фактор 2, а компьютеры любят факторы из 2 лол, так что если вы используете 50, вы можете получить некоторые столкновения.