/// <summary> /// Check for collisions with terrain or other organisms /// Build a list of unique possible collision targets (tiles or other organisms) using the quad tree. /// Initially, just check quickly to see if we are in any danger of hitting any of them. Cull those that /// are definitely irrelevant, then look more closely. /// </summary> private void CheckForCollisions() { Renderable[] candidate = new Renderable[2000]; int numCandidates = 0; // Don't bother if we're an organism with no physics (e.g. the lab) - things can collide with us but not us with them if (Dynamic == false) return; // Search our list of quads and extract tiles or organisms that we share a bottom-level quad with. // Bottom level quads are enough, because no part of us extends beyond this/these. foreach (Map quad in myMaps) { if (quad.Level == Map.NumLevels-1) // Only search smallest quad or quads { foreach (Renderable target in quad.OrganismList) // look at each ORGANISM in quad { if (target==this) // ignore self!!! continue; bool found = false; for (int i=0; i<numCandidates; i++) // if this object isn't already in our list... { if (candidate[i]==target) { found=true; break; } } if (found==false) candidate[numCandidates++] = target; // ...add it } foreach (Renderable target in quad.TerrainList) // look at each TILE in quad { bool found = false; for (int i=0; i<numCandidates; i++) // if this object isn't already in our list... { if (candidate[i]==target) { found=true; break; } } if (found==false) candidate[numCandidates++] = target; // ...add it } } } // Now cull those that are definitely not a risk because their bounding sphere doesn't intersect ours for (int i=0; i<numCandidates; i++) { // How far, if at all, do we penetrate the candidate if (this.AbsSphere.IsPenetrating(candidate[i].AbsSphere)==false) candidate[i] = null; } // Now we're left with objects whose bounding spheres overlap ours, so examine them more closely. for (int i=0; i<numCandidates; i++) { if (candidate[i]!=null) { CheckForCollisions2(candidate[i]); } } }
/// <summary> /// Second-level collision detection. The supplied object's bounding sphere overlaps with ours. /// Drop down to the cell level and look more closely /// </summary> /// <param name="obj"></param> private void CheckForCollisions2(Renderable candidate) { // For each of our cells, look to see if it collides with ANY part of the candidate. foreach (Cell cell in partList) { // Do we penetrate the candidate at all? if (cell.AbsSphere.IsPenetrating(candidate.AbsSphere)) { // Call the target class's virtual method to test more precisely and return any collision force cell.propulsionForce += candidate.CollisionTest(cell); /// *Scene.ElapsedTime * 100f; } } }
/// <summary> /// Add a Renderable object to the batch /// </summary> /// <param name="newObj"></param> public void Add(Renderable newObj) { for (int i=0; i<batch.Count; i++) { if (batch[i].DistSq <= newObj.DistSq) { batch.Insert(i,newObj); return; } } batch.Add(newObj); }
/// <summary> /// Add a Renderable object to the batch with no depth sorting (for objects that don't need it) /// </summary> /// <param name="newObj"></param> public void AddUnsorted(Renderable newObj) { batch.Add(newObj); }
/// <summary> /// Overload of above to test whether a given 3D renderable object is within frustrum /// </summary> /// <param name="obj"></param> /// <returns></returns> public static int CanSee(Renderable obj) { return (CanSee(obj.AbsSphere.Centre,obj.AbsSphere.Radius, 6)); }
/// <summary> /// Recursively remove the object from this node and, if it was present, all relevant subnodes /// </summary> /// <param name="obj">reference to the object to remove</param> private void RecursiveDel(Renderable obj) { int found=-1; if (obj is Organism) found = organismList.IndexOf((Organism)obj); // search correct array for object else if (obj is Terrain) found = terrainList.IndexOf((Terrain)obj); else if (obj is Water) found = waterList.IndexOf((Water)obj); else found = sceneryList.IndexOf((Scenery)obj); if (found>=0) // if present at this node { if (level < NumLevels-1) { child[0].RecursiveDel(obj); // remove it from any child nodes child[1].RecursiveDel(obj); child[2].RecursiveDel(obj); child[3].RecursiveDel(obj); } if (obj is Organism) { organismList.RemoveAt(found); // delete the object from my list obj.DelMap(this); // and remove me to the object's own list } else if (obj is Terrain) { terrainList.RemoveAt(found); // delete the object from my list } else if (obj is Water) { waterList.RemoveAt(found); // delete the object from my list } else { sceneryList.RemoveAt(found); // delete the object from my list } } }
/// <summary> /// Recursively add an object to a node and its children (if it lies within bounds) /// </summary> /// <param name="obj"></param> private void RecursiveAdd(Renderable obj) { if (obj.IsIn(bounds)) // if the obj is within my boundary { if (obj is Organism) { organismList.Add((Organism)obj); // add the object to my Organism list obj.AddMap(this); // and add me to the object's own list } else if (obj is Terrain) { terrainList.Add((Terrain)obj); // add the object to my Terrain list } else if (obj is Water) { waterList.Add((Water)obj); // add the object to my Water list } else { sceneryList.Add((Scenery)obj); // add the object to my Scenery list } if (level < NumLevels-1) { child[0].RecursiveAdd(obj); // and recursively try my children child[1].RecursiveAdd(obj); // (if it isn't within my boundary child[2].RecursiveAdd(obj); // none of my children will contain child[3].RecursiveAdd(obj); // it either) } } }
/// <summary> /// Remove an object completely from the quadtree /// </summary> /// <remarks> /// Object should be Disposed of after this call, if no longer needed /// (while a reference to it still exists) /// </remarks> public static void Remove(Renderable obj) { root.RecursiveDel(obj); // remove from all relevant nodes //Engine.EventHUD.WriteLine("Obj removed from quadtree: "+obj); }
/// <summary> /// Add an object to the quadtree /// </summary> /// <remarks>Object gets added to every node in the tree that bounds it</remarks> public static void Add(Renderable obj) { root.RecursiveAdd(obj); //Engine.EventHUD.WriteLine(String.Format("Obj {0} added to quadtree",root.objects.Count)); }