/// <summary> /// Contacts are persistant and will keep being persistant unless they are /// flagged for filtering. /// This methods flags all contacts associated with the body for filtering. /// </summary> internal void Refilter() { // Flag associated contacts for filtering. ContactEdge edge = Body.ContactList; while (edge != null) { Contact contact = edge.Contact; FSFixture fixtureA = contact.FixtureA; FSFixture fixtureB = contact.FixtureB; if (fixtureA == this || fixtureB == this) { contact.FlagForFiltering(); } edge = edge.Next; } var world = Body.World; if (world == null) { return; } // Touch each proxy so that new pairs may be created IBroadPhase broadPhase = world.ContactManager.BroadPhase; for (int i = 0; i < ProxyCount; ++i) { broadPhase.TouchProxy(Proxies[i].ProxyId); } }
private void Decompose() { //Unsubsribe from the PostSolve delegate _world.ContactManager.PostSolve -= PostSolve; for (int i = 0; i < Parts.Count; i++) { FSFixture fixture = Parts[i]; Shape shape = fixture.Shape.Clone(); object userdata = fixture.UserData; MainBody.DestroyFixture(fixture); FSBody body = BodyFactory.CreateBody(_world); body.BodyType = BodyType.Dynamic; body.Position = MainBody.Position; body.Rotation = MainBody.Rotation; body.UserData = MainBody.UserData; body.CreateFixture(shape, userdata); body.AngularVelocity = _angularVelocitiesCache[i]; body.LinearVelocity = _velocitiesCache[i]; } _world.RemoveBody(MainBody); _world.RemoveBreakableBody(this); }
internal void Destroy(Contact contact) { FSFixture fixtureA = contact.FixtureA; FSFixture fixtureB = contact.FixtureB; FSBody bodyA = fixtureA.Body; FSBody bodyB = fixtureB.Body; if (EndContact != null && contact.IsTouching()) { EndContact(contact); } // Remove from the world. ContactList.Remove(contact); // Remove from body 1 if (contact.NodeA.Prev != null) { contact.NodeA.Prev.Next = contact.NodeA.Next; } if (contact.NodeA.Next != null) { contact.NodeA.Next.Prev = contact.NodeA.Prev; } if (contact.NodeA == bodyA.ContactList) { bodyA.ContactList = contact.NodeA.Next; } // Remove from body 2 if (contact.NodeB.Prev != null) { contact.NodeB.Prev.Next = contact.NodeB.Next; } if (contact.NodeB.Next != null) { contact.NodeB.Next.Prev = contact.NodeB.Prev; } if (contact.NodeB == bodyB.ContactList) { bodyB.ContactList = contact.NodeB.Next; } #if USE_ACTIVE_CONTACT_SET if (ActiveContacts.Contains(contact)) { ActiveContacts.Remove(contact); } #endif contact.Destroy(); }
/// <summary> /// Restores collisions between this fixture and the provided fixture. /// </summary> /// <param name="fixture">The fixture.</param> public void RestoreCollisionWith(FSFixture fixture) { if (_collisionIgnores == null) { return; } if (_collisionIgnores.ContainsKey(fixture.FixtureId)) { _collisionIgnores[fixture.FixtureId] = false; Refilter(); } }
public void RestoreCollisionWith(FSBody other) { for (int i = 0; i < FixtureList.Count; i++) { FSFixture f = FixtureList[i]; for (int j = 0; j < other.FixtureList.Count; j++) { FSFixture f2 = other.FixtureList[j]; f.RestoreCollisionWith(f2); } } }
internal bool CompareTo(FSFixture fixture) { return( CollidesWith == fixture.CollidesWith && CollisionCategories == fixture.CollisionCategories && CollisionGroup == fixture.CollisionGroup && Friction == fixture.Friction && IsSensor == fixture.IsSensor && Restitution == fixture.Restitution && Shape.CompareTo(fixture.Shape) && UserData == fixture.UserData && UserBits == fixture.UserBits ); }
/// <summary> /// Determines whether collisions are ignored between this fixture and the provided fixture. /// </summary> /// <param name="fixture">The fixture.</param> /// <returns> /// <c>true</c> if the fixture is ignored; otherwise, <c>false</c>. /// </returns> public bool IsFixtureIgnored(FSFixture fixture) { if (_collisionIgnores == null) { return(false); } if (_collisionIgnores.ContainsKey(fixture.FixtureId)) { return(_collisionIgnores[fixture.FixtureId]); } return(false); }
public FSBreakableBody(IEnumerable <Vertices> vertices, FSWorld world, float density, object userData) { _world = world; _world.ContactManager.PostSolve += PostSolve; MainBody = new FSBody(_world); MainBody.BodyType = BodyType.Dynamic; foreach (Vertices part in vertices) { PolygonShape polygonShape = new PolygonShape(part, density); FSFixture fixture = MainBody.CreateFixture(polygonShape, userData); Parts.Add(fixture); } }
private static bool ShouldCollide(FSFixture fixtureA, FSFixture fixtureB) { if (FSSettings.UseFPECollisionCategories) { if ((fixtureA.CollisionGroup == fixtureB.CollisionGroup) && fixtureA.CollisionGroup != 0 && fixtureB.CollisionGroup != 0) { return(false); } if (((fixtureA.CollisionCategories & fixtureB.CollidesWith) == Category.None) & ((fixtureB.CollisionCategories & fixtureA.CollidesWith) == Category.None)) { return(false); } if (fixtureA.IsFixtureIgnored(fixtureB) || fixtureB.IsFixtureIgnored(fixtureA)) { return(false); } return(true); } if (fixtureA.CollisionGroup == fixtureB.CollisionGroup && fixtureA.CollisionGroup != 0) { return(fixtureA.CollisionGroup > 0); } bool collide = (fixtureA.CollidesWith & fixtureB.CollisionCategories) != 0 && (fixtureA.CollisionCategories & fixtureB.CollidesWith) != 0; if (collide) { if (fixtureA.IsFixtureIgnored(fixtureB) || fixtureB.IsFixtureIgnored(fixtureA)) { return(false); } } return(collide); }
/// <summary> /// Ignores collisions between this fixture and the provided fixture. /// </summary> /// <param name="fixture">The fixture.</param> public void IgnoreCollisionWith(FSFixture fixture) { if (_collisionIgnores == null) { _collisionIgnores = new Dictionary <int, bool>(); } if (_collisionIgnores.ContainsKey(fixture.FixtureId)) { _collisionIgnores[fixture.FixtureId] = true; } else { _collisionIgnores.Add(fixture.FixtureId, true); } Refilter(); }
/// <summary> /// Destroy a fixture. This removes the fixture from the broad-phase and /// destroys all contacts associated with this fixture. This will /// automatically adjust the mass of the body if the body is dynamic and the /// fixture has positive density. /// All fixtures attached to a body are implicitly destroyed when the body is destroyed. /// Warning: This function is locked during callbacks. /// </summary> /// <param name="fixture">The fixture to be removed.</param> public void DestroyFixture(FSFixture fixture) { Debug.Assert(fixture.Body == this); // Remove the fixture from this body's singly linked list. Debug.Assert(FixtureList.Count > 0); // You tried to remove a fixture that not present in the fixturelist. Debug.Assert(FixtureList.Contains(fixture)); // Destroy any contacts associated with the fixture. ContactEdge edge = ContactList; while (edge != null) { Contact c = edge.Contact; edge = edge.Next; FSFixture fixtureA = c.FixtureA; FSFixture fixtureB = c.FixtureB; if (fixture == fixtureA || fixture == fixtureB) { // This destroys the contact and removes it from // this body's contact list. World.ContactManager.Destroy(c); } } if ((Flags & BodyFlags.Enabled) == BodyFlags.Enabled) { IBroadPhase broadPhase = World.ContactManager.BroadPhase; fixture.DestroyProxies(broadPhase); } FixtureList.Remove(fixture); fixture.Destroy(); fixture.Body = null; ResetMassData(); }
public FSFixture Clone(FSBody body) { FSFixture fixture = new FSFixture(); fixture.Body = body; if (FSSettings.ConserveMemory) { fixture.Shape = Shape; } else { fixture.Shape = Shape.Clone(); } fixture.UserData = UserData; fixture.UserBits = UserBits; fixture.Restitution = Restitution; fixture.Friction = Friction; fixture.IsSensor = IsSensor; fixture._collisionGroup = CollisionGroup; fixture._collisionCategories = CollisionCategories; fixture._collidesWith = CollidesWith; if (_collisionIgnores != null) { fixture._collisionIgnores = new Dictionary <int, bool>(); foreach (KeyValuePair <int, bool> pair in _collisionIgnores) { fixture._collisionIgnores.Add(pair.Key, pair.Value); } } fixture.RegisterFixture(); return(fixture); }
internal void Collide() { // Update awake contacts. #if USE_ACTIVE_CONTACT_SET ActiveList.AddRange(ActiveContacts); foreach (var c in ActiveList) { #else for (int i = 0; i < ContactList.Count; i++) { Contact c = ContactList[i]; #endif FSFixture fixtureA = c.FixtureA; FSFixture fixtureB = c.FixtureB; int indexA = c.ChildIndexA; int indexB = c.ChildIndexB; FSBody bodyA = fixtureA.Body; FSBody bodyB = fixtureB.Body; if (bodyA.Awake == false && bodyB.Awake == false) { #if USE_ACTIVE_CONTACT_SET ActiveContacts.Remove(c); #endif continue; } // Is this contact flagged for filtering? if ((c.Flags & ContactFlags.Filter) == ContactFlags.Filter) { // Should these bodies collide? if (bodyB.ShouldCollide(bodyA) == false) { Contact cNuke = c; Destroy(cNuke); continue; } // Check default filtering if (ShouldCollide(fixtureA, fixtureB) == false) { Contact cNuke = c; Destroy(cNuke); continue; } // Check user filtering. if (ContactFilter != null && ContactFilter(fixtureA, fixtureB) == false) { Contact cNuke = c; Destroy(cNuke); continue; } // Clear the filtering flag. c.Flags &= ~ContactFlags.Filter; } int proxyIdA = fixtureA.Proxies[indexA].ProxyId; int proxyIdB = fixtureB.Proxies[indexB].ProxyId; bool overlap = BroadPhase.TestOverlap(proxyIdA, proxyIdB); // Here we destroy contacts that cease to overlap in the broad-phase. if (overlap == false) { Contact cNuke = c; Destroy(cNuke); continue; } // The contact persists. c.Update(this); } #if USE_ACTIVE_CONTACT_SET ActiveList.Clear(); #endif }
private bool OnCollisionEvent(FSFixture fixtureA, FSFixture fixtureB, Contact contact) { if(!lastContacts.Contains(contact)) lastContacts.Add(contact); return true; }
public FSFixture Clone(FSBody body) { FSFixture fixture = new FSFixture(); fixture.Body = body; if (FSSettings.ConserveMemory) fixture.Shape = Shape; else fixture.Shape = Shape.Clone(); fixture.UserData = UserData; fixture.UserBits = UserBits; fixture.Restitution = Restitution; fixture.Friction = Friction; fixture.IsSensor = IsSensor; fixture._collisionGroup = CollisionGroup; fixture._collisionCategories = CollisionCategories; fixture._collidesWith = CollidesWith; if (_collisionIgnores != null) { fixture._collisionIgnores = new Dictionary<int, bool>(); foreach (KeyValuePair<int, bool> pair in _collisionIgnores) fixture._collisionIgnores.Add(pair.Key, pair.Value); } fixture.RegisterFixture(); return fixture; }
/// <summary> /// Determines whether collisions are ignored between this fixture and the provided fixture. /// </summary> /// <param name="fixture">The fixture.</param> /// <returns> /// <c>true</c> if the fixture is ignored; otherwise, <c>false</c>. /// </returns> public bool IsFixtureIgnored(FSFixture fixture) { if (_collisionIgnores == null) return false; if (_collisionIgnores.ContainsKey(fixture.FixtureId)) return _collisionIgnores[fixture.FixtureId]; return false; }
/// <summary> /// Restores collisions between this fixture and the provided fixture. /// </summary> /// <param name="fixture">The fixture.</param> public void RestoreCollisionWith(FSFixture fixture) { if (_collisionIgnores == null) return; if (_collisionIgnores.ContainsKey(fixture.FixtureId)) { _collisionIgnores[fixture.FixtureId] = false; Refilter(); } }
//Cutting a shape into two is based on the work of Daid and his prototype BoxCutter: http://www.box2d.org/forum/viewtopic.php?f=3&t=1473 /// <summary> /// Split a fixture into 2 vertice collections using the given entry and exit-point. /// </summary> /// <param name="fixture">The Fixture to split</param> /// <param name="entryPoint">The entry point - The start point</param> /// <param name="exitPoint">The exit point - The end point</param> /// <param name="splitSize">The size of the split. Think of this as the laser-width</param> /// <param name="first">The first collection of vertexes</param> /// <param name="second">The second collection of vertexes</param> public static void SplitShape(FSFixture fixture, FVector2 entryPoint, FVector2 exitPoint, float splitSize, out Vertices first, out Vertices second) { FVector2 localEntryPoint = fixture.Body.GetLocalPoint(ref entryPoint); FVector2 localExitPoint = fixture.Body.GetLocalPoint(ref exitPoint); PolygonShape shape = fixture.Shape as PolygonShape; if (shape == null) { first = new Vertices(); second = new Vertices(); return; } Vertices vertices = new Vertices(shape.Vertices); Vertices[] newPolygon = new Vertices[2]; for (int i = 0; i < newPolygon.Length; i++) { newPolygon[i] = new Vertices(vertices.Count); } int[] cutAdded = { -1, -1 }; int last = -1; for (int i = 0; i < vertices.Count; i++) { int n; //Find out if this vertex is on the old or new shape. if (FVector2.Dot(MathUtils.Cross(localExitPoint - localEntryPoint, 1), vertices[i] - localEntryPoint) > FSSettings.Epsilon) n = 0; else n = 1; if (last != n) { //If we switch from one shape to the other add the cut vertices. if (last == 0) { Debug.Assert(cutAdded[0] == -1); cutAdded[0] = newPolygon[last].Count; newPolygon[last].Add(localExitPoint); newPolygon[last].Add(localEntryPoint); } if (last == 1) { Debug.Assert(cutAdded[last] == -1); cutAdded[last] = newPolygon[last].Count; newPolygon[last].Add(localEntryPoint); newPolygon[last].Add(localExitPoint); } } newPolygon[n].Add(vertices[i]); last = n; } //Add the cut in case it has not been added yet. if (cutAdded[0] == -1) { cutAdded[0] = newPolygon[0].Count; newPolygon[0].Add(localExitPoint); newPolygon[0].Add(localEntryPoint); } if (cutAdded[1] == -1) { cutAdded[1] = newPolygon[1].Count; newPolygon[1].Add(localEntryPoint); newPolygon[1].Add(localExitPoint); } for (int n = 0; n < 2; n++) { FVector2 offset; if (cutAdded[n] > 0) { offset = (newPolygon[n][cutAdded[n] - 1] - newPolygon[n][cutAdded[n]]); } else { offset = (newPolygon[n][newPolygon[n].Count - 1] - newPolygon[n][0]); } offset.Normalize(); newPolygon[n][cutAdded[n]] += splitSize * offset; if (cutAdded[n] < newPolygon[n].Count - 2) { offset = (newPolygon[n][cutAdded[n] + 2] - newPolygon[n][cutAdded[n] + 1]); } else { offset = (newPolygon[n][0] - newPolygon[n][newPolygon[n].Count - 1]); } offset.Normalize(); newPolygon[n][cutAdded[n] + 1] += splitSize * offset; } first = newPolygon[0]; second = newPolygon[1]; }
private static bool ShouldCollide(FSFixture fixtureA, FSFixture fixtureB) { if (FSSettings.UseFPECollisionCategories) { if ((fixtureA.CollisionGroup == fixtureB.CollisionGroup) && fixtureA.CollisionGroup != 0 && fixtureB.CollisionGroup != 0) return false; if (((fixtureA.CollisionCategories & fixtureB.CollidesWith) == Category.None) & ((fixtureB.CollisionCategories & fixtureA.CollidesWith) == Category.None)) return false; if (fixtureA.IsFixtureIgnored(fixtureB) || fixtureB.IsFixtureIgnored(fixtureA)) return false; return true; } if (fixtureA.CollisionGroup == fixtureB.CollisionGroup && fixtureA.CollisionGroup != 0) { return fixtureA.CollisionGroup > 0; } bool collide = (fixtureA.CollidesWith & fixtureB.CollisionCategories) != 0 && (fixtureA.CollisionCategories & fixtureB.CollidesWith) != 0; if (collide) { if (fixtureA.IsFixtureIgnored(fixtureB) || fixtureB.IsFixtureIgnored(fixtureA)) { return false; } } return collide; }
public FSFixture DeepClone() { FSFixture fix = Clone(Body.Clone()); return(fix); }
internal bool CompareTo(FSFixture fixture) { return ( CollidesWith == fixture.CollidesWith && CollisionCategories == fixture.CollisionCategories && CollisionGroup == fixture.CollisionGroup && Friction == fixture.Friction && IsSensor == fixture.IsSensor && Restitution == fixture.Restitution && Shape.CompareTo(fixture.Shape) && UserData == fixture.UserData && UserBits == fixture.UserBits ); }
/// <summary> /// Ignores collisions between this fixture and the provided fixture. /// </summary> /// <param name="fixture">The fixture.</param> public void IgnoreCollisionWith(FSFixture fixture) { if (_collisionIgnores == null) _collisionIgnores = new Dictionary<int, bool>(); if (_collisionIgnores.ContainsKey(fixture.FixtureId)) _collisionIgnores[fixture.FixtureId] = true; else _collisionIgnores.Add(fixture.FixtureId, true); Refilter(); }
// Broad-phase callback. private void AddPair(ref FixtureProxy proxyA, ref FixtureProxy proxyB) { FSFixture fixtureA = proxyA.Fixture; FSFixture fixtureB = proxyB.Fixture; int indexA = proxyA.ChildIndex; int indexB = proxyB.ChildIndex; FSBody bodyA = fixtureA.Body; FSBody bodyB = fixtureB.Body; // Are the fixtures on the same body? if (bodyA == bodyB) { return; } // Does a contact already exist? ContactEdge edge = bodyB.ContactList; while (edge != null) { if (edge.Other == bodyA) { FSFixture fA = edge.Contact.FixtureA; FSFixture fB = edge.Contact.FixtureB; int iA = edge.Contact.ChildIndexA; int iB = edge.Contact.ChildIndexB; if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB) { // A contact already exists. return; } if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA) { // A contact already exists. return; } } edge = edge.Next; } // Does a joint override collision? Is at least one body dynamic? if (bodyB.ShouldCollide(bodyA) == false) { return; } //Check default filter if (ShouldCollide(fixtureA, fixtureB) == false) { return; } // Check user filtering. if (ContactFilter != null && ContactFilter(fixtureA, fixtureB) == false) { return; } if (fixtureA.BeforeCollision != null && fixtureA.BeforeCollision(fixtureA, fixtureB) == false) { return; } if (fixtureB.BeforeCollision != null && fixtureB.BeforeCollision(fixtureB, fixtureA) == false) { return; } // Call the factory. Contact c = Contact.Create(fixtureA, indexA, fixtureB, indexB); // Contact creation may swap fixtures. fixtureA = c.FixtureA; fixtureB = c.FixtureB; bodyA = fixtureA.Body; bodyB = fixtureB.Body; // Insert into the world. ContactList.Add(c); #if USE_ACTIVE_CONTACT_SET ActiveContacts.Add(c); #endif // Connect to island graph. // Connect to body A c.NodeA.Contact = c; c.NodeA.Other = bodyB; c.NodeA.Prev = null; c.NodeA.Next = bodyA.ContactList; if (bodyA.ContactList != null) { bodyA.ContactList.Prev = c.NodeA; } bodyA.ContactList = c.NodeA; // Connect to body B c.NodeB.Contact = c; c.NodeB.Other = bodyA; c.NodeB.Prev = null; c.NodeB.Next = bodyB.ContactList; if (bodyB.ContactList != null) { bodyB.ContactList.Prev = c.NodeB; } bodyB.ContactList = c.NodeB; }