基于WebGL 的3D呈现A* Search Algorithm

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例子的对照图。

实现代码比较容易一百多行,不过算法核心在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

基于WebGL 的3D呈现A* Search Algorithm的更多相关文章
- 基于HT for Web的3D呈现A* Search Algorithm
		最近搞个游戏遇到最短路径的常规游戏问题,正巧看到老同事写的3D机房最短路径巡线文章,一时起兴基于HT for Web写了个A*算法的WebGL 3D呈现,算法基于开源 https://github.c ... 
- 基于 WebGL 的 3D 动态柱状图表
		发现现在工业SCADA上或者电信网管方面用图表的特别多,虽然绝大部分人在图表制作方面用的是echarts,他确实好用,但是有些时候我们不能调用别的插件,这个时候就得自己写这些美丽的图表了,然而图表轻易 ... 
- 基于 HTML5 WebGL 的 3D 网络拓扑图
		在数据量很大的2D 场景下,要找到具体的模型比较困难,并且只能显示出模型的的某一部分,显示也不够直观,这种时候能快速搭建出 3D 场景就有很大需求了.但是搭建 3D 应用场景又依赖于通过 3ds Ma ... 
- 用基于WebGL的BabylonJS来共享你的3D扫描模型
		转自:http://www.geekfan.net/6578/ 用基于WebGL的BabylonJS来共享你的3D扫描模型 杰克祥子 2014 年 2 月 26 日 0 条评论 标签:3D扫描 , B ... 
- 基于HT for Web 3D呈现Box2DJS物理引擎
		上篇我们基于HT for Web呈现了A* Search Algorithm的3D寻路效果,这篇我们将采用HT for Web 3D来呈现Box2DJS物理引擎的碰撞效果,同上篇其实Box2DJS只是 ... 
- 基于 WebGL 3D 的 HTML5 档案馆可视化管理系统
		前言 档案管理系统是通过建立统一的标准以规范整个文件管理,包括规范各业务系统的文件管理的完整的档案资源信息共享服务平台,主要实现档案流水化采集功能.为企事业单位的档案现代化管理,提供完整的解决方案,档 ... 
- 基于 HTML5 的 WebGL 自定义 3D 摄像头监控模型
		前言 随着视频监控联网系统的不断普及和发展, 网络摄像机更多的应用于监控系统中,尤其是高清时代的来临,更加快了网络摄像机的发展和应用. 在监控摄像机数量的不断庞大的同时,在监控系统中面临着严峻的现状问 ... 
- B/S 端构建的基于 WebGL 3D 可视化档案馆管理系统
		前言 档案管理系统是通过建立统一的标准以规范整个文件管理,包括规范各业务系统的文件管理的完整的档案资源信息共享服务平台,主要实现档案流水化采集功能.为企事业单位的档案现代化管理,提供完整的解决方案,档 ... 
- 基于 HTML5 WebGL 的 3D 风机 Web 组态工业互联网应用
		基于 HTML5 WebGL 的 3D 风机 Web 组态工业互联网应用 前言 在目前大数据时代背景之下,数据可视化的需求也变得越来越庞大,在数据可视化的背景之下,通过智能机器间的链接并最终将人机链接 ... 
随机推荐
- ABP文档 - Javascript Api - Message
			本节内容: 显示信息 确认 Message API给用户显示一个信息,或从用户那里获取一个确认信息. Message API默认使用sweetalert实现,为使sweetalert正常工作,你应该包 ... 
- C# 发送邮件 附件名称为空
			示例代码: // 1.创建邮件 MailMessage mailMsg = new MailMessage(); mailMsg.To.Add(new MailAddress("test@ ... 
- css实现单行,多行文本溢出显示省略号……
			1.单行文本溢出显示省略号我们可以直接用text-overflow: ellipsis 实现方法: <style> .div_text{width: 300px; padding:10px ... 
- [OpenGL超级宝典]专栏前言
			我小时候的梦想呢,是做宇航员或者科学家或者是做一款属于自己的游戏,后来前面两个梦想都没有实现,于是我就来实现我的第三个梦想了,,,我呢,也算是零基础,因为我的专业是物联网工程,这个专业覆盖面之广,简直 ... 
- .NET跨平台之运行与Linux上的Jexus服务器
			谈及.NET跨平台,已经不是什么稀奇的事儿.今天我们就以Jexus服务器的部署为例.简单示范下.在这里,我用VMWare虚拟机来搭建Linux运行环境. Linux,我们选择CentOS7.大家可以前 ... 
- AFNetworking 3.0 源码解读 总结(干货)(上)
			养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要.记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点.它就像时间一样,会自己消散. 前言 终于写完了 AFNetwo ... 
- JS魔法堂:不完全国际化&本地化手册 之 理論篇
			前言 最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求--国际化&本地化.熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"的阶段而已. ... 
- gulp批量打包文件并提取公共文件
			gulp是前端开发过程中对代码进行构建的工具,是自动化项目的构建利器. browseriyf是模块化打包工具. 一般情况下,Browserify 会把所有的模块打包成单个文件.单个文件在大多数情况下是 ... 
- linux上使用google身份验证器(简版)
			系统:centos6.6 下载google身份验证包google-authenticator-master(其实只是一个.zip文件,在windwos下解压,然后传进linux) #cd /data/ ... 
- 【转】 XenServer的架构
			一.Dom0或者控制域 XenServer从安装上看起来像是一个Linux,所以有些同学认为XenServer就是Linux或者是Linux修改的.真实的XenServer和Linux的关系是这样的: ... 
