A*寻路算法的C#实现
详细讲述了A*寻路算法,有下列地方值得学习
1. 不要用AStarPathNode来构造PathFinder的Matrix,Matrix仅仅是byte[,],需要对Matrix中某个元素进行处理时再构造相应的AStarPathNode
2. 对每个Matrix中的元素取值不仅仅0和1,而是代表其权重,0表示障碍物,1表示平地,n表示高山,沼泽难以行走的地方,Weight越大越难以通过。节点G值会根据Weight进行计算。
newG = parentNode.G + mGrid[newNode.X, newNode.Y];
3. 使用Closed List,用于判断是否达到寻路次数的上限。如果Closed List中的节点数达到某个数值(Search Limit),就停止寻路。
4. 设置A* 算法的参数,
Search Limit :如果Closed List中的节点数达到某个数值(Search Limit),就停止寻路。
Heuristic Formula:使用不同的算法来计算节点的H值,确省为Manhattan算法。
Diagonals:是否处理对角线上的相邻节点
如果Diagonals = false,就意味着找到的路径都是直线
HeavyDiagonals:是否认为走对角线比走直线更远,表现在算法上就是:
if(HeavyDiagonals)
newNodeGValue = parentNode.G + Matrix[newNode.X, newNodeY]*2.41; //???为什么不是根号2~~1.41
else
newNodeGValue = parentNode.G + Matrix[newNode.X, newNodeY]
Punish Change Direction:是否希望找到的路径看起来比较平滑,如果新节点和其父节点的走向与
父节点和父节点的父节点之间的走向不符,则增加新节点的G值。这里要注意newG += 20。//为什么是20???
算法为:
if (PunishChangeDirection)
mHoriz = (parentNode.X - parentNode.PX); //???似乎还应该加上mVert = (parentNode.Y - parentNode.PY)
newNodeGValue = //计算GValue
if (PunishChangeDirection)
{
if ((newNode.X - parentNode.X) != 0)
{
if (mHoriz == 0)
newG += 20;
}
if ((newNode.Y - parentNode.Y) != 0)
{
if (mHoriz != 0) //???在这里使用mVert
newG += 20;
}
}
Tie Breaker: 避免出现殊途同归,轻微的改变H值
if (mTieBreaker)
{
int dx1 = parentNode.X - end.X;
int dy1 = parentNode.Y - end.Y;
int dx2 = start.X - end.X;
int dy2 = start.Y - end.Y;
int cross = Math.Abs(dx1 * dy2 - dx2 * dy1);
newNode.H = (int) (newNode.H + cross * 0.001);
}
不同的组合在不同的环境下具有最好的性能
5. 对相邻节点的处理很巧妙
用 direction = new sbyte[8,2]{ {0,-1} , {1,0}, {0,1}, {-1,0}, {1,-1}, {1,1}, {-1,1}, {-1,-1}}; 分别表示上,右,下,左,右上,右下,左下,左上这八个相邻Node的坐标x,y值的偏移。
比如:current node坐标为x,y,这八个节点的坐标可以这样获得
for(int i=0; i< 8 ; i ++)
{
newNodeX = x + direction[i,0];
newNodeX = x + direction[i,1];
}
6. 不使用普通的array list保存open node,否则,找出F值最小的open node会花去大量的时间,而是引入了Priority Queue作为open node的容器。把排序的复杂度分解在Push和Pop中,保证每次Pop出的都是最小的元素
7. 与Path Find无关。工作线程与UI的交互
public delegate void PathFinderDebugHandler(int fromX, int fromY, int x, int y, PathFinderNodeType type, int totalCost, int cost);
public class PathFinder : IPathFinder
{
public event PathFinderDebugHandler PathFinderDebug;
}
//-------- Form
mPathFinder.PathFinderDebug += new PathFinderDebugHandler(PathFinderDebug); //handle Event
//用delegate来进行跨线程调用
private delegate void PathFinderDebugDelegate(int parentX, int parentY, int x, int y, PathFinderNodeType type, int totalCost, int cost);
private void PathFinderDebug(int parentX, int parentY, int x, int y, PathFinderNodeType type, int totalCost, int cost)
{
if (InvokeRequired)
{
Invoke(new PathFinderDebugDelegate(PathFinderDebug), new object[]{parentX, parentY, x, y, type, totalCost, cost});
return;
}
PnlGUI.DrawDebug(parentX, parentY, x, y, type, totalCost, cost);
}
对本文我进行了下列修改:
1.在遍历当前节点的相邻节点时,需要看这个相邻节点是否已经在open list 或close list中,如果某个相邻节点已经在OpenList中,就要看如果把这个相邻节点的父节点修改为当前节点,是否会降低这个相邻节点的G值,原文中使用了for 循环来检查这个节点是否在list中
int foundInOpenIndex = -1;
for(int j=0; j<mOpen.Count; j++)
{
if (mOpen[j].X == newNode.X && mOpen[j].Y == newNode.Y)
{
foundInOpenIndex = j;
break;
}
}
if (foundInOpenIndex != -1 && mOpen[foundInOpenIndex].G <= newG)
continue;
int foundInCloseIndex = -1;
for(int j=0; j<mClose.Count; j++)
{
if (mClose[j].X == newNode.X && mClose[j].Y == newNode.Y)
{
foundInCloseIndex = j;
break;
}
}
if (foundInCloseIndex != -1 && mClose[foundInCloseIndex].G <= newG)
continue;
为了提高性能,我给保存open node的Queue中加入
private Dictionary<Point, int> pointDictionary = new Dictionary<Point, int>();
并使用Dictionary<Point, AStarNode> closedNodes 保存close node,
以便使用x,y坐标可以在open list或closed list中找到相应的Node
2.为了避免出现这种”穿墙”的情况,我加入了一个条件”CrossDiagonalBar”,
效果如下
还有一个问题有待解决:
如果目标节点本身为障碍物,或是目标节点被障碍物完全包围,如何给出一条路径,使其尽量逼近目标节点?
源码下载请至置顶页~~
A*寻路算法的C#实现相关推荐
- 【Android】基于A星寻路算法的简单迷宫应用
简介 基于[漫画算法-小灰的算法之旅]上的A星寻路算法,开发的一个Demo.目前实现后退.重新载入.路径提示.地图刷新等功能.没有做太多的性能优化,算是深化对A星寻路算法的理解. 界面预览: 初始化: ...
- A*寻路算法的探寻与改良(三)
A*寻路算法的探寻与改良(三) by:田宇轩 第三分:这部分内容基于树.查找算法等对A*算法的执行效率进行了改良,想了解细 ...
- 关于A*寻路算法的认识
最近要参加学校的APP比赛,我们组做的是一个3D迷宫的小APP,我负责的是迷宫的生成与寻路. 寻路算法选择的是A*寻路算法,具体参考的是下面的这篇博客. 本文主要是谈谈自己对A*算法的理解,具体细节, ...
- 光速AStar寻路算法(C++)
光速AStar寻路算法(C++) 一.最终效果 可以看到,我创建了500个小动物,也有110的FPS.虽然它们并不是每一帧都在计算寻路,但是平均下来不卡顿也不错了.我是i7 6700 + GT 720 ...
- Cocos2d-x 寻路算法解析(一): 距离优先
寻路这块在游戏中一直很重要,花了点时间研究了下这个问题,主要参考的是<Data Structures For Game Programmers>,其他的算法用普通Console演示就行了, ...
- Cocos2d-x 寻路算法解析(二): 离目的地的距离优先
看这个图,我们发现这个寻路算法有点傻,明明终点在右侧却每个方向都找.难道没有其他办法了吗?从现实生活中我们知道东西如果在东边,当然是往东边搜索才是最好的办法. Figure 2 计算机中如何表示离目标 ...
- 寻路算法实例解析:贪吃蛇AI的实现
本文是寻路算法的实际应用篇,以贪吃蛇的实现为例子. 1.首先看下这个在微博上很火的贪吃蛇gif 这次我们尝试用代码来模拟下,说不定上面这个图就是计算机搞的. 2.讲贪吃蛇snake AI之前,我们先看 ...
- 游戏中常用的寻路算法的分享(4)处理移动中的障碍物
一个寻路算法会计算出一条绕过静止障碍物的路径,但如果障碍物会移动呢?当一个单位移动到达某特定点时,原来的障碍物可能不在那点了,或者在那点上出现了新的障碍物.如果路线可以绕过典型的障碍物,那么只要使用单 ...
- 游戏中常用的寻路算法(5)预先计算好的路径的所用空间
有时候,影响计算寻路路径的不是时间,而是计算路径所需的上百个单元格所占的空间.寻路是需要内存来运行寻路算法,还需要额外内存来存储寻到的路径.运行寻路算法(A*,开集或闭集)所需的临时空间经常会比存储这 ...
- 游戏中常用的寻路算法(6):地图表示
在本系列文档大部分内容中,我都假设A*用于某种网格上,其中的"节点"是一个个网格的位置,"边"是从某个网格位置出发的各个方向.然而,A*可用于任意图形,不仅仅是 ...
最新文章
- http和dubbo的区别_(转载)Dubbo 接口是什么? 与http 接口有什么区别
- 前端如何获取后台通过map封装的值_如何舒服的写api接口?
- mysql 执行计划大于_Mysql执行计划(大章)
- pythonfind_python实现find -name的功能
- 《南溪的python灵隐笔记》——tqdm的学习笔记
- 知名互联网公司系统架构图[第3期]
- Java配置分离之Spring远程配置
- nginx RTMP FFmpeg 视频直播
- Synchronized与ReentrantLock的区别
- OBS美颜滤镜插件(BF+)——OBS美颜解决办法
- TPP-Fe(3+)四苯基卟啉铁cas16456-81-8性质说明
- 01_Snaker简介
- 更强大、更灵活、更全面丨一文搞懂DolphinDB窗口计算
- 4.分支语句和循环语句
- IDEA 启动项目报错 Error running 'XXXApplication': No jdk for module 'XXX'
- .net 2.0安装包打不开_Android——bilibili缓存视频合并教程[2.0]
- 微信跳转手机默认浏览器打开指定HTML链接 微信点击链接直接下载安装包实现方式及源码
- html移动端语音波纹,html5 +css3 点击后水波纹扩散效果 兼容移动端
- 短线选股操作常用技巧
- ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 A Saving Tang Monk II【分层bfs】
热门文章
- linux命令之tee,linux tee命令
- 二维绕任意点旋转_解析几何|对称,平移和旋转
- 云南计算机专业笔试题库,2010云南省全国计算机等级考试二级笔试试卷VB考试题库...
- Codeforces Round #565 (Div. 3) B. Merge it!
- Python学习—2048小游戏等4个小练习
- pyqt5——控件1
- redis应用之——获取若干最新注册用户
- 从DB-Engines看传统数据库生存状况
- Tomcat Insufficient space for shared memory file
- css知多少(7)——盒子模型