Физика Farseer: проблемы с обнаружением столкновений

У меня есть три прямоугольных блока: наземный блок, синий блок, блок героя. Земля размещается внизу экрана, синий блок лежит на наземном блоке, а блок героя падает на синий блок. У меня есть слушатель, который определяет, когда герой касается земли. Возможны две ситуации: 1) Когда герой падает с небольшой высоты на синий блок, его ок слушатель уведомляет, что герой касается только синего блока. 2) Когда герой падает с немного большей высоты, слушатель синего блока уведомляет, что герой касается земли !!! Как решить эту проблему?

Это прослушиватель Hero OnCollision:

bool heroBody_OnCollision(Fixture fixtureA, Fixture fixtureB, Contact contact)
{

  Texture2D textureB = (Texture2D)fixtureB.UserData;
  string textureBName = ((string)textureB.Tag).ToLower();

  if (textureBName == "ground")
  { 
    OnHeroTouchedGround();
    return true;
   }
   else if (textureBName.Contains("blue"))
   {       
     OnHeroTouchedBlueBlock();
     return true;
   }

   return true;
}


    public HeroState GetHeroState()
    {
        ContactEdge contactEdge = null;

        if (heroBody != null) contactEdge = heroBody.ContactList;

        while (contactEdge != null)
        {
            if (heroBody.LinearVelocity == Vector2.Zero)
            {
                Texture2D textureA = (Texture2D)contactEdge.Contact.FixtureA.UserData;
                string textureAName = ((string)textureA.Tag).ToLower();
                Texture2D textureB = (Texture2D)contactEdge.Contact.FixtureB.UserData;
                string textureBName = ((string)textureB.Tag).ToLower();

                if (textureAName == "ground" || textureBName == "ground")
                    return HeroState.OnGroud;
                 else if (textureAName.Contains("blue") ||    textureBName.Contains("blue"))
                    return HeroState.OnHome;
            }

            contactEdge = contactEdge.Next;
        }

        return HeroState.Playing;
    }

person Maksim Shamihulau    schedule 17.08.2011    source источник
comment
Синий блок очень тонкий? Он легкий, а герой тяжелый? Возможно ли, что блок героя движется достаточно быстро, чтобы он мог на короткое время проникнуть в оба блока?   -  person iforce2d    schedule 18.08.2011
comment
Блок героя имеет размер 60x60px, синий блок имеет высоту 20px. Визуально герой не падает быстро, а пробивает синий блок. Примечание: отображаемые единицы sim: 1 м = 100 пикселей. Возможно, мне нужно поиграть с некоторыми параметрами движка farseer, но какие именно?   -  person Maksim Shamihulau    schedule 19.08.2011


Ответы (2)


Тот факт, что он разный в зависимости от высоты падения, говорит о том, что герой проникает прямо сквозь синий блок, чтобы коснуться земли. Попробуйте установить блок героя в виде тела пули, если проблема устранена, то это действительно так. Вы также можете поэкспериментировать с высотой синего блока, чтобы увидеть, как это влияет на вещи.

Я рекомендую использовать отладку отрисовки, чтобы убедиться, что то, что вы видите, действительно происходит в физическом движке.

person iforce2d    schedule 19.08.2011
comment
Пытался сделать героя телом пули, но проблема не устранена. - person Maksim Shamihulau; 19.08.2011
comment
Спасибо. Похоже, вы вообще не проверяете fixA в этом коде. Нет никакой гарантии, что героем является приспособление A, поэтому на самом деле подфункция там должна называться OnSomethingTouchedGround :) Однако, если вы уже проверяете, является ли действующее устройство A героем до вызова этой функции, все должно быть в порядке. - person iforce2d; 20.08.2011
comment
Я проверил, что приспособление A всегда является героем из-за heroBody.OnCollision += heroBody_OnCollision; поэтому я удалил ненужные проверки. Кстати, когда скорость героя становится равной нулю, у него есть 2 контакта: синий блок, что правда, и, к сожалению, оранжевый блок :(. - person Maksim Shamihulau; 20.08.2011
comment
Полная функция проверки фактических столкновений GetHeroState(); - person Maksim Shamihulau; 20.08.2011
comment
Я добавил проверки для FixtureA в heroBody_OnCollision(). И это показывает, что никаких столкновений с землей нет!!! Это очень хорошо ! Но все еще есть проблема, я хочу проверить, с какими блоками контактирует герой. Когда скорость героя равна нулю, я получаю список контактов, в котором есть 3 контакта: земля с синим, синий с героем и земля с героем. Третий пункт меня убивает... - person Maksim Shamihulau; 20.08.2011

Я нашел, как решить проблему: 1) я подключил проект Farseer к своему решению 2) в Settings.cs нашел строку public const float AABBExtension = 0.1f; 3) Изменено значение на «0,01f». И это работает !!!

person Maksim Shamihulau    schedule 20.08.2011
comment
ладно, кажется, я вижу, что сейчас происходит. Вы не используете обратный вызов BeginContact? BeginContact будет вызван, когда два прибора начнут соприкасаться. Я не знаком со «списком контактов», но похоже, что он содержит контакты для приборов, у которых перекрываются только AABB — это не означает, что сами приборы на самом деле перекрываются, но вы можете проверить, перекрываются ли они с помощью IsTouching(). - person iforce2d; 21.08.2011
comment
Где находится BeginContact и как им пользоваться? Вы имели в виду напр. heroBody.FixtureList[0].BeforeCollision = heroBody_OnCollision; ? - person Maksim Shamihulau; 21.08.2011
comment
Но теперь я использую IsTouching() для контакта, и он работает, больше не нужно менять AABBExtension! Это то, что я искал! Большое спасибо ! - person Maksim Shamihulau; 21.08.2011