『7x24小时有问必答』
第一步:新建3d项目
1.webp
第二步:
Hierarchy->点击+号->Creat Empty
2.webp
第三步:新建C类文件,命名为AStarPathFinding,拖动到物体上。
第四步:添加障碍物,运行
3.webp

AStarPathFinding.cs代码如下
using System.Collections;using System.Collections.Generic;using System.Linq;

using UnityEngine;

public  class  Node{       public  int  x;       public  int  y;

       public  float  walkedDistance;//走过的距离       public  float  functionDistance;//函数距离

       public  Node parent;//父节点,用于最后绘制路径。

}public  class  AStarPathFinding  : MonoBehaviour{      [Header("length表示有多少列,width表示有多少行")]       public  int  length  =  20;       public  int  width  =  20;

      [Header("设定起始位置和结束位置")]       public  Vector2Int  startPos  =  new  Vector2Int(0,  0);       public  Vector2Int  endPos  =  new  Vector2Int(5,  5);

      [Header("设置障碍物位置")]  public  List<vector2int> obstacles =  new  List<vector2int>();

      [Header("可否斜向移动?是的话使用欧几里得距离,否则使用曼哈顿距离")]       public  bool canMoveDiagonally;

      [Header("不使用走过的距离(贪心)")]  public  bool dontUseWalkedDistance;

       public  float  animInterval  =  0.5f;

       private  Node[,] nodes;       private  GameObject[,] cubes;

       private  List<vector2int> openList =  new  List<vector2int>();//开放列表       public  HashSet<vector2int> closedList =  new  HashSet<vector2int>();//关闭列表

       private  Vector2Int currentPos;

       private  GameObject mark;       void  Start()      {             //初始化数据结构            nodes =  new  Node[length, width];            cubes =  new  GameObject[length, width];

             //障碍物添加到关闭列表            foreach (var  obstacle in obstacles)            {                  closedList.Add(obstacle);            }

             //可视化地图             for  (int  i  =  0; i < nodes.GetLength(0); i++)            {                   for  (int  j  =  0; j < nodes.GetLength(1); j++)                  {

                        nodes[i, j] =  new  Node();                        nodes[i, j].x = i;                        nodes[i, j].y = j;

                         //创建方块                         GameObject  cubeGo  =  GameObject.CreatePrimitive(PrimitiveType.Cube);                        cubeGo.transform.position =  new  Vector3(i +  0.5f,  0, j +  0.5f);//设定位置                        cubes[i, j] = cubeGo;

                         if  (obstacles.Contains(new  Vector2Int(i, j)))                        {                               var  renderer  =  cubeGo.GetComponent<renderer>();                              renderer.material.color = Color.red;                        }

                  }            }

            cubes[endPos.x, endPos.y].GetComponent<renderer>().material.color = Color.yellow;//终点设置为黄色

             //初始位置也需要计算,避免已经在目标位置时还进行寻路.如果不添加的话一开始就在终点的情况下会先向外走一格再走回终点            openList.Add(startPos);             //同时需要计算预测距离,不然默认为0,之后会一直找到初始起点而无法前进            UpdateFunctionDistance(nodes[startPos.x, startPos.y]);            nodes[startPos.x, startPos.y].walkedDistance =  0;

            currentPos = startPos;             //开始寻路            StartCoroutine(SearchNeighbour());      }

       //搜寻附近可走位置      IEnumerator  SearchNeighbour()      {             //寻找周围可走格子并放入开放列表             for  (int  i  =  -1; i <  2; i++)            {                   for  (int  j  =  -1; j <  2; j++)                  {                         var  distance  =  Vector2.SqrMagnitude(new  Vector2(i, j));                         if  (!canMoveDiagonally)                        {                               //如果不能斜向走就忽略掉斜向的格子,判断斜向的格子是通过平方向量长度是否大于1来判断的                               if  (distance >  1)                              {                                     continue;                              }                        }                         if  (i ==  0  && j ==  0)//自己不能重复加入开放列表                               continue;

                         if  (currentPos.x + i <  0  || currentPos.x + i > length -  1  || currentPos.y + j <  0  ||                              currentPos.y + j > width -  1)//越界判断                        {                               continue;                        }

                         var  v2I  =  currentPos +  new  Vector2Int(i, j);                         if  (closedList.Contains(v2I) || openList.Contains(v2I))//不能再次加入关闭列表和开放列表中的节点                        {                               continue;                        }                         //更新父节点和走过的距离                        nodes[v2I.x, v2I.y].walkedDistance = nodes[currentPos.x, currentPos.y].walkedDistance + distance;                        nodes[v2I.x, v2I.y].parent = nodes[currentPos.x, currentPos.y];//更新父节点

                        openList.Add(v2I);                  }            }

             var  openNodeList  =  new  List<node>();//获取开放位置列表对应的开放node列表以根据升序排序找出最优节点

            foreach (var  pos in openList)            {                   var  toAdd  =  nodes[pos.x, pos.y];                  openNodeList.Add(toAdd);

                   //更新预估距离                  UpdateFunctionDistance(toAdd);

            }

             //OpenList为空,代表所有开放节点走完了             if  (openNodeList.Count ==  0)            {                  Debug.Log("全图已经遍历完成,无法到达目标位置");                   yield  break;            }

             //排序             var  currentNode  =  openNodeList.OrderBy(x => dontUseWalkedDistance ? x.functionDistance : x.functionDistance + x.walkedDistance).First();            currentPos =  new  Vector2Int(currentNode.x, currentNode.y);

            openList.Remove(new  Vector2Int(currentNode.x, currentNode.y));//从开放列表中移除            closedList.Add(new  Vector2Int(currentNode.x, currentNode.y));//移动到关闭列表中

            cubes[currentNode.x, currentNode.y].GetComponent<renderer>().material.color = Color.black;//当前节点染色

             //当前位置标记            Destroy(mark);            mark = GameObject.CreatePrimitive(PrimitiveType.Cube);            mark.transform.localScale = Vector3.one *  0.5f;            mark.GetComponent<renderer>().material.color = Color.blue;            mark.transform.position =  new  Vector3(currentPos.x +  0.5f,  1, currentPos.y +  0.5f);

             if  (currentPos == endPos)            {                  Debug.Log("找到路径");                  DrawPath();            }             else            {                   yield  return  new  WaitForSeconds(animInterval);                  StartCoroutine(SearchNeighbour());            }

      }

       public  void  UpdateFunctionDistance(Node node)      {

             var  pos  =  new  Vector2(node.x, node.y);             //计算距离             if  (canMoveDiagonally)//斜向使用欧几里得距离,            {                  node.functionDistance = Vector2.Distance(endPos, pos);            }             else            {     //曼哈顿距离                  node.functionDistance = Mathf.Abs(endPos.x - pos.x) + Mathf.Abs(endPos.y - pos.y);            }      }

       void  DrawPath()      {             var  currentNode  =  nodes[currentPos.x, currentPos.y];  // 通过 parent 进行回溯

             // 查找或创建 LineRenderer 组件             LineRenderer  lineRenderer  =  GetComponent<linerenderer>();             if  (lineRenderer ==  null)            {                  lineRenderer = gameObject.AddComponent<linerenderer>();  // 如果没有 LineRenderer,则创建一个            }

             // 设置 LineRenderer 属性            lineRenderer.startWidth =  0.1f;  // 设置起始宽度            lineRenderer.endWidth =  0.1f;     // 设置结束宽度            lineRenderer.material =  new  Material(Shader.Find("Sprites/Default"));  // 设置材质(可以自定义)            lineRenderer.startColor = Color.cyan;  // 设置起始颜色            lineRenderer.endColor = Color.cyan;     // 设置结束颜色            lineRenderer.positionCount =  0;            // 清除之前的路径点

             // 回溯路径并将路径点添加到 LineRenderer            List<vector3> pathPoints =  new  List<vector3>();

             while  (currentNode.parent !=  null)            {                  pathPoints.Add(new  Vector3(currentNode.x +  0.5f,  0.5f, currentNode.y +  0.5f));  // 添加路径点                  currentNode = currentNode.parent;  // 回溯到父节点            }

            pathPoints.Add(new  Vector3(currentNode.x +  0.5f,  0.5f, currentNode.y +  0.5f));  // 添加起点

             // 设置 LineRenderer 的路径点            lineRenderer.positionCount = pathPoints.Count;             for  (int  i  =  0; i < pathPoints.Count; i++)            {                  lineRenderer.SetPosition(i, pathPoints);  // 将每个路径点设置到 LineRenderer            }      }

}

</vector3></vector3></linerenderer></linerenderer></renderer></renderer></node></renderer></renderer></vector2int></vector2int></vector2int></vector2int></vector2int></vector2int>

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

上一主题上一主题         下一主题下一主题
QQ手机版小黑屋粤ICP备17165530号

关于我们·投诉举报· 用户帮助· 联系我们 · 本站服务 · 版权声明· 隐私政策 · 投搞指南

法律保护:PLC技术网,plcjs.com,plcjs.net等字样
Copyright 2010-2030. All rights reserved. 


微信公众号二维码 抖音二维码 百家号二维码 今日头条二维码哔哩哔哩二维码