///
/// 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;
}
}