HT for Web可视化QuadTree四叉树碰撞检测

QuadTree四叉树顾名思义就是树状的数据结构,其每个节点有四个孩子节点,可将二维平面递归分割子区域。QuadTree常用于空间数据库索引,3D的椎体可见区域裁剪,甚至图片分析处理,我们今天介绍的是QuadTree最常被游戏领域使用到的碰撞检测。采用QuadTree算法将大大减少需要测试碰撞的次数,从而提高游戏刷新性能,本文例子基于HT for Web的图形引擎,通过GraphViewGraph3dView共享同一数据模型DataModel,同时呈现QuadTree算法下的2D和3D碰撞视图效果:

QuadTree的实现有很多成熟的版本,我选择的是 https://github.com/timohausmann/quadtree-js/ 四叉树的算法很简单,因此这个开源库也就两百来行代码。使用也非常简单,构建一个Quadtree对象,第一个参数传入rect信息制定游戏空间范围,在每次requestAnimationFrame刷新帧时,先通过quadtree.clear()清除老数据,通过quadtree.insert(rect)插入新的节点矩形区域,这样quadtree就初始化好了,剩下就是根据需要调用quadtree.retrieve(rect)获取指定矩形区域下,与其可能相交需要检测的矩形对象数组。

我构建了HTGraphViewGraph3dView两个组件,通过ht.widget.SplitView左右分割,由于两个视图都共享同一DataModel,因此我们剩下的关注点仅是对DataModel的数据操作,构建了200个ht.Node对象,每个对象的attr属性上保存了随机的运动方向vx和vy,同时保存了将要反复插入quadtree的矩形对象,这样避免每帧更新时反复创建对象,同时矩形对象也引用了ht.Node对象,用来当通过quadtree.retrieve(rect)获取需要检测的矩形对象时,我们能指定其所关联的ht.Node对象,因为我们需要对最终检测为碰撞的图元设置上红颜色的效果,也就是ht.Node平时显示默认的蓝色,当互相碰撞时将改变为红色。

需要注意从quadtree.retrieve(rect)获取需要检测的矩形对象数组中会包含自身图元,同时这些仅仅是可能会碰撞的图元,并不意味着已经碰撞了,由于我们例子是矩形,因此采用ht.Default.intersectsRect(r1, r2)最终判断是否相交,如果你的例子是圆形则可以采用计算两个圆心距离是否小于两个半径来决定是否相交,因此最终判断的标准根据游戏类型会有差异。

采用了QuadTree还是极大了提高了运算性能,否则100个图元就需要100*100次的监测,我这个例子场景下一般也就100*(10~30)的量:

除了碰撞检测外QuadTree算法还有很多有趣的应用领域,有兴趣可以玩玩这个 https://github.com/fogleman/Quads

所有代码如下供参考:

