protected void TryToAdd(Collidable a, Collidable b, Material materialA, Material materialB) { CollisionRule rule; if ((rule = CollisionRules.collisionRuleCalculator(a, b)) < CollisionRule.NoNarrowPhasePair) { //Clamp the rule to the parent's rule. Always use the more restrictive option. //Don't have to test for NoNarrowPhasePair rule on the parent's rule because then the parent wouldn't exist! if (rule < CollisionRule) { rule = CollisionRule; } var pair = new CollidablePair(a, b); if (!subPairs.ContainsKey(pair)) { var newPair = NarrowPhaseHelper.GetPairHandler(ref pair, rule); if (newPair != null) { newPair.UpdateMaterialProperties(materialA, materialB); //Override the materials, if necessary. newPair.Parent = this; subPairs.Add(pair, newPair); } } containedPairs.Add(pair); } }
/// <summary> /// Finds contacts between the query object and any intersected objects within the character's bounding box. /// </summary> /// <param name="queryObject">Collidable to query for contacts with.</param> /// <param name="tractionContacts">Output contacts that would provide traction.</param> /// <param name="supportContacts">Output contacts that would provide support.</param> /// <param name="sideContacts">Output contacts on the sides of the query object.</param> /// <param name="headContacts">Output contacts on the head of the query object.</param> /// <param name="forceStandardPairsToBeQueries">An extremely hacky control parameter that makes any mesh-cylinder pair treat the mesh as double sided. Useful for not going through the ceiling when changing stances.</param> public void QueryContacts(EntityCollidable queryObject, ref QuickList <CharacterContact> tractionContacts, ref QuickList <CharacterContact> supportContacts, ref QuickList <CharacterContact> sideContacts, ref QuickList <CharacterContact> headContacts, bool forceStandardPairsToBeQueries = false) { var downDirection = characterBody.orientationMatrix.Down; tractionContacts.Clear(); supportContacts.Clear(); sideContacts.Clear(); headContacts.Clear(); foreach (var collidable in characterBody.CollisionInformation.OverlappedCollidables) { //The query object is assumed to have a valid bounding box. if (collidable.BoundingBox.Intersects(queryObject.BoundingBox)) { var pair = new CollidablePair(collidable, queryObject); var pairHandler = NarrowPhaseHelper.GetPairHandler(ref pair); if (pairHandler.CollisionRule == CollisionRule.Normal) { if (forceStandardPairsToBeQueries) { //TODO: This is a massive hack that assumes a fixed set of collidable types. This won't work in the long run. //The only reason it's here is that it was the easiest solution, combined with the fact that the character has to be rewritten for v2 anyway. //Hopefully no one gets bit by this before the replacement is available. //The core reason it exists is that one sided meshes don't generate contacts on their backside. That means a query shape can end up above a ceiling //and it won't detect the ceiling. A better solution would be to let the caller choose whether or not to filter the contacts, and then use a //direct test rather than stateful pair to perform the query here. Still some type-related annoyance to deal with, but a bit better. var standardPair = pairHandler as StandardPairHandler; if (standardPair != null) { standardPair.ContactManifold.IsQuery = true; } } pairHandler.SuppressEvents = true; pairHandler.UpdateCollision(0); pairHandler.SuppressEvents = false; if (forceStandardPairsToBeQueries) { //TODO: Again, superhack! Avoid this in v2. var standardPair = pairHandler as StandardPairHandler; if (standardPair != null) { standardPair.ContactManifold.IsQuery = false; } } contactCategorizer.CategorizeContacts(pairHandler, characterBody.CollisionInformation, ref downDirection, ref tractionContacts, ref supportContacts, ref sideContacts, ref headContacts); } //TODO: It would be nice if this was a bit easier. //Having to remember to clean up AND give it back is a bit weird, especially with the property-diving. //No one would ever just guess this correctly. //At least hide it behind a NarrowPhaseHelper function. pairHandler.CleanUp(); pairHandler.Factory.GiveBack(pairHandler); } } }
/// <summary> /// Tests the pair of collidables for intersection without regard for collision rules. /// </summary> /// <param name="pair">Pair to test.</param> /// <returns>Whether or not the pair is intersecting.</returns> public static bool Intersecting(ref CollidablePair pair) { var pairHandler = GetPairHandler(ref pair); if (pairHandler == null) { return(false); } pairHandler.SuppressEvents = true; pairHandler.UpdateCollision(0); bool toReturn = pairHandler.Colliding; pairHandler.SuppressEvents = false; pairHandler.CleanUp(); pairHandler.Factory.GiveBack(pairHandler); return(toReturn); }
protected void TryToAdd(int index) { var entry = new TriangleEntry { Index = index }; if (!subPairs.ContainsKey(entry)) { var collidablePair = new CollidablePair(CollidableA, entry.Collidable = GetOpposingCollidable(index)); var newPair = (MobileMeshPairHandler)NarrowPhaseHelper.GetPairHandler(ref collidablePair); if (newPair != null) { newPair.CollisionRule = CollisionRule; newPair.UpdateMaterialProperties(MaterialA, MaterialB); //Override the materials, if necessary. Meshes don't currently support custom materials but.. newPair.Parent = this; subPairs.Add(entry, newPair); } } containedPairs.Add(entry); }
/// <summary> /// Gets a collidable pair handler for a pair of collidables. /// </summary> /// <param name="pair">Pair of collidables to use to create the pair handler.</param> /// <returns>CollidablePairHandler for the pair.</returns> public static CollidablePairHandler GetPairHandler(ref CollidablePair pair) { var overlap = new BroadPhaseOverlap(pair.collidableA, pair.collidableB); return(GetPairHandler(ref overlap) as CollidablePairHandler); }