基于HTML5的WebGL呈现A星算法的3D可视化

原创 2015年11月18日 01:39:07

IMG_1486

 

http://www.hightopo.com/demo/astar/astar.html

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

Screen Shot 2014-11-24 at 5.36.33 PM

实现代码比较容易一百多行,不过算法核心在astar.js了,界面核心在ht.js里面了,我只需要构建网格信息,只需监听用户点击,然后调用astar.js进行最短路径计算,将结果通过动画的方式呈现出走动的过程,所有代码如下:

function init() {                
    w = 40; m = 20; d = w * m / 2;            
    gridRows = [];                        
    dm = new ht.DataModel();             
    g3d = new ht.graph3d.Graph3dView(dm);                
    g3d.setGridVisible(true);
    g3d.setGridColor('#BBBBBB');
    g3d.setGridSize(m);
    g3d.setGridGap(w);            
    g3d.addToDOM();                                                                                                        
    g3d.sm().setSelectionMode('none');            
    anim = startBall = endBall = null;                        
    g3d.getView().addEventListener(ht.Default.isTouchable ? 'touchstart' : 'mousedown', function(e){                
        if(!anim){
            var p = g3d.getHitPosition(e);
            var x = Math.floor((p[0] + d)/ w);
            var y = Math.floor((p[2] + d)/ w);
            var endBall = dm.getDataByTag("cell_" + x + "_" + y);
            if(endBall && endBall.s('batch') !== 'wall'){                      
                if(startBall.a('x') === x && startBall.a('y') === y){
                    return;
                }                        
                var g = new Graph(gridRows, { 
                    diagonal: formPane.v('diagonal') 
                });
                var start = g.grid[startBall.a('x')][startBall.a('y')];
                var end = g.grid[x][y];
                var result = astar.search(g, start, end, {
                    closest: formPane.v('closest')                            
                });  
                if(!result.length){
                    return;
                }
                x = result[result.length-1].x;
                y = result[result.length-1].y;
                endBall = dm.getDataByTag("cell_" + x + "_" + y);
                endBall.s('3d.visible', true);
                startBall.s('3d.visible', false);
                formPane.setDisabled(true);
                anim = ht.Default.startAnim({
                    duration: 700,
                    finishFunc: function(){  
                        for(var i=0; i<result.length; i++){
                            var ball = dm.getDataByTag("cell_" + result[i].x + "_" + result[i].y);
                            ball.s({
                                '3d.visible': false,
                                'shape3d.opacity': 1,
                                'shape3d.transparent': false
                            }); 
                            startBall.p3(-d+w*x+w/2, w/2, -d+w*y+w/2);
                            startBall.a({x: x, y: y});
                            startBall.s('3d.visible', true);
                        }
                        anim = null;
                        formPane.setDisabled(false);
                    },
                    action: function(v){
                        var index = Math.round(v*result.length);
                        for(var i=0; i<index; i++){
                            var ball = dm.getDataByTag("cell_" + result[i].x + "_" + result[i].y);
                            ball.s({
                                '3d.visible': true,
                                'shape3d.opacity': i/index*0.3 + 0.7,
                                'shape3d.transparent': true
                            });                                    
                        }
                    }
                });                                                
            }
        }               
    }, false);                                    
    createFormPane();
    createGrid();                                
}                
function createGrid(){
    dm.clear();            
    var ball;
    gridRows.length = 0;
    for(var x = 0; x < m; x++) {
        var nodeRow = [];
        gridRows.push(nodeRow);
        for(var y = 0; y < m; y++) {                                
            var isWall = Math.floor(Math.random()*(1/formPane.v('frequency')));
            if(isWall === 0){
                nodeRow.push(0);
                createNode(x, y).s({
                    'batch': 'wall',
                    'all.color': '#9CA69D'
                });
            }else{
                nodeRow.push(1);
                ball = createNode(x, y).s({
                    'shape3d': 'sphere',  
                    'shape3d.color': '#FF703F',
                    '3d.visible': false
                });
            }            
        }       
    }
    if(!ball){
        createGrid();
        return;
    }            
    startBall = createNode(ball.a('x'), ball.a('y'), 'start').s({
        'shape3d': 'sphere',  
        'shape3d.color': '#FF703F'                    
    });  

    shape = new ht.Shape();
    shape.setPoints(new ht.List([
        {x: -d, y: d},
        {x: d, y: d},
        {x: d, y: -d},
        {x: -d, y: -d},
        {x: -d, y: d}
    ]));
    shape.setThickness(4);
    shape.setTall(w);
    shape.setElevation(w/2);
    shape.setClosePath(true);
    shape.s({
        'all.color': 'rgba(187, 187, 187, 0.8)', 
        'all.transparent': true, 
        'all.reverse.cull': true
    });
    dm.add(shape);                            
}
function createNode(x, y, tag){
    var node = new ht.Node();
    tag = tag || "cell_" + x + "_" + y;               
    node.setTag(tag);            
    node.a({ x: x,  y: y });
    node.s3(w*0.9, w*0.9, w*0.9);
    node.p3(-d+w*x+w/2, w/2, -d+w*y+w/2);
    node.s({
        'all.reverse.cull': true,
        'shape3d.reverse.cull': true
    });
    dm.add(node);
    return node;
}                       
function createFormPane() {           
    formPane = new ht.widget.FormPane();
    formPane.setWidth(230);
    formPane.setHeight(70);
    formPane.getView().className = 'formpane';
    document.body.appendChild(formPane.getView());            
    formPane.addRow(['Wall Frequency', {
        id: 'frequency',
        slider: {
            min: 0,
            max: 0.8,
            value: 0.1,                            
            onValueChanged: function(){
                createGrid();
            }
        }
    }], [100, 0.1]);                               
    formPane.addRow([
        {
            id: 'closest',
            checkBox: {
                label: 'Try Closest'
            }
        },
        {
            id: 'diagonal',
            checkBox: {
                label: 'Allow Diagonal'
            }        
        }
    ], [0.1, 0.1]);
}

