A*寻路算法

思路


1.起始节点存入open列表
2. 循环(如果open列表不为空并且目标节点不在其中)
open列表中找出离目标最近的节点做为当前节点
把当前节点放入close列表,
把当前节点从open列表删除,
找出当前节点周围离目标最近的节点,设为当前节点继续循环
(查看周围节点时,如果在close列表中就不用再查了,如果父级节点为空就设为当前节点,返回值可根据父级节点逐级获得路径)
结束循环
3. 循环结束后有两种情况,
open列表为空,此时能到达的节点都查看了,但没有目标,所以是无法到达
目标节点在open列表中,此时己查到目标节点,返回目标节点

4.目标节点逐级查找父级节点使用路径

算法类

  public class Path
  {
      public Path(int h, int w)
      {
          H = h;
          W = w;
          allPosi = new Node[w, h];
          for (int i = 0; i < w; i++)
          {
              for (int j = 0; j < h; j++)
              {
                  allPosi[i, j]= new Node(i, j);
              }
          }
      }
      public Node[,] allPosi;
      /// <summary>
      /// 最大高度
      /// </summary>
      public int H { get; set; }
      /// <summary>
      /// 最大宽度
      /// </summary>
      public int W { get; set; }
      /// <summary>
      /// 获取路径
      /// </summary>
      /// <param name="startx"></param>
      /// <param name="starty"></param>
      /// <param name="endx"></param>
      /// <param name="endy"></param>
      /// <returns></returns>
      public Node GetPaths(int startx,int starty,int endx,int endy)
      {
         if(startx>=0 && starty>=0 &&startx<W && starty < H
              &&endx>=0&&endx<W&&endy>=0&&endy<H)
          {
             return GetPaths(allPosi[startx, starty], allPosi[endx, endy]);
          }
          return null;
      }
      /// <summary>
      /// 获取路径
      /// 
      /// </summary>
      /// <param name="start">开始位置</param>
      /// <param name="end">结束位置</param>
      /// <returns>链式结构   end.before->before.before->.....->start</returns>
      public Node GetPaths(Node start, Node end)
      {
          //如果当前节点或目标节点不可到达,返回空  
          if (!start.CanMove || !end.CanMove)
          {
              return null;
          }
           //清空之前寻路记录
		 foreach (var item in allPosi)
		 {
		     item.before = null;
		 }
          Node current= null;
          var openList = new List<Node>() { start};
        var  closeList= new List<Node>();
          //如果有可查看节点或目标节点未获得
          while(openList.Count>0&& !openList.Contains(end))
          {
              //当前节点是可查看节点中离目标最近的
              current = openList.MinBy(n => Math.Abs(end.X - n.X) + Math.Abs(end.Y - n.Y));
              //查看过的节点存起来不用再查
              closeList.Add(current);
              openList.Remove(current);
              //获取当前节点周围,离目标最近的,可用节点
              var _node = GetNearPosi(current, end,openList, closeList);
              //最近的节点设为当前节点,循环查看
                  current=_node;
          }
          return current;
      }
      /// <summary>
      /// 当前格子周围最近的位置
      /// </summary>
      /// <param name="start"></param>
      /// <param name="end"></param>
      /// <returns></returns>
      Node GetNearPosi(Node start, Node end,List<Node> openList,List<Node> closeList)
      {
          //设置周围可查看范围,不要超出界限
          int minx = start.X - 1;
          int maxx= start.X + 1;
          int miny= start.Y - 1;
          int maxy=start.Y + 1;
          if(minx<0)minx= 0;
          if (maxx >= W) maxx = W - 1;
          if(miny<0)miny= 0;
          if(maxy >= H) maxy = H - 1;
          //临时变量初始化
          Node current = null;
          int currentDis = 0;
          for (int x = minx; x <= maxx; x++)
          {
              for (int y = miny; y <=maxy; y++)
              {
                 //获取临时节点,如果不可到达或己查看过,进入下一个循环
                  var posi = allPosi[x, y];
                  if (!posi.CanMove||closeList.Contains(posi))
                  {
                      continue;
                  }
                  //存入可查看列表
                  openList.Add(posi);
                  //如果临时节点的上一个节点为空,设置成当前节点,方便查找路径
                  if (posi.before == null) posi.before = start;
                  //如果查到了目录节点,反回
                  if (current == end)
                      return end;
                  //临时节点与目标节点的距离,找出距离最近的临时节点
                  var dis=Math.Abs(end.X-x)+Math.Abs(end.Y-y);
                  if (currentDis == 0|| currentDis > dis)
                  {
                      currentDis = dis;
                      current = posi;
                  }
                 
              }
          }
          return current;
      }
     /// <summary>
     /// 设置节点为无法通行
     /// </summary>
     /// <param name="x"></param>
     /// <param name="y"></param>
     /// <param name="can"></param>
      public void SetObs(int x, int y,bool can=false)
      {
          if(x>=0&&x<W&&y>=0&&y<H) 
          allPosi[x, y].CanMove = can;
      }
      /// <summary>
      /// 获取节点
      /// </summary>
      /// <param name="x"></param>
      /// <param name="y"></param>
      /// <returns></returns>
      public Node GetNode(int x,int y)
      {
          if (x >= 0 && x < W && y >= 0 && y < H)
              return allPosi[x, y];
          return null;
      }
  }

节点类

 public class Node
 {
     public Node before = null;
     public int X { get; set; }
     public int Y { get; set; }
     public bool CanMove { get; set; } = true;
     public Node(int x,int y)
     {
         X = x;
         Y = y;
     }
 }

使用

//初始化地块大小
 var _path = new MyPath.Path(H,W);
 //设置障碍物
 _path.SetObs(0, 3);
 _path.SetObs(1, 3);
 _path.SetObs(1, 4);
 //获取节点
 var _start = _path.GetNode(start.X, start.Y);
 var _end = _path.GetNode(obj.X, obj.Y);
 //获取路径  链式结构 end->node->node->....->start
 var node= _path.GetPaths(_start,_end);
 //循环依次得到路径上的所有节点
 while(node!=null)
 {
   node = node.before;
   //移动....
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值