news 2026/3/25 20:55:42

纯前端网格路径规划:PathFinding.js的使用方法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
纯前端网格路径规划:PathFinding.js的使用方法

点赞 + 关注 + 收藏 = 学会了

本文简介

在 Web 应用和游戏中,路径规划是一个核心功能,无论是在地图导航、策略游戏的单位移动,还是虚拟现实中的导航辅助,都离不开高效的路径查找算法。

在一个 Web 项目中,路径规划通常是放在后端做的。但其实前端也可以实现这个功能。在前端实现还可以降低服务器压力。

PathFinding.js作为一个基于网格的纯前端路径规划工具,其轻量级、易于集成和强大的功能,是「纯前端」实现路径规划的一个不错选择。

本文将探讨PathFinding.js的基础使用方法。

在学习PathFinding.js之前,可以先体验一下它的能力。

  • 体验地址:https://qiao.github.io/PathFinding.js/visual/

  • PathFinding.js仓库:https://github.com/qiao/PathFinding.js

安装

使用 npm 的方式将PathFinding.js安装到项目中

npminstallpathfinding

基础用法

我用React+PathFinding.js举例说明。

使用PathFinding.js实现路径规划,需要做以下几步:

  1. 引入PathFinding.js
  2. 创建网格地图(有地图才有路嘛)。
  3. 设置路障(哪里不可以走)。
  4. 设置起点和终点,调用路径规划算法,将可行路径规划出来。

一步步来,先看看这些功能要调哪些API。

1、引入 PathFinding.js

在使用PathFinding.js之前需要将其引入。

importPFfrom'pathfinding'

2、创建网格 (Grid)

PF.GridPathFinding.js库中的一个核心组件,它用于创建和表示一个二维网格,这个网格是路径查找算法的基础。

constgrid=newPF.Grid(width,height)
  • width 和 height 是网格的宽和高。
  • 每个网格点初始化为通行 (0)。

举个例子。

// 创建一个 10x10 的网格constgrid=newPF.Grid(10,10)console.log(grid)

在控制台可以看到这个地图其实就是一个二维数组,长和宽都是10个元素。

3、设置路障

通过grid.setWalkableAt()方法可以设置指定节点的状态。

通过grid.isWalkableAt()可以检查指定节点是否可通行。

grid.setWalkableAt(x,y,walkable)grid.isWalkableAt(x,y)
  • setWalkableAt(x, y, walkable):设置某点是否可通行。
  • isWalkableAt(x, y):检查某点是否可通行。

举个例子。

// 设置 (5, 5) 为不可通行grid.setWalkableAt(5,5,false)// 检查 (5, 5) 是否可通行console.log(grid.isWalkableAt(5,5))// false

4、查找路径

PathFinding.js提供了很多种查找路径的算法,我们先试试PF.AStarFinder算法。

查找路径具体用法如下:

constfinder=newPF.AStarFinder(options);constpath=finder.findPath(startX,startY,endX,endY,grid);
  • options:配置寻路算法的选项,如是否允许对角移动。
  • findPath(startX, startY, endX, endY, grid):寻找从起点到终点的路径。
    • startXstartY:起点坐标。
    • endXendY:终点坐标。
    • grid:网格地图。
  • 返回值是路径点数组[ [x1, y1], [x2, y2], ... ]

举个例子。

constfinder=newPF.AStarFinder();constpath=finder.findPath(0,0,9,9,grid.clone());console.log(path);

除了AStarFinderPathFinding.js提供了多种算法:

  • BreadthFirstFinder
  • DijkstraFinder
  • BiAStarFinder
  • BiBreadthFirstFinder
  • BiDijkstraFinder
  • IDAStarFinder
  • JumpPointFinder

用法类似,只需替换AStarFinder即可。

React里使用

