/// <summary> /// Applies buoyancy forces to appropriate objects. /// Called automatically when needed by the owning Space. /// </summary> /// <param name="dt">Time since last frame in physical logic.</param> void IDuringForcesUpdateable.Update(float dt) { QueryAccelerator.GetEntries(boundingBox, broadPhaseEntries); //TODO: Could integrate the entire thing into the collision detection pipeline. Applying forces //in the collision detection pipeline isn't allowed, so there'd still need to be an Updateable involved. //However, the broadphase query would be eliminated and the raycasting work would be automatically multithreaded. this.dt = dt; //Don't always multithread. For small numbers of objects, the overhead of using multithreading isn't worth it. //Could tune this value depending on platform for better performance. if (broadPhaseEntries.Count > 30 && ParallelLooper != null && ParallelLooper.ThreadCount > 1) { ParallelLooper.ForLoop(0, broadPhaseEntries.Count, analyzeCollisionEntryDelegate); } else { for (int i = 0; i < broadPhaseEntries.Count; i++) { AnalyzeEntry(i); } } broadPhaseEntries.Clear(); }
/// <summary> /// Updates the listing of contained entities and their states after the end of a space update. /// </summary> /// <param name="dt">Time since last frame in simulation seconds.</param> void IEndOfTimeStepUpdateable.Update(float dt) { //Get rid of any entities that are no longer nearby. foreach (Entity e in nearbyEntities.Keys) { if (!(e.CollisionInformation.BoundingBox.Intersects(TriangleMesh.Tree.BoundingBox))) { entities.Add(e); } } for (int i = 0; i < entities.count; i++) { var e = entities.Elements[i]; if (nearbyEntities[e].IsContained) { //STOPS CONTAINED event if (VolumeStopsContainingEntity != null) { VolumeStopsContainingEntity(this, e); } } if (nearbyEntities[e].IsTouching) { //STOPS TOUCHING event if (EntityStopsTouching != null) { EntityStopsTouching(e, this); } } nearbyEntities.Remove(e); } entities.Clear(); //Get an updated look at all included entities. QueryAccelerator.GetEntries(TriangleMesh.Tree.BoundingBox, entries); for (int i = 0; i < entries.count; i++) { var e = entries.Elements[i] as EntityCollidable; if (e != null && CollisionRules.collisionRuleCalculator(e.collisionRules, collisionRules) <= CollisionRule.NoSolver) { entities.Add(e.Entity); } } entries.Clear(); ContainmentState containmentState; for (int i = 0; i < entities.count; i++) { var e = entities.Elements[i]; bool isContained; bool isTouching = IsEntityIntersectingVolume(e, out isContained); if (nearbyEntities.TryGetValue(e, out containmentState)) { if (!containmentState.IsTouching && isTouching) { //BEGIN TOUCHING event if (EntityBeginsTouching != null) { EntityBeginsTouching(e, this); } } else if (containmentState.IsTouching && !isTouching) { //END TOUCHING event if (EntityStopsTouching != null) { EntityStopsTouching(e, this); } } if (!containmentState.IsContained && isContained) { //BEGIN CONTAINED event if (VolumeBeginsContainingEntity != null) { VolumeBeginsContainingEntity(this, e); } } else if (containmentState.IsContained && !isContained) { //END CONTAINED event if (VolumeStopsContainingEntity != null) { VolumeStopsContainingEntity(this, e); } } nearbyEntities[e] = new ContainmentState(isTouching, isContained); } else { //Add new entry for the new entity. nearbyEntities.Add(e, new ContainmentState(isTouching, isContained)); if (isTouching) { //BEGIN TOUCHING event if (EntityBeginsTouching != null) { EntityBeginsTouching(e, this); } } if (isContained) { //BEGIN CONTAINED event if (VolumeBeginsContainingEntity != null) { VolumeBeginsContainingEntity(this, e); } } } } entities.Clear(); }