function init(){
    d = 200;
    speed = 8;
    dataModel = new ht.DataModel();
    g3d = new ht.graph3d.Graph3dView(dataModel);
    g2d = new ht.graph.GraphView(dataModel);
    mainSplit = new ht.widget.SplitView(g3d, g2d);
    mainSplit.addToDOM();
    g2d.translate(300, 220);
    g2d.setZoom(0.8, true);

    for(var i=0; i<100; i++) {
        var node = new ht.Node();
        node.s3(randMinMax(5, 30), 10, randMinMax(5, 30));
        node.p3(randMinMax(-d/2, d/2), 0, randMinMax(-d/2, d/2));
        node.s({
            ‘batch‘: ‘group‘,
            ‘shape‘: ‘rect‘,
            ‘shape.border.width‘: 1,
            ‘shape.border.color‘: ‘white‘,
            ‘wf.visible‘: true,
            ‘wf.color‘: ‘white‘
        });
        node.a({
            vx: randMinMax(-speed, speed),
            vy: randMinMax(-speed, speed),
            obj: {
                width: node.getWidth(),
                height: node.getHeight(),
                data: node
            }
        });
        dataModel.add(node);
    }
    createShape([
        {x: -d, y: d},
        {x: d, y: d},
        {x: d, y: -d},
        {x: -d, y: -d},
        {x: -d, y: d}
    ]);
    quadtree = new Quadtree({ x: -d, y: -d, width: d, height: d });
    requestAnimationFrame(update);
}
function update() {
    quadtree.clear();
    dataModel.each(function(data){
        if(!(data instanceof ht.Shape)){
            var position = data.getPosition();
            var vx = data.a(‘vx‘);
            var vy = data.a(‘vy‘);
            var w = data.getWidth()/2;
            var h = data.getHeight()/2;
            var x = position.x + vx;
            var y = position.y + vy;
            if(x - w < -d){
                data.a(‘vx‘, -vx);
                x = -d + w;
            }
            if(x + w > d){
                data.a(‘vx‘, -vx);
                x = d - w;
            }
            if(y - h < -d){
                data.a(‘vy‘, -vy);
                y = -d + h;
            }
            if(y + h > d){
                data.a(‘vy‘, -vy);
                y = d - h;
            }
            data.setPosition(x, y);
            var obj = data.a(‘obj‘);
            obj.x = x - w;
            obj.y = y - h;

            quadtree.insert(obj);
            setColor(data, undefined);
        }
    });
    dataModel.each(function(data){
        if(!(data instanceof ht.Shape)){
            var obj = data.a(‘obj‘);
            var objs = quadtree.retrieve(obj);
            if(objs.length > 1){
                for(var i=0; i<objs.length; i++ ) {
                    var data2 = objs[i].data;
                    if(data === data2){
                        continue;
                    }
                    if(ht.Default.intersectsRect(obj, data2.a(‘obj‘))){
                        setColor(data, ‘red‘);
                        setColor(data2, ‘red‘);
                    }
                }
            }
        }
    });
    requestAnimationFrame(update);
}
function randMinMax(min, max) {
    return min + (Math.random() * (max - min));
}
function createShape(points){
    shape = new ht.Shape();
    shape.setPoints(points);
    shape.setThickness(4);
    shape.setTall(10);
    shape.s({
        ‘all.color‘: ‘red‘,
        ‘shape.background‘: null,
        ‘shape.border.width‘: 2,
        ‘shape.border.color‘: ‘red‘
    });
    dataModel.add(shape);
    return shape;
}
function setColor(data, color){
    data.s({
        ‘all.color‘: color,
        ‘shape.background‘: color
    });
}
时间: 2024-10-06 11:27:47

HT for Web可视化QuadTree四叉树碰撞检测的相关文章

HTML5实现3D和2D可视化QuadTree四叉树碰撞检测

QuadTree四叉树顾名思义就是树状的数据结构,其每个节点有四个孩子节点,可将二维平面递归分割子区域.QuadTree常用于空间数据库索引,3D的椎体可见区域裁剪,甚至图片分析处理,我们今天介绍的是QuadTree最常被游戏领域使用到的碰撞检测.采用QuadTree算法将大大减少需要测试碰撞的次数,从而提高游戏刷新性能,本文例子基于HT for Web的Canvas拓扑图和WebGL的3D引擎组件,通过GraphView和Graph3dView共享同一数据模型DataModel,同时呈现Qua

HT for Web列表和3D拓扑组件的拖拽应用

很多可视化编辑器都或多或少有一些拖拽功能,比如从一个List列表中拖拽一个节点到拓扑组件上进行建模,并且在拖拽的过程中鼠标位置下会附带一个被拖拽节点的缩略图,那么今天我们就来实现这样的拖拽效果. 首先我们需要创建一个ListView列表,在列表中加入图片信息,让List列表不那么单调,先来看看效果图. 接下来我们一步一步来是想这个ListView列表,先来解决下数据,在这里我就列举一两个: var products = [ { ProductId : 1, ProductName : "Chai

透过HT for Web 3D看动画Easing函数本质

http://www.hightopo.com/guide/guide/plugin/form/examples/example_easing.html 50年前的这个月诞生了BASIC这门计算机语言,回想起自己喜欢上图形界面这行,还得归功于当年在win98下用QBASIC照葫芦画瓢敲了一段绘制奥运五环的代码,当带色彩的奥运五环呈现在自己面前时我已知道自己这辈子要走的路了.在这个忘本逐新的年代不见多少媒体提及这影响了几代人的BASIC语言的50年庆了. 如今消费者对用户体验的高要求,以远不能以静

基于HT for Web的3D呈现A* Search Algorithm

最近搞个游戏遇到最短路径的常规游戏问题,一时起兴基于HT for Web写了个A*算法的WebGL 3D呈现,算法基于开源 https://github.com/bgrins/javascript-astar 的javascript实现,其实作者也有个不错的2D例子实现 http://www.briangrinstead.com/files/astar/ ,只不过觉得所有A*算法的可视化实现都是平面的不够酷,另外还有不少参数需要调节控制,还是值得好好搞个全面的Demo,先上张2D和3D例子的对照

HT for Web框架使用心得

一.简单介绍 在HT for Web的官网首页写着,构建先进2D和3D可视化所需要的一切. 是的,只要你看过官网,你就会知道,这是一个企业的.并非开源的且需要收费的框架. 因为公司的业务需要,且公司使用的3D可视化框架正是基于此框架,所以我,不得不去学习该框架的使用. 二.学习过程 1.第一阶段: 当我刚开始收到要做3D可视化开发的任务委派时,我一脸懵逼,主要对3D开发一窍不通,最重要是没有概念.既然有新的东西可以学,那就来咯. 刚开始的时候,我们前端大佬只给我一个HT for Web的官方网站

基于HT for Web矢量实现HTML5文件上传进度条

在HTML中,在文件上传的过程中,很多情况都是没有任何的提示,这在体验上很不好,用户都不知道到时有没有在上传.上传成功了没有,所以今天给大家介绍的内容是通过HT for Web矢量来实现HTML5文件上传进度条,矢量在<矢量Chart图表嵌入HTML5网络拓扑图的应用>一文中已经讲述了关于setCompType()方法的应用,今天我们用setImage()方法充分利用系统中定义好的矢量资源来实现文件上传进度条,我们先来看下效果图: 从效果图可以看到,向服务器上传了一个mp4文件,并在最下方显示

基于HT for Web 3D呈现Box2DJS物理引擎

上篇我们基于HT for Web呈现了A* Search Algorithm的3D寻路效果,这篇我们将采用HT for Web 3D来呈现Box2DJS物理引擎的碰撞效果,同上篇其实Box2DJS只是二维的平面碰撞物理引擎,但同样通过3D的呈现能让人更直观的体验到碰撞效果,先上张最终例子效果图: Box2D最早是Erin Catto在GDC大会上的一个展示例子,后来不断完善成C++的开源物理引擎库,这些年了衍生出Java.ActionScript以及JS等版本,被广泛应用在游戏领域.说其丰富的确

HT for Web基于HTML5的图像操作(二)

上篇介绍了HT for Web采用HTML5 Canvas的getImageData和setImageData函数,通过颜色乘积实现的染色效果,本文将再次介绍另一种更为高效的实现方式,当然要实现的功能效果是完全一样的.这次我们依然基于HTML5技术,但采用Canvas的globalCompositeOperation属性进行各种blending效果: 各种globalCompositeOperation效果可参考https://developer.mozilla.org/en-US/docs/W

HT For Web 拓扑图背景设置

HT For Web 的HTML5拓扑图组件graphView背景设置有多种途径可选择: divBackground:通过css设置graphView对应的div背景 Painter:通过graphView.addBottomPainter(function(g, rect){…})来绘制背景 Layer:通过设置graphView.setLayer(['…', '…', '…', …])来将graphView拆分为多个图层,并为各个图层命名,再让不同种类的node通过node.setLayer