// 导入 React 和 useState 钩子importReact,{useState}from'react';// 导入路径寻找库importPFfrom'pathfinding';// 定义路径寻找应用组件constPathFindingApp=()=>{// 初始化状态:网格、路径、起点和终点const[grid,setGrid]=useState(newPF.Grid(10,10));// 创建 10x10 的网格console.log(grid)const[path,setPath]=useState([]);// 存储找到的路径const[start,setStart]=useState([0,0]);// 起点坐标const[end,setEnd]=useState([9,9]);// 终点坐标// 切换网格单元的可行走状态consttoggleWalkable=(x,y)=>{constnewGrid=grid.clone();// 克隆当前网格newGrid.setWalkableAt(x,y,!newGrid.isWalkableAt(x,y));// 切换可行走状态setGrid(newGrid);// 更新网格状态};// 寻找路径的函数constfindPath=()=>{constfinder=newPF.AStarFinder();// 创建 A* 寻路算法实例constnewGrid=grid.clone();// 克隆当前网格constnewPath=finder.findPath(start[0],start[1],end[0],end[1],newGrid);// 寻找路径setPath(newPath);// 更新路径状态};return(<div>{/* <h1>PathFinding.js in React</h1> */}<div style={{display:'grid',gridTemplateColumns:'repeat(10, 30px)'}}>{/* 渲染网格 */}{[...Array(10)].map((_,y)=>[...Array(10)].map((_,x)=>{constisWalkable=grid.isWalkableAt(x,y);// 判断当前单元是否可行走constisPath=path.some(([px,py])=>px===x&&py===y);// 判断当前单元是否在路径上constisStart=x===start[0]&&y===start[1];// 判断当前单元是否为起点constisEnd=x===end[0]&&y===end[1];// 判断当前单元是否为终点return(<div key={`${x}-${y}`}onClick={()=>toggleWalkable(x,y)}// 点击切换可行走状态style={{width:30,height:30,backgroundColor:isStart?'green'// 起点为绿色:isEnd?'red'// 终点为红色:isPath?'yellow'// 路径为黄色:isWalkable?'white'// 可行走单元为白色:'black',// 不可行走单元为黑色border:'1px solid gray',cursor:'pointer',}}/>);}))}</div><button onClick={findPath}>Find Path</button>{/* 寻找路径按钮 */}</div>);};// 导出组件exportdefaultPathFindingApp;

结合代码注释和前面的 API 讲解,应该看得懂我上面写的这份代码。

用了 100 个 div 创建了一个网格地图,绿色点是起点,红色点是终点,黑点是不可走的地方,黄线是最终规划出来的录像。

但在实际项目中,我们不可能用那么多个 div 元素来规划地图,性能是很差的。通常会在canvas里绘制地图。

下面是canvas版本的代码,

importReact,{useState,useRef,useEffect}from'react';importPFfrom'pathfinding';// PathFindingApp 组件constPathFindingApp=()=>{// 使用状态钩子管理网格、路径、起点和终点const[grid,setGrid]=useState(newPF.Grid(10,10));// 创建一个 10x10 的网格const[path,setPath]=useState([]);// 存储找到的路径const[start,setStart]=useState([0,0]);// 起点坐标const[end,setEnd]=useState([9,9]);// 终点坐标constcanvasRef=useRef(null);// 引用画布元素// 切换网格单元的可行走状态consttoggleWalkable=(x,y)=>{constnewGrid=grid.clone();// 克隆当前网格newGrid.setWalkableAt(x,y,!newGrid.isWalkableAt(x,y));// 切换可行走状态setGrid(newGrid);// 更新网格状态};// 寻找路径constfindPath=()=>{constfinder=newPF.AStarFinder();// 创建 A* 寻路算法实例constnewGrid=grid.clone();// 克隆当前网格constnewPath=finder.findPath(start[0],start[1],end[0],end[1],newGrid);// 寻找路径setPath(newPath);// 更新路径状态};// 绘制网格constdrawGrid=()=>{constcanvas=canvasRef.current;// 获取画布引用constcontext=canvas.getContext('2d');// 获取绘图上下文constcellSize=30;// 单元格大小// 清空画布context.clearRect(0,0,canvas.width,canvas.height);// 绘制网格for(lety=0;y<10;y++){for(letx=0;x<10;x++){constisWalkable=grid.isWalkableAt(x,y);// 判断单元格是否可行走constisPath=path.some(([px,py])=>px===x&&py===y);// 判断单元格是否在路径上constisStart=x===start[0]&&y===start[1];// 判断单元格是否为起点constisEnd=x===end[0]&&y===end[1];// 判断单元格是否为终点// 设置单元格颜色context.fillStyle=isStart?'green':isEnd?'red':isPath?'yellow':isWalkable?'white':'black';context.fillRect(x*cellSize,y*cellSize,cellSize,cellSize);// 绘制单元格context.strokeStyle='gray';// 设置边框颜色context.strokeRect(x*cellSize,y*cellSize,cellSize,cellSize);// 绘制单元格边框}}};// 使用 effect 钩子在网格或路径变化时重新绘制网格useEffect(()=>{drawGrid();},[grid,path]);// 处理画布点击事件consthandleCanvasClick=(e)=>{constrect=canvasRef.current.getBoundingClientRect();// 获取画布位置constx=Math.floor((e.clientX-rect.left)/30);// 计算点击的网格 x 坐标consty=Math.floor((e.clientY-rect.top)/30);// 计算点击的网格 y 坐标toggleWalkable(x,y);// 切换网格的可行走状态};// 组件返回的 JSXreturn(<div><canvas ref={canvasRef}width={300}height={300}onClick={handleCanvasClick}/><button onClick={findPath}>Find Path</button>{/* 寻找路径按钮 */}</div>);};exportdefaultPathFindingApp;// 导出组件

