# 在2D空间中使用四叉树实现碰撞检测

## 使用四叉树

``````public class Quadtree {

private int MAX_OBJECTS = 10;
private int MAX_LEVELS = 5;

private int level;
private List objects;
private Rectangle bounds;

/*
* Constructor
*/
public Quadtree(int pLevel, Rectangle pBounds) {
level = pLevel;
objects = new ArrayList();
bounds = pBounds;
}
}
``````

``````/*
*/
public void clear() {
objects.clear();

for (int i = 0; i < nodes.length; i++) {
if (nodes[i] != null) {
nodes[i].clear();
nodes[i] = null;
}
}
}
``````

Clear函数，是通过递归来清除四叉树所有节点的所有对象。

``````/*
* Splits the node into 4 subnodes
*/
private void split() {
int subWidth = (int)(bounds.getWidth() / 2);
int subHeight = (int)(bounds.getHeight() / 2);
int x = (int)bounds.getX();
int y = (int)bounds.getY();

nodes[0] = new Quadtree(level+1, new Rectangle(x + subWidth, y, subWidth, subHeight));
nodes[1] = new Quadtree(level+1, new Rectangle(x, y, subWidth, subHeight));
nodes[2] = new Quadtree(level+1, new Rectangle(x, y + subHeight, subWidth, subHeight));
nodes[3] = new Quadtree(level+1, new Rectangle(x + subWidth, y + subHeight, subWidth, subHeight));
}
``````

Split方法，就是用来将节点分成相等的四份面积，并用新的边界来初始化四个新的子节点。

``````/*
* Determine which node the object belongs to. -1 means
* object cannot completely fit within a child node and is part
* of the parent node
*/
private int getIndex(Rectangle pRect) {
int index = -1;
double verticalMidpoint = bounds.getX() + (bounds.getWidth() / 2);
double horizontalMidpoint = bounds.getY() + (bounds.getHeight() / 2);

// Object can completely fit within the top quadrants
boolean topQuadrant = (pRect.getY() < horizontalMidpoint && pRect.getY() + pRect.getHeight() < horizontalMidpoint);
// Object can completely fit within the bottom quadrants
boolean bottomQuadrant = (pRect.getY() > horizontalMidpoint);

// Object can completely fit within the left quadrants
if (pRect.getX() < verticalMidpoint && pRect.getX() + pRect.getWidth() < verticalMidpoint) {
index = 1;
}
index = 2;
}
}
// Object can completely fit within the right quadrants
else if (pRect.getX() > verticalMidpoint) {
index = 0;
}
index = 3;
}
}

return index;
}
``````

getIndex方法是个四叉树的辅助方法，在四叉树里，他决定了一个节点的归属，通过检查节点属于哪个象限。（最上面第一幅图不是顺时针在一个面积里划分了四块面积，上面标示了他们的序号，这个方法就是算在一个父节点里他的子节点的序号）

``````/*
* Insert the object into the quadtree. If the node
* exceeds the capacity, it will split and add all
* objects to their corresponding nodes.
*/
public void insert(Rectangle pRect) {
if (nodes[0] != null) {
int index = getIndex(pRect);

if (index != -1) {
nodes[index].insert(pRect);

return;
}
}

if (objects.size() > MAX_OBJECTS && level < MAX_LEVELS) {
split();

int i = 0;
while (i < objects.size()) {
int index = getIndex(objects.get(i));
if (index != -1) {
nodes[index].insert(objects.remove(i));
}
else {
i++;
}
}
}
}
``````

Insert方法，是将节点聚合在一起的方法。方法首先判断是否有父节点，然后将这个子节点插入父节点的某一序号的孩子上。如果没有子节点，或者这个节点的所属面积不属于任何一个子节点的所属面积，那就将它加入父节点。

``````/*
* Return all objects that could collide with the given object
*/
public List retrieve(List returnObjects, Rectangle pRect) {
int index = getIndex(pRect);
if (index != -1 && nodes[0] != null) {
nodes[index].retrieve(returnObjects, pRect);
}

return returnObjects;
}
``````

## 用这个类来进行2D碰撞检测

``````Quadtree quad = new Quadtree(0, new Rectangle(0,0,600,600));
``````

``````quad.clear();
for (int i = 0; i < allObjects.size(); i++) {
}
``````

``````List returnObjects = new ArrayList();
for (int i = 0; i < allObjects.size(); i++) {
returnObjects.clear();

for (int x = 0; x < returnObjects.size(); x++) {
// Run collision detection algorithm between objects
}
}
``````