Threejs中使用A*算法寻路导航,Threejs室内室外地图导航

简介: Threejs中使用A*算法寻路导航,Threejs室内室外地图导航

1,介绍


该示例使用的是 r95版本Three.js库。这里利用A*算法实现室内室外寻路、导航功能。

效果图如下:

2,主要说明


1,初始化路网

2,设置路障,我这里是使用鼠标点击设置路障,如下图

3,调用算法传入路网数据实现导航



3,源码


<!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>
目录
相关文章
|
2月前
|
算法 数据可视化 新制造
Threejs路径规划_基于A*算法案例完整版
这篇文章详细介绍了如何在Three.js中完整实现基于A*算法的路径规划案例,包括网格构建、路径寻找算法的实现以及路径可视化展示等方面的内容。
87 0
Threejs路径规划_基于A*算法案例完整版
|
2月前
|
存储 算法 机器人
Threejs路径规划_基于A*算法案例V2
这篇文章详细介绍了如何在Three.js中使用A*算法进行高效的路径规划,并通过三维物理电路的实例演示了路径计算和优化的过程。
89 0
|
4月前
|
算法
互动游戏解决遇到问题之基于射线投射寻路算法的问题如何解决
互动游戏解决遇到问题之基于射线投射寻路算法的问题如何解决
|
5月前
|
Dart 算法 数据可视化
用flutter实现五种寻路算法的可视化效果,快来看看!
半年前我写了一篇有关排序算法可视化的文章,挺有意思,还被张风捷特烈-张老师收录进了FlutterUnit,今天让我们再来做一个有关寻路算法的可视化效果吧!
|
算法 测试技术 定位技术
滴滴出行 地图感知算法 面经
滴滴出行 地图感知算法 面经
78 0
|
7月前
|
算法 定位技术 图形学
unity3d寻路算法
unity3d寻路算法
159 8
|
7月前
|
算法 定位技术
【算法】 用Prolog解决地图着色问题
【算法】 用Prolog解决地图着色问题
101 0
|
传感器 算法
m基于虚拟力优化算法的二维室内红外传感器部署策略matlab仿真
m基于虚拟力优化算法的二维室内红外传感器部署策略matlab仿真
298 4
|
机器学习/深度学习 算法 机器人
【路径规划】基于海鸥优化算法实现栅格地图机器人路径规划附matlab代码
【路径规划】基于海鸥优化算法实现栅格地图机器人路径规划附matlab代码
|
算法 Java
导航【数据结构与算法Java】
导航【数据结构与算法Java】
53 0