У меня есть эта работа хорошо (выход) в моей игре в данный момент, но я не являюсь фантастическим в математике. То, когда два примитива сталкиваются, я хочу, чтобы они врезались в крошечные биты, если сила относилась к примитиву, было по порогу набора. Мой обработчик событий коллизии в настоящее время похож на это.
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, не действительно прекрасный это. У кого-либо есть какая-либо идея, как улучшить мой обработчик коллизий?Заранее спасибо.
(Хотя в настоящее время это общепринятый ответ - я бы направил любого к своему другому ответу для потенциально более совершенного подхода.)
Ваш расчет силы удара равен совершенно неверно. Вам нужно получить относительную скорость в точке (точках) контакта - вы получаете что-то довольно странное ...
Ваш код выглядит так, как будто он использует 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 код, чтобы использовать их вместо этого.
Также: я рекомендую просто пометить два объекта как нуждающиеся в разрушении, а затем фактически сломать их после завершения вашего обновления физики (а не в обработчике столкновений).
Хорошо, так что мой другой ответ жизнеспособен. Но я более внимательно посмотрел на 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
.
Я не использовал XNA, но как физическая проблема, почему бы просто не вычесть линейную скорость A из линейной скорости of B, и получить «силу» как квадрат результирующего вектора (суммировать квадраты компонентов)? Это должно согласовываться с задействованной кинетической энергией согласно `E = (mv ^ 2) / 2 'для очень простой физической модели, даже если мы игнорируем массы (или, если на то пошло, эластичность или различие между энергией и импульс). Если объекты движутся в одном общем направлении с одинаковой скоростью, вы получите небольшое значение; если кто-то приближается (или, конечно, удаляется!) на большой скорости, вы получаете большую ценность.