详细讲述了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#实现相关推荐

  1. 【Android】基于A星寻路算法的简单迷宫应用

    简介 基于[漫画算法-小灰的算法之旅]上的A星寻路算法,开发的一个Demo.目前实现后退.重新载入.路径提示.地图刷新等功能.没有做太多的性能优化,算是深化对A星寻路算法的理解. 界面预览: 初始化: ...

  2. A*寻路算法的探寻与改良(三)

    A*寻路算法的探寻与改良(三) by:田宇轩                                        第三分:这部分内容基于树.查找算法等对A*算法的执行效率进行了改良,想了解细 ...

  3. 关于A*寻路算法的认识

    最近要参加学校的APP比赛,我们组做的是一个3D迷宫的小APP,我负责的是迷宫的生成与寻路. 寻路算法选择的是A*寻路算法,具体参考的是下面的这篇博客. 本文主要是谈谈自己对A*算法的理解,具体细节, ...

  4. 光速AStar寻路算法(C++)

    光速AStar寻路算法(C++) 一.最终效果 可以看到,我创建了500个小动物,也有110的FPS.虽然它们并不是每一帧都在计算寻路,但是平均下来不卡顿也不错了.我是i7 6700 + GT 720 ...

  5. Cocos2d-x 寻路算法解析(一): 距离优先

    寻路这块在游戏中一直很重要,花了点时间研究了下这个问题,主要参考的是<Data Structures For Game Programmers>,其他的算法用普通Console演示就行了, ...

  6. Cocos2d-x 寻路算法解析(二): 离目的地的距离优先

    看这个图,我们发现这个寻路算法有点傻,明明终点在右侧却每个方向都找.难道没有其他办法了吗?从现实生活中我们知道东西如果在东边,当然是往东边搜索才是最好的办法. Figure 2 计算机中如何表示离目标 ...

  7. 寻路算法实例解析:贪吃蛇AI的实现

    本文是寻路算法的实际应用篇,以贪吃蛇的实现为例子. 1.首先看下这个在微博上很火的贪吃蛇gif 这次我们尝试用代码来模拟下,说不定上面这个图就是计算机搞的. 2.讲贪吃蛇snake AI之前,我们先看 ...

  8. 游戏中常用的寻路算法的分享(4)处理移动中的障碍物

    一个寻路算法会计算出一条绕过静止障碍物的路径,但如果障碍物会移动呢?当一个单位移动到达某特定点时,原来的障碍物可能不在那点了,或者在那点上出现了新的障碍物.如果路线可以绕过典型的障碍物,那么只要使用单 ...

  9. 游戏中常用的寻路算法(5)预先计算好的路径的所用空间

    有时候,影响计算寻路路径的不是时间,而是计算路径所需的上百个单元格所占的空间.寻路是需要内存来运行寻路算法,还需要额外内存来存储寻到的路径.运行寻路算法(A*,开集或闭集)所需的临时空间经常会比存储这 ...

  10. 游戏中常用的寻路算法(6):地图表示

    在本系列文档大部分内容中,我都假设A*用于某种网格上,其中的"节点"是一个个网格的位置,"边"是从某个网格位置出发的各个方向.然而,A*可用于任意图形,不仅仅是 ...

最新文章

  1. http和dubbo的区别_(转载)Dubbo 接口是什么? 与http 接口有什么区别
  2. 前端如何获取后台通过map封装的值_如何舒服的写api接口?
  3. mysql 执行计划大于_Mysql执行计划(大章)
  4. pythonfind_python实现find -name的功能
  5. 《南溪的python灵隐笔记》——tqdm的学习笔记
  6. 知名互联网公司系统架构图[第3期]
  7. Java配置分离之Spring远程配置
  8. nginx RTMP FFmpeg 视频直播
  9. Synchronized与ReentrantLock的区别
  10. OBS美颜滤镜插件(BF+)——OBS美颜解决办法
  11. TPP-Fe(3+)四苯基卟啉铁cas16456-81-8性质说明
  12. 01_Snaker简介
  13. 更强大、更灵活、更全面丨一文搞懂DolphinDB窗口计算
  14. 4.分支语句和循环语句
  15. IDEA 启动项目报错 Error running 'XXXApplication': No jdk for module 'XXX'
  16. .net 2.0安装包打不开_Android——bilibili缓存视频合并教程[2.0]
  17. 微信跳转手机默认浏览器打开指定HTML链接 微信点击链接直接下载安装包实现方式及源码
  18. html移动端语音波纹,html5 +css3 点击后水波纹扩散效果 兼容移动端
  19. 短线选股操作常用技巧
  20. ACM/ICPC 2018亚洲区预选赛北京赛站网络赛 A Saving Tang Monk II【分层bfs】

热门文章

  1. linux命令之tee,linux tee命令
  2. 二维绕任意点旋转_解析几何|对称,平移和旋转
  3. 云南计算机专业笔试题库,2010云南省全国计算机等级考试二级笔试试卷VB考试题库...
  4. Codeforces Round #565 (Div. 3) B. Merge it!
  5. Python学习—2048小游戏等4个小练习
  6. pyqt5——控件1
  7. redis应用之——获取若干最新注册用户
  8. 从DB-Engines看传统数据库生存状况
  9. Tomcat Insufficient space for shared memory file
  10. css知多少(7)——盒子模型