canvas——路径搜索
在前一篇博客中随机生成迷宫,现在就以随机生成的迷宫为地图,开始寻找路径。
迷宫寻路也可以使用DFS,BFS,但常见的是A*算法,它是启发式搜索算法的一种,效率相比前两者也更高。接下来以A*算法为例,迷宫是一个连通图,因此可以寻找到地图上可通行的任意两点间的路径。
A*算法
A*算法的目的是求出最低通过成本,利用它来寻找最优路径。
A*算法的核心在于它的估值函数:f(n)=g(n)+h(n);
f(n)表示第n点的估值;
g(n)表示起始点到顶点n的代价,这里代表起始点到顶点n距离;
h(n)表示顶点n到终点的代价,这里代表顶点n到终点的距离。
对于h(n)采用曼哈顿距离计算。
|r1-r2| + |y1 - y2|
当然也可以使用其他的评估函数,如欧几里得距离、切比雪夫距离;
实现
每个顶点除了保存自身的坐标位置r、c和通行状态flag外,还需要保存各自的f、g、h值(初始化均为0,通过A*算法计算得出),parent指向经过顶点n的前一顶点,state表示顶点n的状态。
class Point {
constructor(r, c, flag=1) {
this.r = r;
this.c = c;
this.flag = flag; // 0 可以通过 1不能通过
this.state = -1; // 0 在openList 1 在closeList -1 未处理
this.f = 0;
this.g = 0;
this.h = 0;
this.parent = null;
}
}
需要两个数组,openList保存已计算 f 值得顶点,closeList保存最有路径的顶点。
(1)初始状态下,openList包含起点,closeList为空。
(2)从openList中取出第一个顶点curPoint,放入closeList中,将curPoint的state设置为1,表示该顶点在closeList数组中
(3)遍历curPoint上下左右的顶点tp,对tp做处理:
tp没有超出边界,flag==0,且state!=1(不在closeList)的,判断tp是否为终点;
是则将tp的parent指向curPoint,返回true,结束函数执行;
如果不是,计算或更新tp的估值等。
(4)从openList中选择估值最小的顶点,循环步骤3。
/*
* start 起点
* end 终点
* distPoint() 计算两点间曼哈顿距离
* processPoint() 处理四周顶点
*/
findPath(start, end) {
let curPoint = start;
// 上下左右顶点偏移量
let near = [{
r: -1,
c: 0
}, {
r: 1,
c: 0
}, {
r: 0,
c: -1
}, {
r: 0,
c: 1
}];
let finded = false;
start.f = start.h = this.distPoint(start, end);
this.openList.push(start); while(this.openList.length > 0) {
curPoint = this.openList.pop();
curPoint.state = 1;
this.closeList.push(curPoint);
finded = this.processPoint(near, curPoint, end);
if(finded) {
break;
}
}
}
/*
* near 需要遍历的顶点偏移量
* curPoint 当前顶点
* pathArr 包含路和墙的二位数组
* end 终点
* between() 计算数值是否在所给范围内
* addArrSort() 添加顶点到指定数组并排序
* quickSort() 快速排序
* comPonitF() 指定排序方法 — — 比较 f 值
*/
processPoint(near, curPoint, end) {
let len = near.length,
i = 0; while(i < len) {
let tr = curPoint.r + near[i].r,
tc = curPoint.c + near[i].c;
if(this.between(tr, 0, this.r - 1) && this.between(tc, 0, this.c - 1)) {
let tp = this.pathArr[tr][tc];
if(tp.flag === 0 && tp.state !== 1) {
// 判断 tp 是否为终点
if(this.isEqual(tp, end)) {
tp.parent = curPoint;
return true;
}
// tp不在openList(估值未计算)
if(tp.state === -1) {
tp.parent = curPoint;
tp.g = curPoint.g + 1;
tp.h = this.distPoint(tp, end);
tp.f = tp.g + tp.h;
this.addArrSort(this.openList, tp, this.comPonitF);
}else {
let g = curPoint + 1;
if(g < tp.g) {
tp.parent =curPoint;
tp.g = g;
tp.f = tp.g + tp.h;
this.quickSort(this.openList, 0, this.openList.length, this.comPonitF);
}
}
}
}
++i;
}
return false;
}
最终,可以通过终点 parent 往回找到路径。
确定起点、终点
为了探寻任意两点间路径,这里为canvas添加了点击事件,以确定起点和终点,然后描绘出两点间的路线。
/*
* removeEvent() 移除点击事件
*/
addEvent(e) {
if(this.start && this.end) {
this.removeEvent();
return;
}
let c = ~~(e.offsetX / 10), // 取整
r = ~~(e.offsetY / 10);
if(this.pathArr[r][c].flag === 0) {
if(!this.start) {
this.start = this.pathArr[r][c];
this.renderPer(this.start, 'yellow');
}else {
this.end = this.pathArr[r][c];
this.findPath(this.start, this.end);
this.render(this.end);
}
}
}
路径搜索就到这里啦。
canvas——路径搜索的更多相关文章
- html5 canvas常用api总结(三)--图像变换API
canvas的图像变换api,可以帮助我们更加方便的绘画出一些酷炫的效果,也可以用来制作动画.接下来将总结一下canvas的变换方法,文末有一个例子来更加深刻的了解和利用这几个api. 1.画布旋转a ...
- 【探索】利用 canvas 实现数据压缩
前言 HTTP 支持 GZip 压缩,可节省不少传输资源.但遗憾的是,只有下载才有,上传并不支持.如果上传也能压缩,那就完美了.特别适合大量文本提交的场合,比如博客园,就是很好的例子. 虽然标准不支持 ...
- 简单入门canvas - 通过刮奖效果来学习
一 .前言 一直在做PC端的前端开发,从互联网到行业软件.最近发现移动端已经成为前端必备技能了,真是不能停止学习.HTML5新增的一些东西,canvas是用的比较多也比较复杂的一个,简单的入门了一下, ...
- 获取Canvas当前坐标系矩阵
前言 在我的另一篇博文 Canvas坐标系转换 中,我们知道了所有的平移缩放旋转操作都会影响到画布坐标系.那在我们对画布进行了一系列操作之后,怎么再知道当前矩阵数据状态呢. 具体代码 首先请看下面的一 ...
- Canvas坐标系转换
默认坐标系与当前坐标系 canvas中的坐标是从左上角开始的,x轴沿着水平方向(按像素)向右延伸,y轴沿垂直方向向下延伸.左上角坐标为x=0,y=0的点称作原点.在默认坐标系中,每一个点的坐标都是直接 ...
- Canvas绘图之平移translate、旋转rotate、缩放scale
画布操作介绍 画布绘图的环境通过translate(),scale(),rotate(), setTransform()和transform()来改变,它们会对画布的变换矩阵产生影响. 函数 方法 描 ...
- 用html5的canvas和JavaScript创建一个绘图程序
本文将引导你使用canvas和JavaScript创建一个简单的绘图程序. 创建canvas元素 首先准备容器Canvas元素,接下来所有的事情都会在JavaScript里面. <canvas ...
- html5标签canvas函数drawImage使用方法
html5中标签canvas,函数drawImage(): 使用drawImage()方法绘制图像.绘图环境提供了该方法的三个不同版本.参数传递三种形式: drawImage(image,x,y):在 ...
- 使用 JavaScript 和 canvas 做精确的像素碰撞检测
原文地址:Pixel accurate collision detection with Javascript and Canvas 译者:nzbin 我正在开发一个需要再次使用碰撞检测的游戏.我通常 ...
随机推荐
- 分享一本书<<谁都不敢欺负你>>
有些人,不管在工作还是生活上,总是被人欺负. 分享这本书给大家,能给大家带来正能量.你强大了,就没人敢欺负你. 有的时候,感到为什么倒霉的总是我?为什么我的命运是这样?为什么总欺负我? 也许有很多人会 ...
- Eclipse实现图形化界面插件-vs4e
vs4e插件下载地址:http://visualswing4eclipse.googlecode.com/files/vs4e_0.9.12.I20090527-2200.zip 下载完成后,解压,然 ...
- JAVA虚拟机环境变量设置
转自: 网络 下载java环境变量设置所需的jdk并安装,下载地址:http://www.oracle.com/technetwork/cn/java/javase/downloads/jdk7 ...
- systemtap原理及使用
SystemTap的架构 SystemTap用于检查运行的内核的两种方法是 Kprobes和 返回探针.但是理解任何内核的最关键要素是内核的映射,它提供符号信息(比如函数.变量以及它们的地址).有了内 ...
- godot新手中文系列教程1-打包安卓
国内godot qq群 302924317 我也是个新手,可以进群多多交流. 我想要吐槽一下,官方文档有点陈旧,细节缺乏,所以某些时候不要相信官方文档,可以向我们可爱的群友提问,他们一定很乐意回答. ...
- JavaFx自定义Tab-Order
title: JavaFx自定义Tab-Order Tab-order是什么?在界面上当你按tab键触发焦点转移的功能,这就是tab order.但是Javafx有个缺陷就是不方便自己设置tab-or ...
- css浮动布局,浮动原理,清除(闭合)浮动方法
css浮动 1.什么是浮动:在我们布局的时用到的一种技术,能够方便我们进行布局,通过让元素浮动,我们可以使元素在水平上左右移动,再通过margin属性调整位置 2.浮动的原理:使当前元素脱离普通流,相 ...
- Java static 关键字详解
引言 在<Java编程思想>中有这样一段话:static方法就是没有this的方法.在static方法内部不能调用非静态方法,反过来是可以的.而且可以在没有创建任何对象的前提下,仅仅通过类 ...
- PHP中的对象遍历技巧
PHP中的对象遍历 对象的遍历,主要是指遍历对象中的,对外部可见属性.实际上就是用访问限制符public声明的属性,这点大家肯定很熟悉了.并且,在php中,遍历对象居然与遍历数组一样,都可以用使用fo ...
- 谷歌统计使用代码部署和事件API使用
谷歌统计代码部署和API使用 1.注册谷歌账号 要使用GA,必需先成为GOOGLE的注册用户,如果没有请去注册.当然,你有GMAIL邮箱就可以.邮箱就是帐户名. 2.开启Google Analytic ...