Skip to content

Commit

Permalink
Use a double linked list for contacts
Browse files Browse the repository at this point in the history
Fixes #41
  • Loading branch information
Genbox committed Jun 20, 2021
1 parent 02cfc56 commit b9005ec
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 98 deletions.
2 changes: 1 addition & 1 deletion src/VelcroPhysics.MonoGame.DebugView/DebugView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ private void DrawDebugPanel()
_debugPanelSb.AppendLine("Objects:");
_debugPanelSb.Append("- Bodies: ").AppendLine(World.BodyList.Count.ToString());
_debugPanelSb.Append("- Fixtures: ").AppendLine(fixtureCount.ToString());
_debugPanelSb.Append("- Contacts: ").AppendLine(World.ContactList.Count.ToString());
_debugPanelSb.Append("- Contacts: ").AppendLine(World.ContactManager.ContactCount.ToString());
_debugPanelSb.Append("- Joints: ").AppendLine(World.JointList.Count.ToString());
_debugPanelSb.Append("- Controllers: ").AppendLine(World.ControllerList.Count.ToString());
_debugPanelSb.Append("- Proxies: ").AppendLine(World.ProxyCount.ToString());
Expand Down
90 changes: 60 additions & 30 deletions src/VelcroPhysics/Collision/ContactSystem/Contact.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,33 +75,44 @@ public class Contact
}
};

//private bool _initialized;

internal ContactFlags _flags;
internal Manifold _manifold;

// World pool and list pointers.
internal Contact _prev;
internal Contact _next;

// Nodes for connecting bodies.
internal ContactEdge _nodeA = new ContactEdge();
internal ContactEdge _nodeB = new ContactEdge();

internal float _toi;
internal Fixture _fixtureA;
internal Fixture _fixtureB;

private int _indexA;
private int _indexB;

internal Manifold _manifold;

internal int _toiCount;
internal float _toi;

private ContactType _type;

internal Fixture _fixtureA;
internal Fixture _fixtureB;
private float _friction;
private float _tangentSpeed;
private int _childIndexA;
private int _childIndexB;
private float _restitution;

/// <summary>Get the contact manifold. Do not modify the manifold unless you understand the internals of Box2D.</summary>
public Manifold Manifold => _manifold;
private float _tangentSpeed;

private Contact(Fixture fA, int indexA, Fixture fB, int indexB)
{
Reset(fA, indexA, fB, indexB);
}

/// <summary>Get the contact manifold. Do not modify the manifold unless you understand the internals of Box2D.</summary>
public Manifold Manifold => _manifold;

public float Friction
{
get => _friction;
Expand All @@ -126,11 +137,11 @@ public float TangentSpeed

/// <summary>Get the child primitive index for fixture A.</summary>
/// <value>The child index A.</value>
public int ChildIndexA => _childIndexA;
public int ChildIndexA => _indexA;

/// <summary>Get the child primitive index for fixture B.</summary>
/// <value>The child index B.</value>
public int ChildIndexB => _childIndexB;
public int ChildIndexB => _indexB;

/// <summary>
/// Enable/disable this contact.The contact is only disabled for the current time step (or sub-step in continuous
Expand All @@ -148,6 +159,9 @@ public bool Enabled
}
}

public Contact Next => _next;
public Contact Previous => _prev;

internal bool IsTouching => (_flags & ContactFlags.TouchingFlag) == ContactFlags.TouchingFlag;
internal bool IslandFlag => (_flags & ContactFlags.IslandFlag) == ContactFlags.IslandFlag;
internal bool TOIFlag => (_flags & ContactFlags.TOIFlag) == ContactFlags.TOIFlag;
Expand Down Expand Up @@ -181,11 +195,14 @@ private void Reset(Fixture fA, int indexA, Fixture fB, int indexB)
_fixtureA = fA;
_fixtureB = fB;

_childIndexA = indexA;
_childIndexB = indexB;
_indexA = indexA;
_indexB = indexB;

_manifold.PointCount = 0;

_prev = null;
_next = null;

_nodeA.Contact = null;
_nodeA.Prev = null;
_nodeA.Next = null;
Expand All @@ -198,7 +215,7 @@ private void Reset(Fixture fA, int indexA, Fixture fB, int indexB)

_toiCount = 0;

