/// /// The root of an octree that uses CollisionTreeNode objects instead of OctreeNodes /// to create spatial organization for optimizing collision detection. /// public class CollisionTree : Octree { /* * CLASS PROPERTIES */ /// /// The last recurse id used for element searches. /// This is used for preventing duplicates from occuring. /// private uint searchCount; /// /// the root node as a collision tree node /// CollisionTreeNode collisionRoot; /* * CONSTRUCTOR */ /// /// constructor for a new collision octree /// /// the game object /// the top level collision box that contains the entire tree /// the array of collideable elements to be organized by the tree /// the maximum depth to divide the tree /// a threshold that will prevent the trees leaf nodes /// from being subdivided smaller than this volume, or zero to ignore this feature. public CollisionTree(TwelveCylinderGame newGame, string newName, Bounds box, CollideableElement[] newElems, uint maxDepth, float minLeafVolume) : base(newGame, newName, box) { DateTime start = DateTime.Now; //array of all true bool[] allTrue = new bool[newElems.Length]; for (int i = 0; i < allTrue.Length; i++) allTrue[i] = true; treeDepth = GetNewMaxDepth(box.Volume, minLeafVolume, maxDepth); //recursively create tree node hierarchy collisionRoot = new CollisionTreeNode(this, null, curGame, box, allTrue, newElems, 0, treeDepth); root = collisionRoot; //random tree color root.TreeColor = curGame.RandomGenerator.GetNextPalletteColor(); updateTreeData(); searchCount = 0; DateTime end = DateTime.Now; //printTreeData(end - start); } /* * COLLIDEABLE ELEMENT LISTS */ /// /// adds a new collideable element to the collision tree /// /// the element to add to the tree public void AddElement(CollideableElement newElem) { collisionRoot.AddElement(newElem); } /// /// removes the specified collideable element from the collision tree /// /// the element to remove from the tree public void RemoveElement(CollideableElement xElem) { collisionRoot.RemoveElement(xElem); } /// /// updates which tree nodes the element is in /// /// an element that may already be in the tree public void UpdateElement(CollideableElement elem) { elem.RemoveFromAllNodes(); collisionRoot.AddElement(elem); } /// /// gets the collideable elements that intersect /// with the specified bounding box /// /// a box to test for collisions /// the output list of collideable elements public void GetElements(Bounds testBox, ref List elements) { collisionRoot.GetElements(testBox, ref elements, searchCount++); } /// /// gets all collideable elements currently in the tree /// /// the output list of elements public void GetAllElements(ref List elements) { collisionRoot.GetAllElements(ref elements, searchCount++); } /* * BOX INTERSECT */ /// /// Find the first (if any) collision between the specified moving /// collision box and the collideable elements in this tree. /// /// the box to check for collisions defined in the world coordinate system /// output distance from starting position to collision point /// output position at which the collision occured /// output normal of the surface that the box collided with /// returns true if an intersection occured public bool BoxIntersect(MovingBoxData boxData, out float collisionDistance, out Vector3 collisionPosition, out Vector3 collisionNormal) { //default output of no interesection collisionDistance = boxData.OffsetLength; collisionPosition = boxData.WorldEnd; collisionNormal = Vector3.Zero; //get the list of collideable elements that the box may have collided with List elems = new List(); collisionRoot.GetElements(boxData.ColliderVolume, ref elems, searchCount++); bool collided = false; float distance; Vector3 position; Vector3 normal; //check for collision between moving box and collideable elements foreach (CollideableElement elem in elems) { if (elem.BoxIntersect(boxData, out distance, out position, out normal)) { //intersection found if (distance < collisionDistance) { //current intersect distance is less than previous collisionDistance = distance; collisionPosition = position; collisionNormal = normal; collided = true; } } } return collided; } }