Threejs中使用astar(A*)算法寻路导航,Threejs寻路定位导航

简介: Threejs中使用astar(A*)算法寻路导航,Threejs寻路定位导航

1,介绍


该示例使用的是 r95版本Three.js库。利用A*算法实现寻路、导航功能。添加坐标轴。

效果图如下:


2,主要说明


引入A*算法astar.js


<script type="text/javascript" src="libs/astar.js"></script>


初始化路网、障碍物,记录路网、障碍物位置信息


// 绘制路网
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;
    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;
    scene.add(line);
  }
}
// 初始化障碍物
function initGrid() {
  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);
        mesh.push(cube);
      }
    }
    graph.push(nodeRow);
  }
}

调用A*算法,传入路网和障碍物信息,返回计算结果。用返回计算结果绘制路径。


//计算路径
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);
}


3,源码


<!DOCTYPE html>
<html>
  <head>
    <title>Threejs中使用astar(A*)算法寻路导航</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" src="libs/astar.js"></script>
    <style>
      body {
        margin: 0;
        overflow: hidden;
      }
    </style>
  </head>
  <body>
    <div id="dom"></div>
    <script type="text/javascript">
      var camera;
      var renderer;
      var clock = new THREE.Clock();
      var length = 36;
      var ws = 2;
      var graph = [];
      var mesh = [];
      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 = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        // 将平面添加到场景中
        var plane = createPlaneGeometryBasicMaterial();
        scene.add(plane);
        // 在屏幕上显示坐标轴
        var axes = new THREE.AxesHelper(100);
        scene.add(axes);
        // var trackballControls = initTrackballControls(camera, renderer);
        scene.add(new THREE.AmbientLight(0x666666));
        var ambientLight = new THREE.AmbientLight("#ffffff", 1);
        scene.add(ambientLight);
        document.getElementById("dom").appendChild(renderer.domElement);
        initGround();
        initGrid();
        initGridArr();
        // 启动动画
        renderScene();
        // 创建一个地面
        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;
            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;
            scene.add(line);
          }
        }
        // 初始化障碍物
        function initGrid() {
          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);
                mesh.push(cube);
              }
            }
            graph.push(nodeRow);
          }
        }
        function initGridArr() {
          for (var i = 0; i < length / ws; i++) {
            var nodeRow = [];
            for (var j = 0; j < length / ws; j++) {
              nodeRow.push(1);
            }
            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 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;
            }
          }
          initSphere(k, m); //初始化球体
        }
        document.addEventListener('click', pickupObjects, false); //监听单击拾取对象初始化球体
        // 动画渲染
        var step = 5;
        function renderScene() {
          orbit.update();
          // 使用requestAnimationFrame函数进行渲染
          requestAnimationFrame(renderScene);
          renderer.render(scene, camera);
        }
        // 渲染的场景
        renderer.render(scene, camera);
      }
      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>
目录
相关文章
|
算法 定位技术
Threejs中使用A*算法寻路导航,Threejs室内室外地图导航
Threejs中使用A*算法寻路导航,Threejs室内室外地图导航
785 0
Threejs中使用A*算法寻路导航,Threejs室内室外地图导航
|
18天前
|
算法 定位技术 图形学
unity3d寻路算法
unity3d寻路算法
|
12月前
|
算法 定位技术
“ 探索迷局:解密广度寻路算法 “(二)
“ 探索迷局:解密广度寻路算法 “
|
算法 定位技术
基于Astar算法的栅格地图最优路径搜索matlab仿真,可以修改任意数量栅格
基于Astar算法的栅格地图最优路径搜索matlab仿真,可以修改任意数量栅格
184 0
基于Astar算法的栅格地图最优路径搜索matlab仿真,可以修改任意数量栅格
|
算法 定位技术
基于Astar算法的栅格地图目标最短路径搜索算法MATLAB仿真,带GUI界面
基于Astar算法的栅格地图目标最短路径搜索算法MATLAB仿真,带GUI界面
163 0
基于Astar算法的栅格地图目标最短路径搜索算法MATLAB仿真,带GUI界面
|
算法 机器人
m分别使用Dijkstra算法和Astar算法进行刚体机器人最短路径搜索和避障算法的matlab仿真,带GUI界面
m分别使用Dijkstra算法和Astar算法进行刚体机器人最短路径搜索和避障算法的matlab仿真,带GUI界面
139 0
m分别使用Dijkstra算法和Astar算法进行刚体机器人最短路径搜索和避障算法的matlab仿真,带GUI界面
|
存储 人工智能 算法
Unity 实现A* 寻路算法
Unity 实现A* 寻路算法
311 2
Unity 实现A* 寻路算法
|
人工智能 算法 安全
游戏人工智能——A*寻路算法实践
A*寻路算法实践 一、题目背景 随着多媒体设备、虚拟现实、增强现实、物联网等技术的飞跃发展,计算速度与存储容量的日益提高以及相关软件的研究取得长足进步,人工智能的应用得以进一步推广发展起来。地图寻径问题是人工智能技术的一个重要领域。在网络游戏中,寻径问题必须考虑多方面的因素,比如游戏地图中文件结构和起点与目标点之间是否可以连通以及游戏运行时运行内存资源占用、可扩展更新性、安全程度等。长久以来,游戏开发者在开发过程中为了实现这些绞尽脑汁。 在搜索寻径问题中,Dijkstra算法是目前许多工程解决最短路径
301 0
游戏人工智能——A*寻路算法实践
|
机器学习/深度学习 传感器 算法
【无人机】基于卡尔曼滤波实现无人机捷联惯导算法与组合导航附matlab代码
【无人机】基于卡尔曼滤波实现无人机捷联惯导算法与组合导航附matlab代码
488. 祖玛游戏 :「搜索 + 剪枝」&「AStar 算法」
488. 祖玛游戏 :「搜索 + 剪枝」&「AStar 算法」