//Velcro: We only set the friction and restitution if we are not destroying the contact
//Velcro: We only set the friction and restitution if we are not resetting the contact
if (_fixtureA != null && _fixtureB != null)
{
_friction = Settings.MixFriction(_fixtureA._friction, _fixtureB._friction);
Expand All @@ -215,13 +232,11 @@ private void Reset(Fixture fA, int indexA, Fixture fB, int indexB)
/// <param name="contactManager">The contact manager.</param>
internal void Update(ContactManager contactManager)
{
//Velcro: Do not try and update destroyed contacts
if (_fixtureA == null || _fixtureB == null)
return;

Body bodyA = _fixtureA.Body;
Body bodyB = _fixtureB.Body;

Manifold oldManifold = Manifold;
Manifold oldManifold = _manifold;

// Re-enable this contact.
_flags |= ContactFlags.EnabledFlag;
Expand All @@ -231,19 +246,25 @@ internal void Update(ContactManager contactManager)

bool sensor = _fixtureA.IsSensor || _fixtureB.IsSensor;

Body bodyA = _fixtureA.Body;
Body bodyB = _fixtureB.Body;

Transform xfA = bodyA._xf;
Transform xfB = bodyB._xf;

// Is this contact a sensor?
if (sensor)
{
Shape shapeA = _fixtureA.Shape;
Shape shapeB = _fixtureB.Shape;
touching = Narrowphase.Collision.TestOverlap(shapeA, _childIndexA, shapeB, _childIndexB, ref bodyA._xf, ref bodyB._xf);
touching = Narrowphase.Collision.TestOverlap(shapeA, _indexA, shapeB, _indexB, ref xfA, ref xfB);

// Sensors don't generate manifolds.
_manifold.PointCount = 0;
}
else
{
Evaluate(ref _manifold, ref bodyA._xf, ref bodyB._xf);
Evaluate(ref _manifold, ref xfA, ref xfB);
touching = _manifold.PointCount > 0;

// Match old contact ids to new contact ids and copy the
Expand Down Expand Up @@ -282,13 +303,13 @@ internal void Update(ContactManager contactManager)
else
_flags &= ~ContactFlags.TouchingFlag;

if (touching)
if (wasTouching == false && touching)
{
// Report the collision to both participants:
//Velcro: Report the collision to both fixtures:
_fixtureA.OnCollision?.Invoke(_fixtureA, _fixtureB, this);
_fixtureB.OnCollision?.Invoke(_fixtureB, _fixtureA, this);

// Report the collision to both bodies:
//Velcro: Report the collision to both bodies:
bodyA.OnCollision?.Invoke(_fixtureA, _fixtureB, this);
bodyB.OnCollision?.Invoke(_fixtureB, _fixtureA, this);

Expand All @@ -304,7 +325,7 @@ internal void Update(ContactManager contactManager)

if (wasTouching && !touching)
{
//Report the separation to both participants:
//Report the separation to both fixtures:
_fixtureA.OnSeparation?.Invoke(_fixtureA, _fixtureB, this);
_fixtureB.OnSeparation?.Invoke(_fixtureB, _fixtureA, this);

Expand All @@ -315,10 +336,8 @@ internal void Update(ContactManager contactManager)
contactManager.EndContact?.Invoke(this);
}

if (sensor)
return;

contactManager.PreSolve?.Invoke(this, ref oldManifold);
if (!sensor && touching)
contactManager.PreSolve?.Invoke(this, ref oldManifold);
}

/// <summary>Evaluate this contact with your own manifold and transforms.</summary>
Expand Down Expand Up @@ -393,14 +412,25 @@ internal static Contact Create(Fixture fixtureA, int indexA, Fixture fixtureB, i

internal void Destroy()
{
_fixtureA.Body._world._contactPool.Enqueue(this);
//Debug.Assert(_initialized);

if (Manifold.PointCount > 0 && !_fixtureA.IsSensor && !_fixtureB.IsSensor)
//Fixture fixtureA = _fixtureA;
//Fixture fixtureB = _fixtureB;

if (_manifold.PointCount > 0 && !_fixtureA.IsSensor && !_fixtureB.IsSensor)
{
_fixtureA.Body.Awake = true;
_fixtureB.Body.Awake = true;
}

//b2Shape::Type typeA = fixtureA->GetType();
//b2Shape::Type typeB = fixtureB->GetType();

//Debug.Assert(0 <= typeA && typeA < b2Shape::e_typeCount);
//Debug.Assert(0 <= typeB && typeB < b2Shape::e_typeCount);

_fixtureA._body._world._contactPool.Enqueue(this);

Reset(null, 0, null, 0);
}
}
Expand Down
Loading

0 comments on commit b9005ec

Please sign in to comment.