PathFinding.js 可实现纯前端网格路径规划,降低服务器压力,还支持多种算法适配不同场景。落地时要考虑性能优化与快速集成问题,不妨看看RollCode 低代码平台的私有化部署、自定义组件、静态页面发布(SSG + SEO)能力。


以上就是本文的全部内容啦,如果本文对你有帮助的话,记得点赞 + 关注 + 收藏

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/24 7:23:11

基于深度学习框架YOLOV8打架暴力行为检测系统 YOLO模型如何训练打架及暴力行为数据集 基于深度学习的暴力行为检测系统 使用 PyQt5 + YOLOv8 + OpenCV

1基于深度学习的暴力行为检测系统 使用 PyQt5 YOLOv8 1 1 以下是您提供的 基于深度学习的暴力行为检测系统 的完整代码实现&#xff0c;该系统使用 PyQt5 YOLOv8 OpenCV 构建&#xff0c;支持&#xff1a; ✅ 图片/视频/摄像头实时检测✅ 暴力行为&#xff08;打架、推搡…

作者头像 李华
网站建设 2026/3/12 18:45:32

AI赋能网络小说创作:脑洞生成的实操指南与技术技巧

在网络小说创作领域&#xff0c;“脑洞”是作品脱颖而出的核心竞争力——无论是反转迭起的剧情、打破常规的世界观设定&#xff0c;还是极具反差感的人物形象&#xff0c;都离不开新颖且可落地的脑洞支撑。随着大语言模型技术的快速迭代&#xff0c;AI已成为创作者突破灵感瓶颈…

作者头像 李华
网站建设 2026/3/18 12:13:33

SFT对大语言模型的作用

1. SFT的作用 如果没有 SFT&#xff08;监督微调&#xff09;&#xff0c;你面对的不是一个“助手”&#xff0c;而是一个“复读机”或者“复印机”。 举个例子&#xff0c;假如你给一个仅经过预训练&#xff08;Base Model&#xff09;的模型发指令&#xff1a; 你的输入&…

作者头像 李华
网站建设 2026/3/22 22:04:53

iOS签名证书,免费与付费的本质差异

当您踏入iOS开发世界&#xff0c;选择签名证书是第一个分水岭。看似相似&#xff0c;但免费与付费证书的差异&#xff0c;直接决定了您应用的测试效率、分发规模与商业潜力。理解其核心区别&#xff0c;是做出明智决策的第一步。核心差异&#xff1a;分发范围与设备限制苹果提供…

作者头像 李华
网站建设 2026/3/23 6:49:54

提示词工程进阶:Chain-of-Thought(CoT)在复杂任务中的应用

在使用 DeepSeek 处理复杂逻辑问题时&#xff0c;你是否发现&#xff1a;如果直接问 答案是多少&#xff1f;&#xff0c;它往往会一本正经地胡说八道&#xff1b;但如果你多加一句 请一步步思考&#xff0c;它就像突然打通了任督二脉&#xff0c;给出了完美的推导过程。 这就是…

作者头像 李华