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

实现代码比较容易一百多行,不过算法核心在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空间最短路径,但还是足够解决很多实际应用问题了。

时间: 2024-10-11 16:55:42

基于HT for Web的3D呈现A* Search Algorithm的相关文章

基于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*算法的可视化实现都是平面的不够

基于HT for Web的3D树的实现

在HT for Web中2D和3D应用都支持树状结构数据的展示,展现效果各异,2D上的树状结构在展现层级关系明显,但是如果数据量大的话,看起来就没那么直观,找到指定的节点比较困难,而3D上的树状结构在展现上配合HT for Web的弹力布局组件会显得比较直观,一眼望去可以把整个树状结构数据看个大概,但是在弹力布局的作用下,其层次结构看得就不是那么清晰了.所以这时候结构清晰的3D树的需求就来了,那么这个3D树具体长成啥样呢,我们来一起目睹下~ 要实现这样的效果,该从何下手呢?接下来我们就将这个问题

基于HT for Web的3D拓扑树的实现

在HT for Web中2D和3D应用都支持树状结构数据的展示,展现效果各异,2D上的树状结构在展现层级关系明显,但是如果数据量大的话,看起来就没那么直观,找到指定的节点比较困难,而3D上的树状结构在展现上配合HT for Web的弹力布局组件会显得比较直观,一眼望去可以把整个树状结构数据看个大概,但是在弹力布局的作用下,其层次结构看得就不是那么清晰了.所以这时候结构清晰的3D树的需求就来了,那么这个3D树具体长成啥样呢,我们来一起目睹下~ 要实现这样的效果,该从何下手呢?接下来我们就将这个问题

基于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矢量实现3D叶轮旋转

在上一篇<基于HT for Web矢量实现2D叶轮旋转>中讲述了叶轮旋转在2D上的应用,今天我们就来讲讲叶轮旋转在3D上的应用. 在3D拓扑上可以创建各种各样的图元,在HT for Web系统中提供了一些常规的3D模型,但是对于那些比较复杂的模型,比如汽车.人物等模型就无能为力了,那再项目中需要用到这样的模型该肿么办呢?这时候就需要借助专业的3ds Max工具来建模了,然后通过3ds Max工具将模型导出成obj文件,然后再项目中引用导出的obj文件,这样就能成功的使用上复杂的图元了. 在&l

基于HT for Web 3D技术快速搭建设备面板

以真实设备为模型,搭建出设备面板,并实时获取设备运行参数,显示在设备面板上,这相比于纯数值的设备监控系统显得更加生动直观.今天我们就在HT for Web的3D技术上完成设备面板的搭建. 我们今天模拟的设备是机房设备,先来目睹下最终效果: 我来解释下这个模型,一个带有透明玻璃门的机柜,机柜里装有5台设备,门可以开合,设备可以插拔,那么我么该如何搭建这样的设备呢?方法不难,我们一步一步来. 我们先从设备开始,设备的示意图如下: 看起来有模有样的,其实呢,它就是一个长方体,然后在长方体的正面贴上一张

基于HT for Web 快速搭建3D机房设备面板

以真实设备为模型,搭建出设备面板,并实时获取设备运行参数,显示在设备面板上,这相比于纯数值的设备监控系统显得更加生动直观.今天我们就在HT for Web的3D技术上完成设备面板的搭建. 我们今天模拟的设备是机房设备,先来目睹下最终效果: 我来解释下这个模型,一个带有透明玻璃门的机柜,机柜里装有5台设备,门可以开合,设备可以插拔,那么我么该如何搭建这样的设备呢?方法不难,我们一步一步来. 我们先从设备开始,设备的示意图如下: 看起来有模有样的,其实呢,它就是一个长方体,然后在长方体的正面贴上一张

HT for Web中3D流动效果的实现与应用

流动效果在3D领域有着广泛的应用场景,如上图中医学领域可通过3D的流动直观的观察人体血液的流动,燃气领域可用于监控管道内流动的液体或气体的流向.流速和温度等指标. 如今企业数据中心机房普遍面临着设备散热的问题,采用冷热通道方案可大大提高数据中心的散热能力,充分有效利用机柜和机房的空间,因此在电信的3D机房监控领域,也常需要借助流动的效果,对机房冷热通道系统进行监控. Hightopo的HT for Web作为3D客户端呈现解决方案,今天介绍的重点不在于采集这些指标,而在于如何应用HT的预定于3D

基于HT for Web的Web SCADA工控移动应用

在电力.油田燃气.供水管网等工业自动化领域Web SCADA的概念已经提出了多年,早先年的Web SCADA前端技术大部分还是基于Flex.Silverlight甚至Applet这样的重客户端方案,在HTML5流行前VML和SVG算是真正纯种Web方案也是有不少应用,近些年随着HTML5的流行,加上移动终端对HTML5支持的普及,越来越多新项目开始采用真正纯HTML5的方案,更具体的说大数据量应用性能高于SVG的Canvas方案,已经逐渐成为当今Web SCADA前端技术的首选标配方案. 最近客