/// <summary> /// Finds a supporting entity, the contact location, and the contact normal. /// </summary> /// <param name="location">Contact point between the wheel and the support.</param> /// <param name="normal">Contact normal between the wheel and the support.</param> /// <param name="suspensionLength">Length of the suspension at the contact.</param> /// <param name="entity">Supporting object.</param> /// <param name="material">Material of the wheel.</param> /// <returns>Whether or not any support was found.</returns> protected internal override bool FindSupport(out Vector3 location, out Vector3 normal, out float suspensionLength, out Entity entity, out Material material) { suspensionLength = float.MaxValue; location = Toolbox.NoVector; entity = null; normal = Toolbox.NoVector; material = null; Collidable testCollider; RayHit rayHit; bool hit = false; for (int i = 0; i < detector.CollisionInformation.pairs.Count; i++) { NarrowPhasePair pair = detector.CollisionInformation.pairs[i]; testCollider = (pair.BroadPhaseOverlap.entryA == detector.CollisionInformation ? pair.BroadPhaseOverlap.entryB : pair.BroadPhaseOverlap.entryA) as Collidable; if (testCollider != null) { if (CollisionRules.CollisionRuleCalculator(CollisionRules, testCollider.collisionRules) == CollisionRule.Normal && testCollider.RayCast(new Ray(wheel.suspension.worldAttachmentPoint, wheel.suspension.worldDirection), wheel.suspension.restLength, out rayHit) && rayHit.T < suspensionLength) { suspensionLength = rayHit.T; EntityCollidable entityCollisionInfo; if ((entityCollisionInfo = testCollider as EntityCollidable) != null) { entity = entityCollisionInfo.Entity; material = entityCollisionInfo.Entity.Material; } else { entity = null; var materialOwner = testCollider as IMaterialOwner; if (materialOwner != null) { material = materialOwner.Material; } } location = rayHit.Location; normal = rayHit.Normal; hit = true; } } } if (hit) { if (suspensionLength > 0) { normal.Normalize(); } else { Vector3.Negate(ref wheel.suspension.worldDirection, out normal); } return(true); } return(false); }
protected void OnCreatePair(NarrowPhasePair pair) { overlapMapping.Add(pair.BroadPhaseOverlap, pair); pair.OnAddedToNarrowPhase(); if (CreatingPair != null) CreatingPair(pair); }
protected void OnRemovePair(NarrowPhasePair pair) { overlapMapping.Remove(pair.BroadPhaseOverlap); pair.CleanUp(); pair.Factory.GiveBack(pair); if (RemovingPair != null) { RemovingPair(pair); } }
void RemoveFriction(EntityCollidable sender, BroadPhaseEntry other, NarrowPhasePair pair) { var collidablePair = pair as CollidablePairHandler; if (collidablePair != null) { //The default values for InteractionProperties is all zeroes- zero friction, zero bounciness. //That's exactly how we want the character to behave when hitting objects. collidablePair.UpdateMaterialProperties(new InteractionProperties()); } }
public void OnPairUpdated(BroadPhaseEntry other, NarrowPhasePair collisionPair) { if (InternalPairUpdated != null) { eventStoragePairUpdated.Enqueue(new EventStoragePairUpdated(other, collisionPair)); } if (PairUpdating != null) { PairUpdating(owner, other, collisionPair); } }
private void RemoveStaleOverlaps() { //Remove stale objects. for (int i = narrowPhasePairs.Count - 1; i >= 0; i--) { NarrowPhasePair pair = narrowPhasePairs.Elements[i]; //A stale overlap is a pair which has not been updated, but not because of inactivity. //Pairs between two inactive shapes are not updated because the broad phase does not output overlaps //between inactive entries. We need to keep such pairs around, otherwise when they wake up, lots of extra work //will be needed and quality will suffer. //The classic stale overlap is two objects which have moved apart. Because the bounding boxes no longer overlap, //the broad phase does not generate an overlap for them. Obviously, we should get rid of such a pair. //Any such pair will have at least one active member. Having velocity requires activity and teleportation will activate the object. //There's another sneaky kind of stale overlap. Consider a sleeping dynamic object on a Terrain. The Terrain, being a static object, //is considered inactive. The sleeping dynamic object is also inactive. Now, remove the sleeping dynamic object. //Both objects are still considered inactive. But the pair is clearly stale- one of its members doesn't even exist anymore! //This has nasty side effects, like retaining memory. To solve this, also check to see if either member does not belong to the simulation. if (pair.NeedsUpdate && //If we didn't receive an update in the previous narrow phase run and... (pair.broadPhaseOverlap.entryA.IsActive || pair.broadPhaseOverlap.entryB.IsActive || //one of us is active or.. pair.broadPhaseOverlap.entryA.BroadPhase == null || pair.broadPhaseOverlap.entryB.BroadPhase == null)) //one of us doesn't exist anymore... { //Get rid of the pair! if (RemovingPair != null) { RemovingPair(pair); } narrowPhasePairs.FastRemoveAt(i); overlapMapping.Remove(pair.BroadPhaseOverlap); //The clean up will issue an order to get rid of the solver updateable if it is active. pair.CleanUp(); pair.Factory.GiveBack(pair); } else { pair.NeedsUpdate = true; } } }
///<summary> /// Gets a narrow phase pair for a given broad phase overlap. ///</summary> ///<param name="pair">Overlap to use to create the pair.</param> ///<returns>A INarrowPhasePair for the overlap.</returns> public static NarrowPhasePair GetPairHandler(ref BroadPhaseOverlap pair) { NarrowPhasePairFactory factory; if (collisionManagers.TryGetValue(new TypePair(pair.entryA.GetType(), pair.entryB.GetType()), out factory)) { var toReturn = factory.GetNarrowPhasePair(); toReturn.BroadPhaseOverlap = pair; toReturn.Factory = factory; return(toReturn); } //Convex-convex collisions are a pretty significant chunk of all tests, so rather than defining them all, just have a fallback. var a = pair.entryA as ConvexCollidable; var b = pair.entryB as ConvexCollidable; if (a != null && b != null) { NarrowPhasePair toReturn = Factories.ConvexConvex.GetNarrowPhasePair(); toReturn.BroadPhaseOverlap = pair; toReturn.Factory = Factories.ConvexConvex; return(toReturn); } return(null); }
internal EventStoragePairUpdated(BroadPhaseEntry other, NarrowPhasePair pair) { this.other = other; this.pair = pair; }
/// <summary> /// Returns a pair to the factory for re-use. /// </summary> /// <param name="pair">Pair to return.</param> public abstract void GiveBack(NarrowPhasePair pair);
private void OnCollisionPairCreated(EntityCollidable sender, BroadPhaseEntry other, NarrowPhasePair pair) { if (!(other.Tag is Collider)) { Console.WriteLine("ERROR: TAG WAS NOT COLLIDER."); } else { Collider otherCollider = (Collider)other.Tag; TriggerEntered?.Invoke(otherCollider); } }