AStar寻路算法 (C#)

2023-05-16

一.介绍
A星算法其实并不是最短路径算法,它找到的路径并不是最短的,它的目标首先是能以最快的速度找到通往目的地的路
B星实际上是A星的优化 但是B星的缺点是不能向后查找 所以会有问题
还有一种D星的可以用来找最短路径不做过多介绍
二.原理
A星通过从起始点开始,检查相邻方格的方式,向外扩展,直到找到目标;
将平面网格化通过计算每个格子的预测值来寻找最近的路径
G-当前点与起始点的距离
H-当前点与目标点的距离
F的值是G和F的和 也就是预测值或者叫总费
这里的预测值算法有好几种 例如:可以斜着走,不可以斜着走,还有一种是三角形 NavMesh 就是用这种方法的
F,G和H的评分被写在每个方格里.
A星的缺点是它的空间增长是指数级别的;(格子越多计算的量也就越大)<优化可以使用 二叉堆 >
在这里插入图片描述
原理的话基本上网上都能找到 我就直接上代码了
三.代码
我用得是可以斜着走的 如果是直来直往的改一下计算距离的方法就可以了
三角形的写法有兴趣可以看看NavMesh的底层
准备工作:创建出地图
将障碍物设置层级 为UnWalk

之后就可以开始敲代码了
首先创建出每个格子的节点类

public class Node 
{
    public bool walkable;
 
    public int x;
    public int y;
    public Vector3 pos;
    public int hCost;//当前点到终点的距离
    public int gCost;//起始点到当前点的距离
    public Node parent;

    public Node( int x, int y, bool walkable, Vector3 pos)
    {
        this.walkable = walkable;
        this.x = x;
        this.y = y;
        this.pos = pos;
    }

    public int fCost { get { return gCost + hCost; } }

}

之后创建出网格

public class Grid : MonoBehaviour
{
    public Transform player, target;
    Node playerNode, targetNode;
    public List<Node> path;
    public LayerMask unwalkbaleMesk;
    public Vector2 gridSizze;//当前网格尺寸
    public float nodeRadius;//节点的半径
    float nodeDiameter;//节点直径
    public int nodeNumX;//节点数量
    public int nodeNumY;//节点数量
    public Node[,] grid; //按节点定义的网格
    // Start is called before the first frame update
    void Start()
    {
        nodeDiameter = nodeRadius * 2;
        nodeNumX = Mathf.RoundToInt(gridSizze.x / nodeDiameter);
        nodeNumY = Mathf.RoundToInt(gridSizze.y / nodeDiameter);
        CreateGrid();
    }

    private void CreateGrid()
    {
        grid = new Node[nodeNumX, nodeNumY];
        Vector3 startPos = transform.position - new Vector3(gridSizze.x/2,0, gridSizze.y/2);
        for (int x = 0; x < nodeNumX; x++)
        {
            for (int y = 0; y < nodeNumY; y++)
            {
                Vector3 currentPos = startPos + new Vector3(x * nodeDiameter + nodeRadius,0, y * nodeDiameter + nodeRadius);
                bool walkable = !Physics.CheckSphere(currentPos, nodeRadius, unwalkbaleMesk);//检查小圆球范围内是否有物体并且层是否为mask
               
               // print(walkable);
                grid[x, y] = new Node(x,y,walkable,currentPos);
            }
        }
    }
    /// <summary>
    /// 获取点所在的Node
    /// </summary>
    /// <param name="pos"></param>
    /// <returns></returns>
    public Node GetNodeFromPosition(Vector3 pos)
    {
        float percentX = (pos.x + gridSizze.x / 2) / gridSizze.x;
        float percentY = (pos.z + gridSizze.y / 2) / gridSizze.y;
        percentX = Mathf.Clamp01(percentX);
        percentY = Mathf.Clamp01(percentY);
        int x = Mathf.RoundToInt( percentX * (nodeNumX - 1));
        int y = Mathf.RoundToInt( percentY * (nodeNumY - 1));
        return  grid[x,y];
    }

    /// <summary>
    /// 画格
    /// </summary>
    private void  OnDrawGizmos()
    {
        Gizmos.color = Color.green;
        Gizmos.DrawCube(transform.position, new Vector3(gridSizze.x,1,gridSizze.y));
        if (grid!=null)
        {
            foreach (Node n in grid)
            {
                if (n.walkable)
                {
                    Gizmos.color = Color.grey;
                    if (GetNodeFromPosition(player.position)==n)
                    {
                        Gizmos.color = Color.red;
                    }
                    if (GetNodeFromPosition(target.position)==n)
                    {
                        Gizmos.color = Color.yellow;
                    }
                    if (path!=null&&path.Contains(n))
                    {
                      
                            Gizmos.color = Color.blue;
                       
                    }
                    Gizmos.DrawCube(n.pos,new Vector3(nodeDiameter*0.9f,1,nodeDiameter*0.9f));
                }
            }
        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

最后是AStar的寻路代码

public class PathFinding : MonoBehaviour
{
    Grid myGrid;
    
    Node startNode, targetNode;
    private void Awake()
    {
        myGrid = GetComponent<Grid>();
    }

    void FindPath(Vector3 startPos,Vector3 targetPos)
    {
         startNode = myGrid.GetNodeFromPosition(startPos);
         targetNode = myGrid.GetNodeFromPosition(targetPos);
        List<Node> openSet = new List<Node>();//开放节点   需要被评估的节点
        HashSet<Node> closeSet = new HashSet<Node>();//闭合节点   已经评估的节点
        openSet.Add(startNode);
       
        //如果小于0证明遍历完了  没有找到路径
        while (openSet.Count > 0)
        {
            Node currentNode = openSet[0];
            for (int i = 1; i < openSet.Count; i++)
            {
                if (openSet[i].fCost < currentNode.fCost || (openSet[i].fCost == currentNode.fCost && openSet[i].hCost < currentNode.hCost))
                {
                    currentNode = openSet[i];
                }
            }
            openSet.Remove(currentNode);//移除当前节点
            closeSet.Add(currentNode);//添加到闭合节点里
            if (currentNode == targetNode)
            {
                Debug.Log("Path was found");
                RetrievePath(currentNode);
                return;
            }

            foreach (Node n in GetNeighbors(currentNode))
            {
                if (!n.walkable||closeSet.Contains(n))
                    continue;
                int newgCost = currentNode.fCost + GetDistance(currentNode, n);
                bool inOpenSet = openSet.Contains(n);
                if (newgCost<n.gCost||!inOpenSet)
                {
                    n.gCost = newgCost;
                    n.hCost = GetDistance(n, targetNode);
                    n.parent = currentNode;
                    if (!inOpenSet)
                    {
                        openSet.Add(n);
                    }
                }    
            }
        }
    }

    private void RetrievePath(Node n)
    {
        List<Node> p = new List<Node>();
        while (n != startNode)
        {
            p.Add(n);
            n = n.parent;
        }
       // p.Reverse();
        myGrid.path = p;
    }

    int GetDistance(Node n1, Node n2)
    {
        int distanceX = (int)Mathf.Abs(n1.x - n2.x);
        int distanceY = (int)Mathf.Abs(n1.y - n2.y);
        if (distanceX> distanceY)
        {
            return 14 * (distanceY) + 10 * (distanceX - distanceY);
        }
        else
        {
            return 14 * (distanceX) + 10 * (distanceY - distanceX);
        }
    }
    /// <summary>
    /// 找邻居节点
    /// </summary>
    /// <param name="n"></param>
    /// <returns></returns>
    private List<Node> GetNeighbors(Node n)
    {
        List<Node> neighbors = new List<Node>();
        int xx = n.x, yy = n.y;
        for (int x = -1; x <=1; x++)
        {
            for (int y = -1; y <=1 ; y++)
            {
                if (x==0&&y==0)
                    continue;
                if (xx+x>=0&&xx+x<myGrid.nodeNumX&&yy+y>=0&&yy+y<myGrid.nodeNumY)
                {
                    neighbors.Add(myGrid.grid[xx + x, yy + y]);
                }
            }
        }

        return neighbors;
    }




    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        FindPath(myGrid.player.position,myGrid.target.position);
    }
}

需要在地图中心创建一个空物体 之后将Grid和PathFinding挂在上边,设置起点中点就ok了

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AStar寻路算法 (C#) 的相关文章

随机推荐

  • 解决Ubuntu没有wifi图标的问题

    在配置过程中输入命令后就没有wifi图标了 xff0c 不能上网了 xff08 可能是删除了网卡驱动 xff09 后续使用命令查询网卡 hardware of Internet 状态 lshw C network 查看网卡状态发现 无线网被
  • 2022-11-15日Linux安装csitools问题及解决办法

    问题一 xff1a 执行完这三步后电脑没有wifi图标了 xff0c 不能联网了 sudo modprobe r iwldvm iwlwifi mac80211 sudo modprobe r iwlwifi mac80211 cfg802
  • win10扩展c盘容量(2022-11-17)亲测可用

    个人经验 xff1a 想要通过右键我的电脑 管理 磁盘管理 xff0c 将紧挨着C盘的E盘压缩一100G扩展给C盘 这种做法试了不行 xff0c 即使让可用空间挨着C盘 xff0c C盘的扩展卷选项也是灰色的 解决 xff1a 下载傲梅分区
  • S-V信道模型理解

    Saleh和Valenzuela提出的S V信道模型是基于大量室内信道测试构建的 xff0c 更加符合室内真实路径的传播规律 xff0c 可以用来进行信道建模与仿真 下图显示了具有多簇射线的S V信道模型 xff0c 该模型中多径以簇形式达
  • wifi收发数据包分析

    根据802 11n协议WIFI每次发送64字节数据 Intel5300网卡接收的数据包大小为213字节或者393字节或者573字节 说明接受的数据包包含多个发送的包 猜想每个数据包是由多个主体重复加上固定的标志位组成 x 61 1 2 3
  • 清华大学 | 摄像头-激光雷达的时空在线集成标定方法

    点击下方卡片 xff0c 关注 自动驾驶之心 公众号 ADAS巨卷干货 xff0c 即可获取 后台回复 多模态综述 获取论文 xff01 后台回复 ECCV2022 获取ECCV2022所有自动驾驶方向论文 xff01 后台回复 领域综述
  • 操作系统-硬件结构(小林coding笔记)

    控制和管理整个计算机系统的硬件和软件资源 xff1b 提供给用户和其他软件方便的接口和环境 xff1b 主要包括进程管理 内存管理 文件系统 设备管理和网络系统 图灵机的工作方式 基本思想就是用机器模拟人类用纸笔进行数学运算的过程 主要包含
  • 操作系统-三、操作系统结构(小林coding笔记)

    3 1Linux内核和Windows内核 Windows和Linux是常见的两款操作系统 xff0c 操作系统最核心的东西就是内核 内核 内核作为应用连接硬件设备的桥梁 内核的四个基本功能 xff1a 进程调度 内存管理 硬件通信 系统调用
  • 操作系统-四、内存管理(小林coding笔记)

    虚拟内存 防止内存运行多个程序时崩溃 把进程所使用的地址隔离开 xff0c 让操作系统为每个进程分配一套独立的虚拟地址 操作系统会提供一种机制 xff0c 将不同进程的虚拟地址和不同内存的物理地址映射起来 内存分段 程序时由若干逻辑分段组成
  • libcurl库

    目录 1 libcurl简介2 libcurl的使用3 libcurl的安装Libcurl库等第三方库的通用编译方法 3 调用libcurl访问百度主页4 libcurl 相关API解读1 curl global init 2 curl g
  • ERROR: cannot launch node of type: rplidar_ros

    1首先使用rospack find 命令查找该功能包 xff0c 如果输出功能包路径则该功能包存在 xff0c 如果提示没有则说明我们需要下载一个rplidar ros rospack find rplidar ros 2使用sudo ap
  • 【jetson nano】jetson nano环境配置+yolov5部署+tensorRT加速模型

    目录 jetson nano环境配置 43 yolov5部署 43 tensorRT加速模型致谢主机和jetson nano环境jetson系统开机烧录 系统设置 换源python环境配置conda环境yolov5环境matplotlib和
  • MDK仿真出现NOT IN SCOPE(不在范围内)

    这两天刚拿到一套GD32F1系列的开发板 xff0c 想着测试一下 xff0c 看和STM32的有啥不同 xff0c 自己仿真时候 xff0c 想要在窗口观察一下数值 xff0c 结果总是提示NOT IN SCOPE没办法 xff0c 就查
  • Keil调试局部变量显示“not in scope“的问题解决

    Keil调试局部变量显示 34 not in scope 34 的问题解决 参考文章 xff1a xff08 1 xff09 Keil调试局部变量显示 34 not in scope 34 的问题解决 xff08 2 xff09 https
  • MPU6050可以读取ID值,温度值和原始数据值为零问题解决

    MPU6050可以读取ID值 xff0c 温度值和原始数据值为零问题解决 参考文章 xff1a xff08 1 xff09 MPU6050可以读取ID值 xff0c 温度值和原始数据值为零问题解决 xff08 2 xff09 https w
  • 英伟达Jetson Xavier NX部署YOLO5

    1 查看JetPack版本 新到手的NX首先需要确定一下JetPack的版本 xff1a sudo apt span class token operator span cache show nvidia span class token
  • 史上最全 | BEV感知算法综述(基于图像/Lidar/多模态数据的3D检测与分割任务)...

    点击下方卡片 xff0c 关注 自动驾驶之心 公众号 ADAS巨卷干货 xff0c 即可获取 点击进入 自动驾驶之心技术交流群 后台回复 BEV综述 获取论文 xff01 后台回复 ECCV2022 获取ECCV2022所有自动驾驶方向论文
  • matlab-字符串的处理操作

    建立一个字符串向量 xff0c 然后对该向量做如下处理 xff1a 取第1 5个字符组成的子字符串 将字符串倒过来重新排列 将字符串中的小写字母变成相应的大写字母 xff0c 其余字符不变 统计字符串中小写字母的个数 代码 ch 61 39
  • curl发送带有Authorization的POST请求

    一 参数说明 格式 xff1a curl H 请求头 d 请求体 X POST 接口地址 参数内容格式 H header 请求头 Content Type application json d请求内容 remote host 10 163
  • AStar寻路算法 (C#)

    一 介绍 A星算法其实并不是最短路径算法 xff0c 它找到的路径并不是最短的 xff0c 它的目标首先是能以最快的速度找到通往目的地的路 B星实际上是A星的优化 但是B星的缺点是不能向后查找 所以会有问题 还有一种D星的可以用来找最短路径