Threejs中使用A*算法寻路导航

 

<!DOCTYPE html>
<html>
	<head>
		<title>Threejs中使用A*算法寻路导航,Threejs室内室外地图导航</title>
		<script type="text/javascript" src="libs/three.js"></script>
		<script type="text/javascript" src="libs/OrbitControls.js"></script>
		<script type="text/javascript" charset="UTF-8" src="libs/other/Tween.min.js"></script>
		<script type="text/javascript" charset="UTF-8" src="libs/three/loaders/GLTFLoader.js"></script>
 
		<script type="text/javascript" src="libs/OBJLoader.js"></script>
		<script type="text/javascript" src="libs/MTLLoader.js"></script>
 
		<script type="text/javascript" src="libs/util.js"></script>
		<script type="text/javascript" src="libs/util/dat.gui.js"></script>
		<script type="text/javascript" src="libs/astar.js"></script>
		<style>
			body {
				margin: 0;
				overflow: hidden;
			}
		</style>
	</head>
	<body>
		<div id="webgl-output"></div>
		<script type="text/javascript">
			var camera;
			var renderer;
			var clock = new THREE.Clock();
			var mixer = new THREE.AnimationMixer();
			var clipAction;
			var animationClip;
			var length = 36;
			var ws = 2;
			var graph = []; // 记录地图
			var meshArr = new Array(); // 记录障碍物对象数据
			var meshxy = [{
					"x": 35,
					"y": 7
				},
				{
					"x": 35,
					"y": 7
				},
				{
					"x": 35,
					"y": 9
				},
				{
					"x": 35,
					"y": 11
				},
				{
					"x": 29,
					"y": 11
				},
				{
					"x": 29,
					"y": 13
				},
				{
					"x": 33,
					"y": 13
				},
				{
					"x": 33,
					"y": 11
				},
				{
					"x": 33,
					"y": 9
				},
				{
					"x": 33,
					"y": 5
				},
				{
					"x": 33,
					"y": 7
				},
				{
					"x": 29,
					"y": 5
				},
				{
					"x": 31,
					"y": 5
				},
				{
					"x": 31,
					"y": 11
				},
				{
					"x": 27,
					"y": 5
				},
				{
					"x": 25,
					"y": 5
				},
				{
					"x": 25,
					"y": 7
				},
				{
					"x": 25,
					"y": 9
				},
				{
					"x": 25,
					"y": 11
				},
				{
					"x": 25,
					"y": 13
				},
				{
					"x": 23,
					"y": 9
				},
				{
					"x": 21,
					"y": 9
				},
				{
					"x": 19,
					"y": 9
				},
				{
					"x": 19,
					"y": 11
				},
				{
					"x": 19,
					"y": 13
				},
				{
					"x": 15,
					"y": 9
				},
				{
					"x": 13,
					"y": 7
				},
				{
					"x": 13,
					"y": 9
				},
				{
					"x": 13,
					"y": 11
				},
				{
					"x": 11,
					"y": 7
				},
				{
					"x": 13,
					"y": 5
				},
				{
					"x": 11,
					"y": 5
				},
				{
					"x": 7,
					"y": 5
				},
				{
					"x": 5,
					"y": 5
				},
				{
					"x": 5,
					"y": 7
				},
				{
					"x": 7,
					"y": 7
				},
				{
					"x": 7,
					"y": 9
				},
				{
					"x": 7,
					"y": 11
				},
				{
					"x": 5,
					"y": 11
				},
				{
					"x": 5,
					"y": 9
				},
				{
					"x": 7,
					"y": 15
				},
				{
					"x": 7,
					"y": 17
				},
				{
					"x": 7,
					"y": 19
				},
				{
					"x": 11,
					"y": 23
				},
				{
					"x": 11,
					"y": 17
				},
				{
					"x": 11,
					"y": 21
				},
				{
					"x": 11,
					"y": 19
				},
				{
					"x": 17,
					"y": 25
				},
				{
					"x": 17,
					"y": 27
				},
				{
					"x": 17,
					"y": 29
				},
				{
					"x": 19,
					"y": 25
				},
				{
					"x": 21,
					"y": 25
				},
				{
					"x": 17,
					"y": 21
				},
				{
					"x": 17,
					"y": 23
				},
				{
					"x": 17,
					"y": 19
				},
				{
					"x": 15,
					"y": 19
				},
				{
					"x": 13,
					"y": 19
				},
				{
					"x": 7,
					"y": 29
				},
				{
					"x": 7,
					"y": 31
				},
				{
					"x": 7,
					"y": 33
				},
				{
					"x": 9,
					"y": 33
				},
				{
					"x": 13,
					"y": 33
				},
				{
					"x": 11,
					"y": 33
				},
				{
					"x": 13,
					"y": 31
				},
				{
					"x": 13,
					"y": 29
				},
				{
					"x": 15,
					"y": 33
				},
				{
					"x": 17,
					"y": 33
				},
				{
					"x": 19,
					"y": 33
				},
				{
					"x": 21,
					"y": 33
				},
				{
					"x": 25,
					"y": 29
				},
				{
					"x": 25,
					"y": 31
				},
				{
					"x": 25,
					"y": 33
				},
				{
					"x": 27,
					"y": 29
				},
				{
					"x": 29,
					"y": 29
				},
				{
					"x": 29,
					"y": 23
				},
				{
					"x": 27,
					"y": 23
				},
				{
					"x": 25,
					"y": 23
				},
				{
					"x": 29,
					"y": 21
				},
				{
					"x": 29,
					"y": 19
				},
				{
					"x": 33,
					"y": 19
				},
				{
					"x": 33,
					"y": 21
				},
				{
					"x": 33,
					"y": 23
				},
				{
					"x": 33,
					"y": 25
				},
				{
					"x": 33,
					"y": 27
				},
				{
					"x": 33,
					"y": 29
				},
				{
					"x": 33,
					"y": 31
				},
				{
					"x": 33,
					"y": 33
				},
				{
					"x": 31,
					"y": 35
				},
				{
					"x": 29,
					"y": 35
				},
				{
					"x": 27,
					"y": 35
				},
				{
					"x": 25,
					"y": 35
				},
				{
					"x": 7,
					"y": 23
				},
				{
					"x": 11,
					"y": 15
				},
				{
					"x": 9,
					"y": 15
				},
				{
					"x": 35,
					"y": 9
				},
				{
					"x": 35,
					"y": 11
				},
				{
					"x": 29,
					"y": 11
				},
				{
					"x": 29,
					"y": 13
				},
				{
					"x": 33,
					"y": 13
				},
				{
					"x": 33,
					"y": 11
				},
				{
					"x": 33,
					"y": 9
				},
				{
					"x": 33,
					"y": 5
				},
				{
					"x": 33,
					"y": 7
				},
				{
					"x": 29,
					"y": 5
				},
				{
					"x": 31,
					"y": 5
				},
				{
					"x": 31,
					"y": 11
				},
				{
					"x": 27,
					"y": 5
				},
				{
					"x": 25,
					"y": 5
				},
				{
					"x": 25,
					"y": 7
				},
				{
					"x": 25,
					"y": 9
				},
				{
					"x": 25,
					"y": 11
				},
				{
					"x": 25,
					"y": 13
				},
				{
					"x": 23,
					"y": 9
				},
				{
					"x": 21,
					"y": 9
				},
				{
					"x": 19,
					"y": 9
				},
				{
					"x": 19,
					"y": 11
				},
				{
					"x": 19,
					"y": 13
				},
				{
					"x": 15,
					"y": 9
				},
				{
					"x": 13,
					"y": 7
				},
				{
					"x": 13,
					"y": 9
				},
				{
					"x": 13,
					"y": 11
				},
				{
					"x": 11,
					"y": 7
				},
				{
					"x": 13,
					"y": 5
				},
				{
					"x": 11,
					"y": 5
				},
				{
					"x": 7,
					"y": 5
				},
				{
					"x": 5,
					"y": 5
				},
				{
					"x": 5,
					"y": 7
				},
				{
					"x": 7,
					"y": 7
				},
				{
					"x": 7,
					"y": 9
				},
				{
					"x": 7,
					"y": 11
				},
				{
					"x": 5,
					"y": 11
				},
				{
					"x": 5,
					"y": 9
				},
				{
					"x": 7,
					"y": 15
				},
				{
					"x": 7,
					"y": 17
				},
				{
					"x": 7,
					"y": 19
				},
				{
					"x": 11,
					"y": 23
				},
				{
					"x": 11,
					"y": 17
				},
				{
					"x": 11,
					"y": 21
				},
				{
					"x": 11,
					"y": 19
				},
				{
					"x": 17,
					"y": 25
				},
				{
					"x": 17,
					"y": 27
				},
				{
					"x": 17,
					"y": 29
				},
				{
					"x": 19,
					"y": 25
				},
				{
					"x": 21,
					"y": 25
				},
				{
					"x": 17,
					"y": 21
				},
				{
					"x": 17,
					"y": 23
				},
				{
					"x": 17,
					"y": 19
				},
				{
					"x": 15,
					"y": 19
				},
				{
					"x": 13,
					"y": 19
				},
				{
					"x": 7,
					"y": 29
				},
				{
					"x": 7,
					"y": 31
				},
				{
					"x": 7,
					"y": 33
				},
				{
					"x": 9,
					"y": 33
				},
				{
					"x": 13,
					"y": 33
				},
				{
					"x": 11,
					"y": 33
				},
				{
					"x": 13,
					"y": 31
				},
				{
					"x": 13,
					"y": 29
				},
				{
					"x": 15,
					"y": 33
				},
				{
					"x": 17,
					"y": 33
				},
				{
					"x": 19,
					"y": 33
				},
				{
					"x": 21,
					"y": 33
				},
				{
					"x": 25,
					"y": 29
				},
				{
					"x": 25,
					"y": 31
				},
				{
					"x": 25,
					"y": 33
				},
				{
					"x": 27,
					"y": 29
				},
				{
					"x": 29,
					"y": 29
				},
				{
					"x": 29,
					"y": 23
				},
				{
					"x": 27,
					"y": 23
				},
				{
					"x": 25,
					"y": 23
				},
				{
					"x": 29,
					"y": 21
				},
				{
					"x": 29,
					"y": 19
				},
				{
					"x": 33,
					"y": 19
				},
				{
					"x": 33,
					"y": 21
				},
				{
					"x": 33,
					"y": 23
				},
				{
					"x": 33,
					"y": 25
				},
				{
					"x": 33,
					"y": 27
				},
				{
					"x": 33,
					"y": 29
				},
				{
					"x": 33,
					"y": 31
				},
				{
					"x": 33,
					"y": 33
				},
				{
					"x": 31,
					"y": 35
				},
				{
					"x": 29,
					"y": 35
				},
				{
					"x": 27,
					"y": 35
				},
				{
					"x": 25,
					"y": 35
				},
				{
					"x": 7,
					"y": 23
				},
				{
					"x": 11,
					"y": 15
				},
				{
					"x": 9,
					"y": 15
				},
				{
					"x": 35,
					"y": 9
				},
				{
					"x": 35,
					"y": 11
				},
				{
					"x": 29,
					"y": 11
				},
				{
					"x": 29,
					"y": 13
				},
				{
					"x": 33,
					"y": 13
				},
				{
					"x": 33,
					"y": 11
				},
				{
					"x": 33,
					"y": 9
				},
				{
					"x": 33,
					"y": 5
				},
				{
					"x": 33,
					"y": 7
				},
				{
					"x": 29,
					"y": 5
				},
				{
					"x": 31,
					"y": 5
				},
				{
					"x": 31,
					"y": 11
				},
				{
					"x": 27,
					"y": 5
				},
				{
					"x": 25,
					"y": 5
				},
				{
					"x": 25,
					"y": 7
				},
				{
					"x": 25,
					"y": 9
				},
				{
					"x": 25,
					"y": 11
				},
				{
					"x": 25,
					"y": 13
				},
				{
					"x": 23,
					"y": 9
				},
				{
					"x": 21,
					"y": 9
				},
				{
					"x": 19,
					"y": 9
				},
				{
					"x": 19,
					"y": 11
				},
				{
					"x": 19,
					"y": 13
				},
				{
					"x": 15,
					"y": 9
				},
				{
					"x": 13,
					"y": 7
				},
				{
					"x": 13,
					"y": 9
				},
				{
					"x": 13,
					"y": 11
				},
				{
					"x": 11,
					"y": 7
				},
				{
					"x": 13,
					"y": 5
				},
				{
					"x": 11,
					"y": 5
				},
				{
					"x": 7,
					"y": 5
				},
				{
					"x": 5,
					"y": 5
				},
				{
					"x": 5,
					"y": 7
				},
				{
					"x": 7,
					"y": 7
				},
				{
					"x": 7,
					"y": 9
				},
				{
					"x": 7,
					"y": 11
				},
				{
					"x": 5,
					"y": 11
				},
				{
					"x": 5,
					"y": 9
				},
				{
					"x": 7,
					"y": 15
				},
				{
					"x": 7,
					"y": 17
				},
				{
					"x": 7,
					"y": 19
				},
				{
					"x": 11,
					"y": 23
				},
				{
					"x": 11,
					"y": 17
				},
				{
					"x": 11,
					"y": 21
				},
				{
					"x": 11,
					"y": 19
				},
				{
					"x": 17,
					"y": 25
				},
				{
					"x": 17,
					"y": 27
				},
				{
					"x": 17,
					"y": 29
				},
				{
					"x": 19,
					"y": 25
				},
				{
					"x": 21,
					"y": 25
				},
				{
					"x": 17,
					"y": 21
				},
				{
					"x": 17,
					"y": 23
				},
				{
					"x": 17,
					"y": 19
				},
				{
					"x": 15,
					"y": 19
				},
				{
					"x": 13,
					"y": 19
				},
				{
					"x": 7,
					"y": 29
				},
				{
					"x": 7,
					"y": 31
				},
				{
					"x": 7,
					"y": 33
				},
				{
					"x": 9,
					"y": 33
				},
				{
					"x": 13,
					"y": 33
				},
				{
					"x": 11,
					"y": 33
				},
				{
					"x": 13,
					"y": 31
				},
				{
					"x": 13,
					"y": 29
				},
				{
					"x": 15,
					"y": 33
				},
				{
					"x": 17,
					"y": 33
				},
				{
					"x": 19,
					"y": 33
				},
				{
					"x": 21,
					"y": 33
				},
				{
					"x": 25,
					"y": 29
				},
				{
					"x": 25,
					"y": 31
				},
				{
					"x": 25,
					"y": 33
				},
				{
					"x": 27,
					"y": 29
				},
				{
					"x": 29,
					"y": 29
				},
				{
					"x": 29,
					"y": 23
				},
				{
					"x": 27,
					"y": 23
				},
				{
					"x": 25,
					"y": 23
				},
				{
					"x": 29,
					"y": 21
				},
				{
					"x": 29,
					"y": 19
				},
				{
					"x": 33,
					"y": 19
				},
				{
					"x": 33,
					"y": 21
				},
				{
					"x": 33,
					"y": 23
				},
				{
					"x": 33,
					"y": 25
				},
				{
					"x": 33,
					"y": 27
				},
				{
					"x": 33,
					"y": 29
				},
				{
					"x": 33,
					"y": 31
				},
				{
					"x": 33,
					"y": 33
				},
				{
					"x": 31,
					"y": 35
				},
				{
					"x": 29,
					"y": 35
				},
				{
					"x": 27,
					"y": 35
				},
				{
					"x": 25,
					"y": 35
				},
				{
					"x": 7,
					"y": 23
				},
				{
					"x": 11,
					"y": 15
				},
				{
					"x": 9,
					"y": 15
				},
				{
					"x": 19,
					"y": 21
				},
				{
					"x": 21,
					"y": 21
				},
				{
					"x": 21,
					"y": 19
				},
				{
					"x": 29,
					"y": 27
				},
				{
					"x": 29,
					"y": 25
				}
			]; // 记录障碍坐标物数据
			var lineArr = new Array(); // 记录路网数据
			var meshbool = false; // 显示障碍物
			var linebool = false; // 显示路网
			var resultArray = new Array();
			var isCaculate = false;
 
			function init() {
				// 创建一个场景,它将包含我们所有的元素,如物体,相机和灯光。
				var scene = new THREE.Scene();
 
				var urls = [
					'assets/textures/cubemap/flowers/posx.jpg',
					'assets/textures/cubemap/flowers/negx.jpg',
					'assets/textures/cubemap/flowers/posy.jpg',
					'assets/textures/cubemap/flowers/negy.jpg',
					'assets/textures/cubemap/flowers/posz.jpg',
					'assets/textures/cubemap/flowers/negz.jpg'
				];
 
				var cubeLoader = new THREE.CubeTextureLoader();
				scene.background = cubeLoader.load(urls);
 
				// 创建一个摄像机,它定义了我们正在看的地方
				camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 0.1, 1000);
				// 将摄像机对准场景的中心
				camera.position.x = 60;
				camera.position.y = 35;
				camera.position.z = 60;
				camera.lookAt({
					x: 0,
					y: 5,
					z: -20
				});
				var orbit = new THREE.OrbitControls(camera);
				orbit.target = camera.position;
				orbit.update();
 
				// 创建一个渲染器并设置大小,WebGLRenderer将会使用电脑显卡来渲染场景
				// initialize basic renderer
				renderer = initRenderer({
					antialias: true,
					logarithmicDepthBuffer: true,
				});
 
				// 将平面添加到场景中
				var plane = createPlaneGeometryBasicMaterial();
				scene.add(plane);
 
				// 在屏幕上显示坐标轴
				var axes = new THREE.AxesHelper(100);
				scene.add(axes);
 
				scene.add(new THREE.AmbientLight(0x666666));
				scene.add(new THREE.AmbientLight("#ffffff", 1));
 
				initModel();
				// initPeople();
 
				initGround();
				initGrid();
 
				var i = 0;
 
				function tweenComplete() {
					if (i < points.length) {
						switch (i) {
							case 0:
								aaa.rotateY(Math.PI);
								break;
							case 1:
							case 5:
							case 8:
							case 9:
								aaa.rotateY(-0.5 * Math.PI);
								break;
							case 2:
							case 3:
							case 4:
							case 6:
							case 7:
								aaa.rotateY(0.5 * Math.PI);
								break;
							case 10:
								mixer.stopAllAction();
								break;
 
						}
						tween = new TWEEN.Tween(points[i])
							.to(points[i + 1], 3000)
							.easing(TWEEN.Easing.Linear.None)
							.onUpdate(function() {
								aaa.position.set(this.x, this.y, this.z);
							})
							.onComplete(tweenComplete)
							.start();
						i++;
					}
				}
 
 
				// 使用GUI调试库
				var controls = new function() {
					this.clickBool = false;
 
					this.displayRoadGrid = function() {
						for (var i = 0; i < lineArr.length; i++) {
							if (linebool) {
								// 显示路网
								scene.add(lineArr[i].obj);
							} else {
								// 隐藏路网
								var obj = scene.getObjectByName(lineArr[i].name);
								scene.remove(obj);
							}
						}
						linebool = !linebool
					}
 
					this.displayObstacles = function() {
						for (var i = 0; i < meshArr.length; i++) {
							if (meshbool) {
								// 显示障碍物
								scene.add(meshArr[i].obj);
							} else {
								// 隐藏障碍物
								var obj = scene.getObjectByName(meshArr[i].name);
								scene.remove(obj);
							}
						}
						meshbool = !meshbool
					}
 
					this.outputObstacles = function() {
						for (var i = 0; i < meshArr.length; i++) {
							meshxy.push({
								x: meshArr[i].x,
								y: meshArr[i].y
							})
						}
						console.log(meshArr)
						console.log(lineArr)
						console.log(meshxy)
						localStorage.setItem('meshArr', JSON.stringify(meshArr));
						localStorage.setItem('lineArr', JSON.stringify(lineArr));
						localStorage.setItem('meshxy', JSON.stringify(meshxy));
					}
				}
				var gui = new dat.GUI();
				// 隐藏显示障路网
				gui.add(controls, 'displayRoadGrid');
				// 隐藏显示障碍物
				gui.add(controls, 'displayObstacles');
				// 输出障碍物对象
				gui.add(controls, 'outputObstacles');
				gui.add(controls, "clickBool");
 
				// 启动动画
				renderScene();
 
				// 添加模型
				function initModel() {
					var mtlLoader = new THREE.MTLLoader();
					mtlLoader.setPath("assets/models/obj_mtl/")
					mtlLoader.load('city.mtl', function(materials) {
						materials.preload();
 
						var objLoader = new THREE.OBJLoader();
						objLoader.setMaterials(materials);
						objLoader.load('assets/models/obj_mtl/city.obj', function(object) {
							var mesh = object;
							mesh.scale.set(3, 3, 3);
							mesh.position.set(18, 0, 18);
							scene.add(mesh);
						});
					});
				}
 
				// 添加人物模型
				function initPeople() {
					var loader = new THREE.GLTFLoader();
					loader.load('assets/models/CesiumMan/CesiumMan.gltf', function(result) {
						result.scene.scale.set(1, 1, 1);
						result.scene.translateY(0);
						aaa = result.scene;
						scene.add(result.scene);
 
						tweenComplete();
 
						mixer = new THREE.AnimationMixer(result.scene);
						animationClip = result.animations[0];
						clipAction = mixer.clipAction(animationClip).play();
						animationClip = clipAction.getClip();
					});
				}
 
				// 创建一个地面并设置草坪材质
				function createPlaneGeometryBasicMaterial() {
					var textureLoader = new THREE.TextureLoader();
					var cubeMaterial = new THREE.MeshStandardMaterial({
						map: textureLoader.load("assets/textures/stone/cd.jpg"),
					});
					cubeMaterial.map.wrapS = THREE.RepeatWrapping;
					cubeMaterial.map.wrapT = THREE.RepeatWrapping;
					cubeMaterial.map.repeat.set(18, 18)
					// 创建地平面并设置大小
					var planeGeometry = new THREE.PlaneGeometry(500, 500);
					var plane = new THREE.Mesh(planeGeometry, cubeMaterial);
 
					// 设置平面位置并旋转
					plane.rotation.x = -0.5 * Math.PI;
					plane.position.x = 0;
					plane.position.z = 0;
					return plane;
				}
 
				// 绘制线路
				function initLine(pArr) {
					var points = [];
					var geometry = new THREE.Geometry();
					for (var i = 0; i < pArr.length; i++) {
						var randomX = pArr[i].x;
						var randomY = pArr[i].y;
						var randomZ = pArr[i].z;
						var vector = new THREE.Vector3(randomX, randomY, randomZ);
						geometry.vertices.push(vector);
						points.push(vector);
					}
					var material = new THREE.LineBasicMaterial({
						color: 0x0000FF
					});
					var line = new THREE.Line(geometry, material);
					scene.add(line);
					return points;
				}
 
				// 绘制路网
				function initGround() {
					var geometry = new THREE.Geometry();
					geometry.vertices.push(new THREE.Vector3(0, 0, 0));
					geometry.vertices.push(new THREE.Vector3(length, 0, 0));
 
					for (var i = 0; i <= length / ws; i++) {
						var material = new THREE.LineBasicMaterial({
							color: 0x808080
						});
						var line = new THREE.Line(geometry, material);
						line.position.z = i * ws;
						line.name = "line_" + i;
						lineArr.push({
							name: "line_" + i,
							obj: line
						});
						scene.add(line);
 
						var line = new THREE.Line(geometry, material);
						line.position.x = i * ws;
						line.position.z = length;
						line.rotation.y = 90 * Math.PI / 180;
						line.name = "line_" + i + 180;
						lineArr.push({
							name: "line_" + i + 180,
							obj: line
						});
						scene.add(line);
					}
				}
 
				// 初始化障碍物随机
				function initGrid() {
					for (var i = 0; i < length / ws; i++) {
						var nodeRow = [];
						for (var j = 0; j < length / ws; j++) {
							nodeRow.push(1);
						}
						graph.push(nodeRow);
					}
					if (meshxy.length > 0) {
						for (var i = 0; i < meshxy.length; i++) {
							initObstacles(meshxy[i].x, meshxy[i].y);
						}
					} else {
						for (var i = 0; i < length / ws; i++) {
							var nodeRow = [];
							for (var j = 0; j < length / ws; j++) {
								var salt = Math.random() * 7;
								if (salt > 2) {
									nodeRow.push(1);
								} else {
									nodeRow.push(0);
								}
								if (salt <= 2) {
									var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1), new THREE
										.MeshBasicMaterial({
											color: 0xC0C0C0
										}));
									let x = ws * j + ws / 2;
									let z = ws * i + ws / 2;
									cube.position.set(x, 1.2, z);
									scene.add(cube);
								}
							}
							graph.push(nodeRow);
						}
 
					}
				}
 
				//计算路径
				function caculatePath(resultArray) {
					var maps = new Graph(graph); // 地图
					var startX = parseInt(resultArray[0].position.z / ws);
					var startY = parseInt(resultArray[0].position.x / ws);
					var endX = parseInt(resultArray[1].position.z / ws);
					var endY = parseInt(resultArray[1].position.x / ws);
					var start = maps.grid[startX][startY];
					var end = maps.grid[endX][endY];
					result = astar.search(maps, start, end);
					if (result.length == 0) {
						alert("无可到达路径");
						cleanSphere();
						return;
					}
 
					var nArr = [{
						x: resultArray[0].position.x,
						z: resultArray[0].position.z,
						y: 1.2
					}];
					for (var i = 0; i < result.length; i++) {
						let d = {
							x: result[i].y * ws + ws / 2,
							y: 1.2,
							z: result[i].x * ws + ws / 2,
						}
						nArr.push(d);
					}
					initLine(nArr);
				}
 
				//清除小球
				function cleanSphere() {
					let child = scene.children; //获取场景中的所有子对象
					for (var i = 0; i < child.length; i++) {
						if (child[i].geometry instanceof THREE.SphereGeometry) { //几何对象是球体几何
							scene.remove(child[i]); //从场景中移除
							i--;
						}
					}
					isCaculate = false;
				}
 
				//初始球体
				function initSphere(x, z) {
					if (isCaculate) {
						cleanSphere();
					}
					var geometry = new THREE.SphereGeometry(ws / 2, 30, 30); //球体几何
					var material = new THREE.MeshBasicMaterial({
						color: 0xffff00
					}); //网格基础材料
 
					if (resultArray.length == 0) {
						var sphere = new THREE.Mesh(geometry, material);
						sphere.position.x = x;
						sphere.position.y = 1;
						sphere.position.z = z;
						resultArray.push(sphere);
						scene.add(sphere);
					} else if (resultArray[0].position.x != x || resultArray[0].position.z != z) {
						var sphere = new THREE.Mesh(geometry, material);
						sphere.position.x = x;
						sphere.position.y = 1;
						sphere.position.z = z;
						resultArray.push(sphere);
						scene.add(sphere);
						caculatePath(resultArray);
						isCaculate = true;
						resultArray = new Array();
					}
				}
 
				// 绘制障碍物
				function initObstacles(x, z) {
					var name = "mesh_" + x + z;
					var obj = scene.getObjectByName(name);
					if (obj) {
						scene.remove(obj);
						for (var i = 0; i < meshArr.length; i++) {
							if (meshArr[i].name == name) {
								meshArr.splice(i, 1);
							}
						}
						graph[parseInt(z / ws)][parseInt(x / ws)] = 1;
					} else {
						var geometry = new THREE.BoxGeometry(ws, ws, ws); //球体几何
						var material = new THREE.MeshBasicMaterial({
							color: 0xff0000
						});
 
						var sphere = new THREE.Mesh(geometry, material);
						sphere.position.x = x;
						sphere.position.y = 1;
						sphere.position.z = z;
						sphere.name = name;
						scene.add(sphere);
						meshArr.push({
							name: name,
							obj: sphere,
							x: x,
							y: z,
						});
						graph[parseInt(z / ws)][parseInt(x / ws)] = 0;
					}
				}
 
				// 拾取对象
				function pickupObjects(event) {
					// 点击屏幕创建一个向量
					var raycaster = new THREE.Raycaster();
					var vector = new THREE.Vector2((event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window
						.innerHeight) * 2 + 1);
					var fxl = new THREE.Vector3(0, 1, 0);
					var groundplane = new THREE.Plane(fxl, 0);
					raycaster.setFromCamera(vector, camera);
					var ray = raycaster.ray;
					let intersects = ray.intersectPlane(groundplane);
					let x = intersects.x;
					let z = intersects.z;
 
					if (x < 0 || z < 0 || length < z || length < x) {
						return;
					}
 
					var k, m;
					for (var i = 0; i < length; i += ws) {
						if (x >= i && x < i + ws) {
							k = i + ws / 2;
						}
					}
					for (var j = 0; j < length; j += ws) {
						if (z >= j && z < j + ws) {
							m = j + ws / 2;
						}
					}
 
 
					if (controls.clickBool) {
						initSphere(k, m); //初始化球体
					} else {
						initObstacles(k, m);
					}
				}
				document.addEventListener('click', pickupObjects, false); //监听单击拾取对象初始化球体
 
				// 动画渲染
				var step = 5;
 
				function renderScene() {
					TWEEN.update();
					var delta = clock.getDelta();
 
					orbit.update();
					mixer.update(delta);
 
					// 使用requestAnimationFrame函数进行渲染
					requestAnimationFrame(renderScene);
					renderer.render(scene, camera);
				}
 
				// 渲染的场景
				renderer.render(scene, camera);
 
				// 创建一个球形几何体
				function createSphereGeometryLambertMaterial(point) {
					// 创建一个球体
					var sphereGeometry = new THREE.SphereGeometry(0.2, 20, 20);
					var sphereMaterial = new THREE.MeshBasicMaterial({
						color: 0x7777ff,
						wireframe: true
					});
					var sphereMaterial = new THREE.MeshLambertMaterial({
						color: 0xff0000
					});
					var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
					// 设置该物体投射阴影
					sphere.castShadow = true;
 
					// 位置范围
					sphere.position.x = point.x;
					sphere.position.y = point.y;
					sphere.position.z = point.z;
					return sphere;
				}
			}
			window.onload = init;
 
			function onResize() {
				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();
				renderer.setSize(window.innerWidth, window.innerHeight);
			}
			// 监听调整大小事件
			window.addEventListener('resize', onResize, false);
		</script>
	</body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/885515.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot 使用自定义注解和枚举类对接口入参校验

