обнаружение столкновений в физическом движке Farseer 3.3

для тех из вас, кто знаком с farseer, у меня есть вопрос относительно обнаружения столкновений. Я много читал и смотрел отличный видеоурок по XNAtutorial Джорана Омарка. К сожалению, он использовал более старую версию farseer (версия 2006 года), поэтому мне пришлось немного подправить, чтобы моя работала. Теперь все работает, кроме моего обнаружения столкновений. Я просто не могу заставить их работать. Я решил использовать подход screenmanager и поэтому создал хорошие отдельные классы.

Мой 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://farseerphysics.codeplex.com/releases/view/64108 и затем пример HelloWorld. Я читал материал о GeomFactory, который использовался в предыдущих версиях для коллизий. Однако это изменилось с новой версией Farseer, где bodyfactory может обрабатывать целую кучу вещей. Так кто-нибудь знает, почему моя коллизия не работает?


person Shinji    schedule 05.09.2011    source источник
comment
Я не вижу ничего явно неправильного в вашем коде, все стандартные вещи вроде бы на месте. Вы уверены, что рисуете вещи в правильном месте? Из того, что вы опубликовали, я не вижу, правильно ли вы конвертируете единицы Sim в единицы экрана. Всегда хорошей идеей будет в первую очередь подключить DebugviewXNA.   -  person Nick    schedule 05.09.2011
comment
Извините за поздний ответ, не увидел комментарий, но спасибо за совет. У меня такое ощущение, что действительно преобразование единиц измерения идет неправильно. Не пробовал DebugViewXNA. Но это звучит как план. Если я каким-то образом разберусь с этим, я опубликую ответ.   -  person Shinji    schedule 13.09.2011


Ответы (1)


Да, ваше позиционирование отключено, потому что, судя по тому, что я получил, поигравшись с движком, он использует координаты экрана в метрах. Это означает, что ваш экран может быть только 10x16 (около) метров (480x800 пикселей), потому что это то, чем Microsoft ограничивает разрешение экрана. Таким образом, когда вы передаете позиции в 16000,1500 пикселей и делите их на 50, вы действительно помещаете тела на 320 м и 30 м, что находится далеко за пределами экрана для тел, но на экране для функции рисования, потому что она думает, что эти значения находятся в пикселях.

Кроме того, из того, что я видел в примере HelloWorld, который находится на их сайте, вы должны использовать 64 для деления на 50, а не 50. Я не уверен, почему это именно так, но я могу предположить, что это потому, что 64 является коэффициентом 2, а компьютеры любят множители. из 2, лол, поэтому, если вы используете 50, вы можете столкнуться с некоторыми столкновениями.

person Tom    schedule 17.09.2011
comment
Спасибо за ваши ответы. Однако вопрос? Вы имеете в виду, что есть другое тело столкновения (возможно, использование FixtureFactory). Потому что я все еще могу перетаскивать свое тело и усиливать его движением мыши, поэтому, если бы мое тело было расположено далеко, то я думаю, что это было бы невозможно. Также мои извинения, что я использовал/использую 64f, только я скопировал/вставил предыдущую тестовую часть. - person Shinji; 19.09.2011