# 在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
}
}
``````

## 总结：

• 序言：七十年代末，一起剥皮案震惊了整个滨河市，随后出现的几起案子，更是在滨河造成了极大的恐慌，老刑警刘岩，带你破解...
沈念sama阅读 78,954评论 1 174
• 序言：滨河连续发生了三起死亡事件，死亡现场离奇诡异，居然都是意外死亡，警方通过查阅死者的电脑和手机，发现死者居然都...
沈念sama阅读 26,937评论 1 143
• 文/潘晓璐 我一进店门，熙熙楼的掌柜王于贵愁眉苦脸地迎上来，“玉大人，你说我怎么就摊上这事。” “怎么了？”我有些...
开封第一讲书人阅读 30,608评论 0 102
• 文/不坏的土叔 我叫张陵，是天一观的道长。 经常有香客问我，道长，这世上最难降的妖魔是什么？ 我笑而不...
开封第一讲书人阅读 16,804评论 0 87
• 正文 为了忘掉前任，我火速办了婚礼，结果婚礼上，老公的妹妹穿的比我还像新娘。我一直安慰自己，他们只是感情好，可当我...
茶点故事阅读 22,088评论 0 144
• 文/花漫 我一把揭开白布。 她就那样静静地躺着，像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上，一...
开封第一讲书人阅读 18,155评论 0 87
• 那天，我揣着相机与录音，去河边找鬼。 笑死，一个胖子当着我的面吹牛，可吹牛的内容都是我干的。 我是一名探鬼主播，决...
沈念sama阅读 10,931评论 2 162
• 文/苍兰香墨 我猛地睁开眼，长吁一口气：“原来是场噩梦啊……” “哼！你这毒妇竟也来了？” 一声冷哼从身侧响起，我...
开封第一讲书人阅读 10,360评论 0 78
• 想象着我的养父在大火中拼命挣扎，窒息，最后皮肤化为焦炭。我心中就已经是抑制不住地欢快，这就叫做以其人之道，还治其人...
爱写小说的胖达阅读 8,879评论 5 112
• 序言：老挝万荣一对情侣失踪，失踪者是张志新（化名）和其女友刘颖，没想到半个月后，有当地人在树林里发现了一具尸体，经...
沈念sama阅读 12,142评论 0 130
• 正文 独居荒郊野岭守林人离奇死亡，尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
茶点故事阅读 10,900评论 1 126
• 正文 我和宋清朗相恋三年，在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
茶点故事阅读 11,710评论 0 129
• 白月光回国，霸总把我这个替身辞退。还一脸阴沉的警告我。[不要出现在思思面前， 不然我有一百种方法让你生不如死。]我...
爱写小说的胖达阅读 6,538评论 0 17
• 序言：一个原本活蹦乱跳的男人离奇死亡，死状恐怖，灵堂内的尸体忽然破棺而出，到底是诈尸还是另有隐情，我是刑警宁泽，带...
沈念sama阅读 9,326评论 2 116
• 正文 年R本政府宣布，位于F岛的核电站，受9级特大地震影响，放射性物质发生泄漏。R本人自食恶果不足惜，却给世界环境...
茶点故事阅读 12,452评论 3 124
• 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹，春花似锦、人声如沸。这庄子的主人今日做“春日...
开封第一讲书人阅读 8,173评论 0 3
• 文/苍兰香墨 我抬头看了看天上的太阳。三九已至，却和暖如春，着一层夹袄步出监牢的瞬间，已是汗流浃背。 一阵脚步声响...
开封第一讲书人阅读 8,388评论 0 77
• 我被黑心中介骗来泰国打工， 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留，地道东北人。 一个月前我还...
沈念sama阅读 12,919评论 2 133
• 正文 我出身青楼，却偏偏与公主长得像，于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子，可洞房花烛夜当晚...
茶点故事阅读 13,563评论 2 130