目录 1. jar包导入2. 自定义注解3. 校验类4. 定义枚举类5. 被校验的实体类6. 全局异常拦截7. controller8. 测试 1. jar包导入 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId&g…

拯救神经健康!多系统萎缩患者必知的维生素“黄金组合”✨

亲爱的朋友们&#xff0c;今天我们来聊聊一个可能不太为人熟知但极其重要的健康话题——多系统萎缩&#xff08;MSA&#xff09;。面对这一挑战&#xff0c;科学合理的营养补充显得尤为重要。你知道吗&#xff1f;有几种维生素堪称神经系统的“黄金守护者”&#xff0c;它们能在…

【IOS】申请开发者账号(公司)

目录 申请开发者账号前提 查询/申请D-U-N-S 编号 申请开发者 官网&#xff1a;Apple Developer (简体中文) 申请开发者账号前提 如果是第一次申请建议注册一个新的apple id作为组织的开发者账号。&#xff08;确保apple id的个人信息是真实的&#xff0c;不能是网名或者是…

c++第十二章续(队列结构类模拟)

队列类 设计类&#xff0c;需要开发公有接口和私有实现 Queue类接口 公有接口&#xff1a; 默认初始化&#xff0c;和可以用显式初始化覆盖默认值 Queue类的实现 如何表示队列数据&#xff1a; 一种方法是使用new动态分配一个数组&#xff0c;它包含所需的元素数。不过&…

