theme: jzman
视频说明
jvideo
前言
效果一
技术栈
- html
- javascript
- css
- canvas
项目主要功能上传一张地图,或者迷宫地图,通过canvas的一系列操作,并指定一个起点和终点,并找到到达终点最近的路线
迷宫找出口效果
正文
加载图像
首先是加载图像,选择一张图,最好是底色是相同的 或者说底色的色差不是很大,你也可以在网上找一张迷宫的图片
```javascript var imgObj = new Image(); imgObj.src = "../img/floor.jpg";
//待图片加载完后,将其显示在canvas上 imgObj.onload = function () { drawImg(this) } ```
通过new Image
构造一个图像,等价于document.createElement("img")
,这张图在onload调用后会得到图片的尺寸,和具体的图像信息,创建实例为HTMLImageElement
,
这样我们就得到了一个图像,接下来就是将图像通过canvas分析,得到每个像素点的色值
获取色值信息
ImageData ctx.getImageData(sx, sy, sw, sh);
getImageData
接受的参数一共4个,两个为一组,第一组是获取图片信息的起始点,一般都填写0,0
,如果你的图像需要识别切边以后的数据,可以根据实际情况调整,第二组为识别区域的结束图标,通常为图像的宽度和高度。
这就是获取到的图像信息Uint8ClampedArray
,由取值范围在0和255之间的无符号整数组成,其中包含了字节长度,和色值。在图像中每个像素用4个1bytes 值(按照红、绿、蓝和透明值的顺序;这就是“RGBA”格式)来代表。
顺序分别是图像的第一行第一个像素色值到第一行最后一个像素的色值,再从第二行第一个像素色值到最后一个像素的色值,这样Z字形排列,直到最后一行。
行和列的数量我们晓得了,就是图像的宽高,接下来就是遍历Uint8ClampedArray
提供的字节信息,得到每一个像素点的色值
```javascript for (let i = 0; i < (pixelData.length / limit); i++) { const r = pixelData[i * limit + 0] const g = pixelData[i * limit + 1] const b = pixelData[i * limit + 2] const diff = distance([r, g, b]) const flag = diff <= colorDeff // 可通行标志 col++ if (i % accuracy === 0) { flagCol++ } if (i % width === 0) { // 折行 col = 0 row++
flagCol = 0
if (i % accuracy === 0) {
// flagCol++
flagRow++ // 数据数组加一行
}
}
```
在此之前需要先知道几个常量和方法: 1. distance
用来计算两个颜色之间色差的方法, 2. standardColor
底色(视为可行走范围的颜色), 3. colorDeff
色差范围,像素颜色和规定底色色差小于这个值,则视为可行走范围,而超过这范围视作色差太大, 不符合可行走范围的色值;
在循环中,得到像素点的rgb,通过像素点上的色值,通过distance
方法和standardColor
对比色差,如果色差小于规定的色差值colorDeff
,则被视为可行走路线
标记行走范围
``` typescript if (flag) { if (!runFlag[flagCol] && !runFlag[flagCol] !== 0) runFlag[flagCol] = []; if (!runFlag[flagCol][flagRow] && runFlag[flagCol][flagRow] !== 0) runFlag[flagCol][flagRow] = 1 // drawRect(col, row) } else { if (!runFlag[flagCol]) runFlag[flagCol] = []; if (!runFlag[flagCol][flagRow]) runFlag[flagCol][flagRow] = 0
} if (!points[flagCol]) points[flagCol] = []; if (!points[flagCol][flagRow]) { points[flagCol][flagRow] = { x: col, y: row } } ```
当循环完毕,根据色值对比的flag判断当前像素是否为可通行状态(像素色值和底色色值小于等于色差范围);
当flag为true的时候runFlag
数组添加一个为1的标记,如果为false则添加一个为0的标记, 通过计算得到runFlag
二维数组数组,
用drawRect(col, row, 2, 2, 'green')
方法将可行走的位置在canvas上标记出来:
寻路
有了这些点位,在确定起点和终点的时候后,就可以执行寻路算法了,
首先假定起点为1和3 const start = [1, 3]
,终点为某处的随机点位 typescript const randomX = getRandomInt(ex / 2, ex) const randomY = getRandomInt(ey / 2, ey)
确定两个点位以后,执行astar算法 typescript if (runFlag) runPoints = astarCreate(start, end, runFlag) console.log(runPoints);
寻路算法计算出的可行走路线
从这种图上可以看到,终点的随机位置为不可通过的点位,这时候可以设置astar的属性 { closest: true }
即可找到目标点位最近的可通过路线。
astar
关于astar的详细介绍可以翻阅历史文章 # Astar算法基础使用——寻路
历史文章
# threejs渲染高级感可视化涡轮模型
# 写一个高德地图巡航功能的小DEMO
# threejs 打造 world.ipanda.com 同款3D首页
源码git地址
canvas-astar