先看一下效果 同屏100个对象
四叉树算法的优点是检测效率和对象数量无关,只和树的深度有关
该算法广泛运用在游戏AI搜索,多物体碰撞检测等场合。
建树
var levelIndex:int = 0;
var columeIndex:int;
var rowIndex:int;
while(levelIndex < maxTreeLevel){//遍历每一层
nColumeCount = 1 << levelIndex;
nLeavesTotal = Math.pow(4,levelIndex);//每层叶子结点数量1,4,16,64 4的N次幂
//构建一个数组,存储每一层的所有子节点 因为第一层是没有父节点的 所以用levelIndex+1
aryLeavesArry = treeNodeVec2[levelIndex+1] = new Vector.<QuadNode>(nLeavesTotal,true);
//节点size
nNodeWidth = nMapWidth >> levelIndex;
nNodeHeight = nMapHeight >> levelIndex;
columeIndex = 0;
//构建行,列 map
while(columeIndex < nColumeCount){
rowIndex = 0;
//行列值肯定是相等的 比如 1*1 4*4 16*16 64*64
while(rowIndex < nColumeCount){
vQuadNode = new QuadNode();
vQuadNode.left = rowIndex * nNodeWidth;
vQuadNode.right = rowIndex * nNodeWidth + nNodeWidth;
vQuadNode.top = columeIndex * nNodeHeight;
vQuadNode.bottom = columeIndex * nNodeHeight + nNodeHeight;
//最后一层不用创建子节点 没有孩子了
if(levelIndex < maxTreeLevel - 1){
vQuadNode.children = new Vector.<QuadNode>();
}
//有孩子的就存起来,这个index可以这样理解,第一层就一个 index = 0
//第二层有4个 0,1,2,3
//第三层有16个 4,5,6,7,,,,15 推到一下就知道怎么算了
var index:int = columeIndex * nColumeCount + rowIndex; //方格子嘛!
vQuadNode.level = levelIndex+1;
vQuadNode.index = index;
aryLeavesArry[index] = vQuadNode;
//关联父子节点 treeNodeVec2[0]是空的,因为第一层是没有父节点的
if(treeNodeVec2[levelIndex] != null){
var parentIndex:int = index >> 2;//除以四就能算出父节点的index来了,自己画图验证吧
vQuadNode.Parent = treeNodeVec2[levelIndex][parentIndex];
vQuadNode.Parent.children.push(vQuadNode);//太他妈巧妙了
}
rowIndex++;
}
columeIndex++;
}
levelIndex++;
}//建树完毕
trace('建树完毕');
//构建个对象池
proxyPool = new Vector.<QObjBounds>(1<<9,true);
for (var i:int = 0; i < proxyPool.length; i++)
{
var obj:QObjBounds = new QObjBounds();
obj.id = i;
obj.nextId =i +1;
proxyPool[i] = obj;
}
优化算法部分,查找结点,采用等比缩放,异或位运算实现快速节点查找
/**
* 查找结点
* @param p
* @return
*
*/
private function findNode(p:QObjBounds):QuadNode
{
// TODO Auto Generated method stub
//坐标映射到 节点上
var n_left:int = p.left * m_nScaleW;
var n_top:int = p.top * m_nScaleH;
var n_right:int = p.right * m_nScaleW;
var n_bottom:int = p.bottom * m_nScaleH;
//异或操作 求出对现所在 节点层级 如果不理解,可以把 层级映射成二进制来表示
var m_nXRange:int = n_left ^ n_right;
var m_nYRange:int = n_top ^ n_bottom;
var nodeLevel:int = maxTreeLevel;
while((m_nXRange + m_nYRange) !=0){
m_nXRange = m_nXRange >> 1;
m_nYRange = m_nYRange >> 1;
nodeLevel -- ;
}
if(nodeLevel == 0){
trace("daddsd");
}
if(nodeLevel == 0)nodeLevel =1;
//这里为啥要有移位,很多同学不理解,举个例子
//例如 一个深度是3的四叉树 上面的 top left 都是基于最高层级去算的
//也就是第三层,那么你算出来发现显示对象在第二层,
//就需要我们把当前的top,left缩放到第二层的大小,
//再根据 列数 * 维度 + 行数 求出索引,缩放多少层呢 就是下面的差
var m_nShiftCount:int = maxTreeLevel - nodeLevel;
n_left = n_left >> m_nShiftCount;
n_top = n_top >> m_nShiftCount;
//找到层级后,接着找具体的节点索引
//索引 = 列数 * 维度 + 行数 比如 3层 16个节点的树 当代理对象在第15个空间中
// 行数 = 4 列数 = 3 维度 4*4
// if(nodeLevel == 0)nodeLevel =1;
var weishu:int = 1 << (nodeLevel - 1);
var index:int = n_top * weishu + n_left;
var quadNode:QuadNode = treeNodeVec2[nodeLevel][index];
return quadNode;
}
碰撞检测
/**
* 检测碰撞
*
*/
private function checkCollision(checkObj:QObjBounds):void
{
// TODO Auto Generated method stub
var vNode:QuadNode;
var nextObj:QObjBounds;
var preObj:QObjBounds;
vNode = checkObj.node;
var nodeLevel:int = vNode.level;
//检测当前结点对象
nextObj = checkObj.nextInNode;
while(nextObj){
if(checkObj.intersect(nextObj)){
// nextObj.color = 0xFFFF00FF;
// checkObj.color = 0xFFFF00FF;
nextObj.isCollision = checkObj.isCollision = true;
}
nextObj = nextObj.nextInNode;
}
//检查 跨越所有子节点
var level:int = maxTreeLevel;
var nLineStart:int= checkObj.left*m_nScaleW;
var nLineEnd:int = checkObj.right*m_nScaleW;
var nColumeStart:int = checkObj.top*m_nScaleH;
var nColumeEnd:int = checkObj.bottom*m_nScaleH;
while(level!=0){
for (var i:int = nColumeStart; i <= nColumeEnd; i++)
{
for (var j:int = nLineStart; j <= nLineEnd; j++)
{
var index:int =int( i * (1 << (level -1)))+j;
vNode = treeNodeVec2[level][index];
//检测当前结点对象
nextObj = vNode.proxyListHead;
while(nextObj){
if(nextObj != checkObj){//当前检测的不是原来的
if(checkObj.intersect(nextObj)){
// nextObj.color = 0xFFFF00FF;
// checkObj.color = 0xFFFF00FF;
nextObj.isCollision = checkObj.isCollision = true;
}
}
nextObj = nextObj.nextInNode;
}
}
}
//缩小包围圈
nLineStart>>=1;
nLineEnd>>=1;
nColumeStart>>=1;
nColumeEnd>>=1;
level --;
if(nodeLevel == level)break;
}
}
“`
源码及问题请留言或联系作者