Python从入门到高手3.5节-程序实战之最小值算法

目录 3.5.1 算法思路 3.5.2 构造随机数 3.5.3 条件控制语句 3.5.4 完整的代码实现 3.5.5 大神薯条老师 3.5.1 算法思路 算法原理很简单&#xff0c;先任取两个数进行比较&#xff0c;以计算两个数中的最小值&#xff1a; 假设得到的最小值为min_&#xff0c;再用这两个数…

天坑!Spark+Hive+Paimon+Dolphinscheduler

背景: 数据中台项目使用Spark+Hive+Paimon做湖仓底层,调度任务使用的是基于Dolphinscheduler进行二开。在做离线脚本任务开发时,在Paimon库下执行非查询类SQL报错。 INSERT报错 DELETE报错 现状: 原始逻辑为数据中台中选择的Paimon数据源,实际上在Dolphinscheduler中是…

卷积神经网络(CNN)的计算量和参数怎么准确估计?

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 1. 卷积层&#xff08;Convolutional Layer&#xff09; a) 计算量估计&#xff1a; 卷积层的 FLOPs 2 * H_out * W_out * C_in * C_out * K_h * K_w 详细解释&#xff1a; H_out, W_out&#xff…

(JAVA)浅尝关于 “栈” 数据结构

1. 栈的概述&#xff1a; 1.1 生活中的栈 存储货物或供旅客住宿的地方&#xff0c;可引申为仓库、中转站。例如酒店&#xff0c;在古时候叫客栈&#xff0c;是供旅客休息的地方&#xff0c;旅客可以进客栈休息&#xff0c;休息完毕后就离开客栈 1.2计算机中的栈 将生活中的…

