基于四叉树2D碰撞检测以及D3简单分析

前言 《数据结构-使用JS实现四叉树》 上文中简单介绍了四叉树的一些实现和应用场景 本篇文章应评论区各位小伙伴的留言 基于四叉树实现一下2D的碰撞检测。
话不多说开始今天的内容。
首先看下quadtree测试效果图 【基于四叉树2D碰撞检测以及D3简单分析】基于四叉树2D碰撞检测以及D3简单分析
文章图片

正文coding部分 实现思路

  • 数据结构采取四叉树
  • 碰撞节点比对进行四叉树查找
    sample采取canvas2d进行绘制,JavaScript进行实现。
实现过程
定义quadtree数据结构
/** *四叉树构造函数 *@四叉树 2D类碰撞 需要四叉树边界/节点层数/ *@param{Rect}节点的边界({x,y,width,height}) *@param{number}[max\u objects=10]在拆分为4个子节点之前,节点可以容纳的最大对象数 默认:4 *@param{number}[max\u levels=4]根四叉树内的总最大级别 默认为 4 *@param{number}[level=0] 深度级别,子节点需要 默认:0初始深度 */ function Quadtree(bounds, max_objects, max_levels, level) {this.max_objects= max_objects || 4; this.max_levels= max_levels || 4; this.level= level || 0; this.bounds = bounds; this.objects= []; this.nodes= []; };

添加objects/如果超出max_objects那么就拆分子节点
/* *将对象插入节点。如果节点 *超过容量时,将拆分并添加所有 *对象到其相应的子节点。 *@param{Rect}要添加的对象的pRect边界({x,y,width,height}) *@memberof四叉树 */ Quadtree.prototype.insert = function(pRect) {var i = 0, indexes; //如果存在子节点,那么找到子节点像子节点添加数据(子节点就是子树) if(this.nodes.length) { indexes = this.getIndex(pRect); for(i=0; i this.max_objects && this.level < this.max_levels) {//拆分子节点 (split方法可以移步仓库看代码,很简单。后续不贴了) if(!this.nodes.length) { this.split(); }//将所有objects添加到对应的nodes for(i=0; i

获取
/** *确定对象属于哪个节点 *@param{Rect}要检查的区域的pRect边界({x,y,width,height}) *@return{number[]}相交子节点的索引数组(0-3=右上、左上、左下、右下) *@memberof四叉树 */ Quadtree.prototype.getIndex = function(pRect) {var indexes = [], verticalMidpoint= this.bounds.x + (this.bounds.width/2), //x中心 horizontalMidpoint= this.bounds.y + (this.bounds.height/2); //y中心 // 判断属于哪个区域 var startIsNorth = pRect.y < horizontalMidpoint, startIsWest= pRect.x < verticalMidpoint, endIsEast= pRect.x + pRect.width > verticalMidpoint, endIsSouth= pRect.y + pRect.height > horizontalMidpoint; //右上 quad if(startIsNorth && endIsEast) { indexes.push(0); }//左上 quad if(startIsWest && startIsNorth) { indexes.push(1); }//左下 quad if(startIsWest && endIsSouth) { indexes.push(2); }//右下 quad if(endIsEast && endIsSouth) { indexes.push(3); } return indexes; };

给定一个rect结构进行碰撞
/** *返回所有可能与给定对象碰撞的对象 *@param{Rect}要检查的对象的pRect边界({x,y,width,height}) *@return{Rect[]}数组,包含所有检测到的对象 *@memberof四叉树 */ Quadtree.prototype.retrieve = function(pRect) {var indexes = this.getIndex(pRect), returnObjects = this.objects; //if we have subnodes, retrieve their objects if(this.nodes.length) { for(var i=0; i= index; }); return returnObjects; };

清除四叉树
/** * 清除四叉树 * @memberof Quadtree */ Quadtree.prototype.clear = function() {this.objects = []; for(var i=0; i < this.nodes.length; i++) { if(this.nodes.length) { this.nodes[i].clear(); } }this.nodes = []; };

quadtree其他相关仓库 D3 Quadtree 拿D3来做一下学习,首先实现更为全面(可以看下面截图里具体的一个结构模块)有add cover,data,find.... 而且细节做的很棒,值得学习。下面简单举个例子
基于四叉树2D碰撞检测以及D3简单分析
文章图片

就拿一个模块来说: find.js 也是寻找相应的nodes 然后追加 同样的实现,区别在于可以理解为访问做了记录/不访问重复点,而且有就近访问原则(这个可以做一些其他工作)i = (y >= ym) << 1 | (x >= xm),有兴趣的可以去学习一下。
基于四叉树2D碰撞检测以及D3简单分析
文章图片

总的来说D3内部存在一些能够帮助到你思维转变提升的东西,学习还是很要必要的。对了, 实践过程中可以尝试和d3-force模块结合使用,效果更佳。
结语 四叉树作为树的一种结构,上面的例子很好的体现了四叉树在2D碰撞的实践,有任何疑问请随时留言。
最后~ 托更一天本人感到非常抱歉!!!
其他链接 上述示例代码仓库
D3 Quadtree

    推荐阅读