Проблемы обработчика событий OnCollision в C# XNA с Физикой Farseer

У меня есть эта работа хорошо (выход) в моей игре в данный момент, но я не являюсь фантастическим в математике. То, когда два примитива сталкиваются, я хочу, чтобы они врезались в крошечные биты, если сила относилась к примитиву, было по порогу набора. Мой обработчик событий коллизии в настоящее время похож на это.

public bool Collision(Fixture fixtureA, Fixture fixtureB, Manifold manifold) 
{ 
   Vector2 position = manifold.LocalNormal; 
   float angle = (float)Math.Atan2(position.Y, position.X); 
   Vector2 force = Vector2.Zero; 
   if (angle < 0) 
     force = new Vector2((float)(Math.Cos(angle) * fixtureA.Body.LinearVelocity.X), (float)Math.Sin(MathHelper.TwoPi + angle) * fixtureA.Body.LinearVelocity.Y); 
   else 
     force = new Vector2((float)(Math.Cos(angle) * fixtureA.Body.LinearVelocity.X), (float)Math.Sin(MathHelper.TwoPi - angle) * fixtureA.Body.LinearVelocity.Y); 
   double XForce = Math.Sqrt(force.X * force.X); 
   double YForce = Math.Sqrt(force.Y * force.Y); 
   double totalForce = XForce + YForce; 
   if ((Breakable) && (totalForce > BreakForce)) 
   { 
      Breakable = false; 
      Active = false; 
      BreakUp(fixtureA, fixtureB); 
   } 
   return true; 
} 

Я вставил это давным-давно, когда я просто играл вокруг. Это вызывает определенную проблему в определенных ситуациях. Например, если примитив является стационарным на полу и другом примитиве падения на него от достойной высоты, почти всегда, падение втискивает удары, и покоящееся поле выживает. Также, если два поля падают рядом и дают друг другу самое крошечное из касаний, то оба поля аварийно завершают середину воздуха. Hmmmmm, не действительно прекрасный это. У кого-либо есть какая-либо идея, как улучшить мой обработчик коллизий?Заранее спасибо.

6
задан DrLazer 22 July 2010 в 10:50
поделиться

3 ответа

(Хотя в настоящее время это общепринятый ответ - я бы направил любого к своему другому ответу для потенциально более совершенного подхода.)

Ваш расчет силы удара равен совершенно неверно. Вам нужно получить относительную скорость в точке (точках) контакта - вы получаете что-то довольно странное ...

Ваш код выглядит так, как будто он использует Farseer 3.0 (вы должны указать, потому что это скорее форк Box2DX, чем Провидец 2.1). Что я сделал в Farseer 2.1 (где у вас есть ContactList контактов вместо Manifold ), чтобы получить скорость удара, было:

foreach(Contact contact in contacts)
{
    Vector2 position = contact.Position;
    Vector2 v0;
    me.Body.GetVelocityAtWorldPoint(ref position, out v0);
    Vector2 v1 = new Vector2();
    if(!hit.Body.IsStatic)
        hit.Body.GetVelocityAtWorldPoint(ref position, out v1);
    v0 -= v1;

    float hitVelocity = v0.Length();
    // To then get the force, you need the mass of the two objects
}

Из краткого обзора исходного кода Farseer 3.0 , кажется, что Manifold имеет член:

public FixedArray2<ManifoldPoint> Points;

И оба Manifold и ManifoldPoint имеют элементы:

public Vector2 LocalPoint;

Должно быть довольно просто изменить мой Farseer 2.1 код, чтобы использовать их вместо этого.

Также: я рекомендую просто пометить два объекта как нуждающиеся в разрушении, а затем фактически сломать их после завершения вашего обновления физики (а не в обработчике столкновений).

6
ответ дан 8 December 2019 в 14:39
поделиться

Хорошо, так что мой другой ответ жизнеспособен. Но я более внимательно посмотрел на Farseer 3.0 (текущую версию SVN) и обнаружил, что он уже реализует почти в точности то, что вы пытаетесь сделать.

Найдите « BreakableBody.cs ». Вы можете использовать это напрямую, но в противном случае вы можете просто скопировать нужную вам функциональность.

В частности: вместо того, чтобы прикреплять функцию к OnCollision вашего прибора, вы хотите прикрепить ее к PostSolve . Требуется ContactConstraint , в которое вы можете погрузиться и найти импульсы от столкновения.

Это реализация функции, используемой BreakableBody :

private void PostSolve(ContactConstraint contactConstraint)
{
    if (!Broken)
    {
        float maxImpulse = 0.0f;
        for (int i = 0; i < contactConstraint.manifold.PointCount; ++i)
        {
            maxImpulse = Math.Max(maxImpulse,
                         contactConstraint.manifold.Points[0].NormalImpulse);
            maxImpulse = Math.Max(maxImpulse,
                         contactConstraint.manifold.Points[1].NormalImpulse);
        }

        if (maxImpulse > Strength)
        {
            // Flag the body for breaking.
            _break = true;
        }
    }
}

Очевидно импульсные данные в коллекторах правильно установлены только в PostSolve , а не в ] OnCollision .

8
ответ дан 8 December 2019 в 14:39
поделиться

Я не использовал XNA, но как физическая проблема, почему бы просто не вычесть линейную скорость A из линейной скорости of B, и получить «силу» как квадрат результирующего вектора (суммировать квадраты компонентов)? Это должно согласовываться с задействованной кинетической энергией согласно `E = (mv ^ 2) / 2 'для очень простой физической модели, даже если мы игнорируем массы (или, если на то пошло, эластичность или различие между энергией и импульс). Если объекты движутся в одном общем направлении с одинаковой скоростью, вы получите небольшое значение; если кто-то приближается (или, конечно, удаляется!) на большой скорости, вы получаете большую ценность.

2
ответ дан 8 December 2019 в 14:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: