`
xhload3d
  • 浏览: 205740 次
社区版块
存档分类
最新评论

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

阅读更多

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

http://www.hightopo.com/demo/QuadTree/ht-quadtree.html

Screen Shot 2014-12-06 at 12.41.24 AM

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

我构建了HT(http://www.hightopo.com/)的GraphViewGraph3dView两个组件,通过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)的量:http://v.youku.com/v_show/id_XODQyNTA1NjY0.html

http://www.hightopo.com/demo/QuadTree/ht-quadtree.html

 

Screen Shot 2014-12-06 at 12.42.35 AM

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

Screen Shot 2014-12-06 at 12.52.17 AM

所有代码如下供参考:

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
    });
}

 

4
2
分享到:
评论

相关推荐

    用opengl和glut实现的简单四叉树的demo

    四叉树是一种数据结构,特别适用于空间分割和物体碰撞检测,常见于游戏开发和计算机图形学应用。在这个demo中,四叉树被用来优化场景中的图形渲染。 OpenGL是一个跨平台的图形库,提供了一套强大的低级编程接口,...

    D3D11_QuadTree

    四叉树是计算机图形学中用于空间分割的一种数据结构,常用于优化场景中的碰撞检测、渲染优化等任务。D3D11是Microsoft的DirectX API的一个版本,专门用于3D图形渲染。 描述中没有提供额外的信息,但我们可以推测这...

    cocos2d-x obb 旋转碰撞 矩形

    - 调试碰撞检测通常需要可视化obb和矩形,以确认它们的位置和旋转是否正确。cocos2d-x提供了绘制几何形状的功能,开发者可以利用这个功能辅助调试。 7. **总结**: - 了解和掌握obb碰撞检测是cocos2d-x游戏开发中...

    cocos2d-x游戏开发系列教程-坦克大战游戏之坦克和地图碰撞的检测

    在cocos2d-x游戏开发中,坦克大战游戏的实现涉及到了多个关键知识点,其中最重要的是坦克和地图的碰撞检测。这一过程对于游戏的交互性和趣味性至关重要,因为正确的碰撞检测能够确保坦克与地形、障碍物之间的交互...

    cocos2d-x 3.0游戏开发xcode5帅印博客教学 006.[HoldTail]子弹的创建和子弹与敌人的碰撞

    总的来说,通过Cocos2d-x 3.0的强大功能,我们可以轻松地在Xcode5环境下实现“HoldTail”游戏中的子弹创建和碰撞检测。理解这些基本原理并灵活运用,将有助于我们开发出更加丰富和引人入胜的2D游戏。

    speedytree:JavaScript中针对Deno的快速四叉树实现

    10. **测试与调试**:为确保快速四叉树实现的正确性,需要编写单元测试覆盖插入、删除、查询等各种操作,同时可以利用可视化工具来帮助理解树的结构和行为。 综上所述,"speedytree:JavaScript中针对Deno的快速四叉...

    box2d_processing.zip

    9. **性能优化**:理解并合理使用分离轴定理(SAP)和空间分层结构(如QuadTree)来提高碰撞检测效率。 10. **调试工具**:JBox2D提供了一些调试工具,如绘制轴对齐边界框(AABBs)和法线,帮助开发者检查物理模拟...

    碰撞检测算法

    碰撞检测算法在JavaScript中的应用场景非常丰富,如网页游戏、交互式可视化、3D建模工具等。例如,在网页游戏中,它可以用于角色与环境、角色与角色之间的碰撞响应,实现真实的物理效果;在交互式设计中,可以检测...

    3D渲染引擎OGRE源码分析

    场景管理器负责组织3D世界中的对象,如摄像机、光源、节点等,并提供高级功能如碰撞检测和动态分层。源码分析可以揭示如何构建复杂的场景结构,以及如何通过空间划分技术(如Octree或Quadtree)来加速渲染和查询。 ...

    Geometry

    - 划分与细分:如四叉树(QuadTree)和kd树(kd-Tree)用于高效地组织和查询几何对象。 - 多边形处理:包括多边形的遍历、填充、剪裁等。 - 几何图形的简化:如Douglas-Peucker算法用于减少几何图形的顶点数量,...

Global site tag (gtag.js) - Google Analytics