/// /// The CollisionTreeNode class replaces the OctreeNode class in a CollisionTree. In addition to the /// spatial definition of the OctreeNode, the CollisionTreeNode stores a list of CollideableElements /// which are at least partially inside the space of this node. This allows the tree to be quickly searched /// for CollideableElements by their spatial locations. /// public class CollisionTreeNode : OctreeNode { /* * CLASS PROPERTIES */ /// /// list with elements included in the node (only created on leaf nodes) /// private List elems; /* * CONSTRUCTOR */ /// /// Recursive constructor to create a new /// collision tree node and children. /// /// A collision tree object that is the root of the tree /// the collision tree node that is the parent to this one /// the TwelveCylinderGame object /// the collision box that defines the new tree node /// an array of bools indicating if each element in the newElems array was contained by the parent tree node /// the collideable element array that is contained by this tree /// the current depth in the tree of this node /// the subdivision level of the new tree node where 0 is a leaf node public CollisionTreeNode(Octree newTree, OctreeNode newParent, TwelveCylinderGame newGame, Bounds box, bool[] possibleElems, CollideableElement[] newElems, uint depth, uint maxDivisions) : base(newTree, newParent, newGame, box, depth) { uint numElements = 0; // if subdivision needed if (depth < maxDivisions) { bool[] contained = new bool[newElems.Length]; for (int i = 0; i < newElems.Length; i++) { if (!possibleElems[i]) contained[i] = false; //parent doesn't contain the element else if (newElems[i].box.BoxOverlap(box)) { contained[i] = true; //this tree node contains the element numElements++; } else contained[i] = false; //this tree node does not contain the element } // if collision tree node contains one or zero // collideable elements we can stop subdivision if (numElements == 1) { for (int i = 0; i < contained.Length; i++) if (contained[i]) { this.AddElement(newElems[i]); //add the one element and stop return; } } else if (numElements == 0) return; //no elements in the node, we can stop subdivide(contained, newElems, maxDivisions); } else { //add collideable elements to leaf node for (int i = 0; i < newElems.Length; i++) { if (possibleElems[i]) this.AddElement(newElems[i]); } } } /* * METHODS */ /// /// subdivides this collision octree node into 8 children /// /// the array of bools that describe which collideable elements are contained by this tree node1 /// the elements being added to the tree /// the maximum subdivision level to drill down to public virtual void subdivide(bool[] possibleElems, CollideableElement[] newElems, uint maxDivisions) { uint childDepth = treeLevel + 1; // create the 8 children children = new CollisionTreeNode[NUM_TREE_CHILDREN]; //octree subdivisons Bounds[] childrenBox = getChildNodeBounds(); // increment subdivision level and create new tree nodes for (uint i = 0; i < NUM_TREE_CHILDREN; i++) children[i] = new CollisionTreeNode(curTree, this, curGame, childrenBox[i], possibleElems, newElems, childDepth, maxDivisions); } /* * COLLIDABLE ELEMENT LIST */ /// /// recursive method to add a collidable element to the tree /// /// the collideable element to add to the tree public void AddElement(CollideableElement newElem) { // if element do not intersect node, return if (newElem.box.BoxOverlap(box) == false) return; if (children == null) { //only add collidable elements to leaf nodes... if (elems == null) //if no elements list, add one elems = new List(); // add element to list elems.Add(newElem); newElem.AddTreeNode(this); } else { // if not a leaf recurse to all its children foreach (CollisionTreeNode child in children) child.AddElement(newElem); } } /// /// removes a collidable element from this node /// /// the collideable element to remove public void RemoveElement(CollideableElement e) { if (elems != null) elems.Remove(e); } /// /// Recursive function to get all elements /// that intersect the specified bounding box. /// /// the output list of elements with intersecting bounding boxes /// the bounding box to test for intersection /// the ID representing the current iteration of the element search function. It prevents redudant entries in the element list public void GetElements(Bounds testBox, ref List elemList, uint searchCount) { // if selection box does not intersect node box, return if (!testBox.BoxOverlap(box)) return; //test box does not overlap with tree node's box if (elems != null) { //leaf node that contains elements foreach (CollideableElement elem in elems) { // elements can be repeated in many nodes // only add element to selection list if not already // added by another node in this same recursion if (elem.LastSearchId < searchCount) { // if selection box intersect the element box if (elem.box.BoxOverlap(testBox)) elemList.Add(elem); // add element to selection list // set this recuse id to prevent duplicate results elem.LastSearchId = searchCount; } } } else if (children != null) { // if not a leaf node, recurse to all children foreach (CollisionTreeNode child in children) child.GetElements(testBox, ref elemList, searchCount); } } /// /// recursively gets all elements in the tree /// /// the output list of elements /// the recusion search id public void GetAllElements(ref List elemList, uint searchCount) { if (elems != null) { //leaf node that contains elements foreach (CollideableElement elem in elems) { // elements can be repeated in many nodes // only add element to selection list if not already // added by another node in this same recursion if (elem.LastSearchId < searchCount) { elemList.Add(elem); // add element to selection list // set this recuse id to prevent duplicate results elem.LastSearchId = searchCount; } } } else if (children != null) { // if not a leaf node, recurse to all children foreach (CollisionTreeNode child in children) child.GetAllElements(ref elemList, searchCount); } } }