只从iOS8支持WebGL后在移动终端上测试3D应用比当前的大部分Android平板舒服多了,以上的例子在iOS系统下呈现和算法都挺流畅,http://v.youku.com/v_show/id_XODMzOTU1Njcy.html,当然这个小例子数据量也不大,本质其实还是2D的最短路径算法,并非真正意义的3D空间最短路径,但还是足够解决很多实际应用问题了。

http://www.hightopo.com/demo/astar/astar.html

Screen Shot 2014-11-24 at 5.09.13 PM

 

Html5游戏框架Craftyjs入门简单RPG及A*寻路

Crafty.js是一个比较简单轻量的Html5游戏框架,个人比较喜欢,是因为它足够简便(如果你只需要制作简单的小游戏,例如微信h5中的各种游戏)。 遗憾的是,Crafty.js的社区活跃的人越来越少...
  • dyyaries
  • dyyaries
  • 2016年10月29日 17:22
  • 1773

基于HTML5的WebGL呈现A星算法的3D可视化

http://www.hightopo.com/demo/astar/astar.html 最近搞个游戏遇到最短路径的常规游戏问题,一时起兴基于HT for Web写了个A*算法的WebGL 3D呈...
  • yixiaof
  • yixiaof
  • 2018年01月09日 11:11
  • 7

数百个 HTML5 例子学习 HT 图形组件 – WebGL 3D 篇

《数百个 HTML5 例子学习 HT 图形组件 – 拓扑图篇》一文让读者了解了 HT 的 2D 拓扑图组件使用,本文将对 HT 的 3D 功能做个综合性的介绍,以便初学者可快速上手使用 HT 构建例如...
  • u013161495
  • u013161495
  • 2016年08月26日 03:01
  • 5304

基于 HTML5 的 WebGL 技术构建 3D 场景(一)

HT for Web 提供了多种基础类型供用户建模使用,不同于传统的 3D 建模方式,HT 的建模核心都是基于 API 的接口方式,通过 HT 预定义的图元类型和参数接口,进行设置达到三维模型的构建。...
  • u013161495
  • u013161495
  • 2016年07月13日 00:51
  • 5662

通过实例深入理解HTML5/CSS3/SVG/WebGL的技术本质

常常听到人们对于HTML5的讨论,看了页面头部这个那个就是HTML5,误认为HTML5只是新增些标签“而已”,学完了速查手册似乎就理解了。实际上很多从业人员并没有深入理解业界为什么要推出HTML5系列...
  • iefreer
  • iefreer
  • 2016年11月06日 00:56
  • 8386

数据可视化的实现技术和工具比较(HTML5 canvas(Echart)、SVG、webGL等等)

http://www.cnblogs.com/zhangdi/p/3690284.html?utm_source=tuicool&utm_medium=referral 友盟的指数报告页面的统计图表,...
  • oLevin
  • oLevin
  • 2016年05月02日 15:08
  • 9456

html5可视化图形编辑器(基于canvas)

我以前特别喜欢flash,不过flash水平一般,那是的我并不是程序员,充其量也就是个爱好者,在这个html5的时代中,我依旧对那个有时间轴的flash编辑界面念念不忘。于是便有了这篇文章。我的目标是...
  • tx101q
  • tx101q
  • 2016年10月28日 20:52
  • 5837

Miner3D Professional可视化数据分析方案

Miner3D Professional支持探索数据中隐藏和未知的部分。发现趋势,进行数据聚类查找相关性,不让这些埋藏在原始数据中。Miner3D Professional加速了研究人员、分析师、管理...
  • pk52020081
  • pk52020081
  • 2015年06月11日 17:54
  • 733

2016年最火的15款HTML5游戏引擎

2016年最火的15款HTML5游戏引擎 HTML5游戏从2014年Egret引擎开发的神经猫引爆朋友圈之后,就开始一发不可收拾,今年《传奇世界》更是突破流水2000万!从两年多的发展来看,游戏...
  • YaoXTao
  • YaoXTao
  • 2016年04月06日 10:11
  • 2647

基于HTML5实现3D监控应用流动效果

Hightopo的HT for Web作为3D客户端呈现解决方案,今天介绍的重点不在于采集这些指标,而在于如何应用HT的预定于3D元素来实现流动的效果。在《透过WebGL 3D看动画Easing函数本...
  • u013161495
  • u013161495
  • 2015年10月11日 22:08
  • 1356
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:基于HTML5的WebGL呈现A星算法的3D可视化
举报原因:
原因补充:

(最多只允许输入30个字)