WebGIS包括哪些技术栈?怎么学习?

WebGIS&#xff0c;其实是利用Web开发技术结合地理信息系统&#xff08;GIS&#xff09;的产物&#xff0c;它是一种通过Internet实现GIS交互操作和服务的最佳途径。 WebGIS通过图形化界面直观地呈现地理信息和特定数据&#xff0c;具有可扩展性和跨平台性。 它提供交互性&am…

springboot实战学习(10)(ThreadLoacl优化获取用户详细信息接口)(重写拦截器afterCompletion()方法)

接着学习。之前的博客的进度&#xff1a;完成用户模块的注册接口的开发以及注册时的参数合法性校验、也基本完成用户模块的登录接口的主逻辑的基础上、JWT令牌"的组成与使用、完成了"登录认证"&#xff08;生成与验证JWT令牌&#xff09;以及完成获取用户详细信…

使用Qt实现实时数据动态绘制的折线图示例

基于Qt的 QChartView 和定时器来动态绘制折线图。它通过动画的方式逐步将数据点添加到图表上&#xff0c;并动态更新坐标轴的范围&#xff0c;提供了一个可以实时更新数据的折线图应用。以下是对代码的详细介绍及其功能解析&#xff1a; 代码概述 该程序使用Qt的 QChartView…

Vxe UI vue 使用 vxe-form 表单实现简历模板

Vxe UI 使用 vxe-form 表单实现简历模板 查看 github <template><div><p>边框&#xff1a;<vxe-switch v-model"border"></vxe-switch>标题背景&#xff1a;<vxe-switch v-model"titleBackground"></vxe-switch&…

鸿蒙开发(NEXT/API 12)【请求用户授权】手机侧应用开发

为保护用户隐私&#xff0c;Wear Engine的API需要用户授权才可以正常访问。建议开发者在用户首次调用Wear Engine开放能力的时候执行本章节操作。 申请用户穿戴设备权限 应用拉起华为账号登录和授权界面&#xff0c;由用户授权相应的数据访问权限。用户可以自主选择授权的数据…

计算机毕业设计 二手图书交易系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

如何利用ChatGPT开发一个盈利的AI写作助手网站

3-1 整体介绍写作助手及原型展示说明 在当今数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;技术正逐步改变我们的生活方式&#xff0c;特别是在内容创作领域。本文将详细介绍如何利用ChatGPT技术&#xff0c;开发一个能够生成高质量内容的AI写作助手网站&#xff…

黑马头条day10 热点文章定时文章

day8-9是项目实战没有新东西 暂时跳过 进度到这里 但是后边的东西一直跑不通 调度一直失败 我也不知道哪里出了问题 整tm一天了也没搞出来 心态炸了 主要是xxl调度算是新内容 但是一直跑不出来就很烦 所谓的热点也就是计算权值然后存储到redis就行了 未解决&#xff1a; we…

解决Pymysql has no attribute ‘escape_string‘ 并且无法引入该模块

打印出的pymysql版本是1.4.6 需要import这个module&#xff0c;并且根据pymysql的版本import的方式还不同 import pymysqlif pymysql.__version__ >1.0.0:from pymysql.converters import escape_string else:escape_string lambda x: pymysql.escape_string(x)然而&am…

基于ESP8266—AT指令连接阿里云+MQTT透传数据(3)

MQTT_RX设备为接收(订阅)数据的Topic,使用ESP8266通过AT指令实现。 首先需要串口通信软件,如 SSCOM、PuTTY、SecureCRT 等串口调试工具,功能丰富,支持常见的串口调试功能,用于发送AT指令。 以下是ESP8266通过AT指令连接阿里云MQTT服务的步骤: 1、初始化WiFi 发送下面…

BOM对象

BOM对象 ECMAScript BOM DOM BOM&#xff08;Browser Object Model&#xff09;浏览器对象模型 BOM 使 JavaScript 有能力与浏览器“对话” BOM尚无正式标准,但是浏览器已经&#xff08;几乎&#xff09;实现了 JavaScript 交互性方面的相同方法和属性&#xff08;window&a…

详解TCP协议(三次握手四次挥手)

1. TCP通信时序 下图是一次TCP通讯的时序图。TCP连接建立断开。包含大家熟知的三次握手和四次握手。 在这个例子中&#xff0c;首先客户端主动发起连接、发送请求&#xff0c;然后服务器端响应请求&#xff0c;然后客户端主动关闭连接。两条竖线表示通讯的两端&#xff0c;从上…