路径规划A*(A-Star)算法

这篇具有很好参考价值的文章主要介绍了路径规划A*(A-Star)算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

路径规划A*算法介绍

A*(A-Star)算法是一种常用的寻路算法,用于图形表达的环境中找到起点到目标点的最短路径。

代价函数𝑓(𝑛)由两部分组成:起点沿着已生成的路径到达当前节点的开销𝑔(𝑛)和当前节点到终点的预估开销ℎ(𝑛)。公式表示: 𝑓(𝑛) = 𝑔(𝑛) + ℎ(𝑛)

A*算法的详细原理之定义
基本定义
G: G表示从起点A移动到网格上指定方格的移动耗费(上下左右,下面实例没写沿斜方向移动)
H: H表示从指定方格移动到终点的预计耗费(H方法多种,这里设定忽略障碍物上下左右移动)
F: F=G+H,表示该点的总耗费
4.open列表:一个记录下所有被考虑来寻找最短路径的格子
5. closed列表: 一个记录下不会再被考虑的格子

曼哈顿距离:通过计算两点在空间中沿着网格线(垂直和水平方向)距离来度量它们之间的距离

A*算法结合了广度优先搜索和启发式搜索的思想。它使用一个启发式函数来估计从当前位置到目标位置的代价,通过不断更新并选择代价最低的路径来进行搜索。

下面是A*算法的详细步骤:

1. 初始化
   - 将起点放入一个待处理节点列表中,并将其代价设为0。
   - 初始化一个节点存储表,用于记录每个节点的父节点、代价等信息。
   - 初始化一个节点集合,用于存储已经访问过的节点。

2. 循环直到找到目标点或者遍历完所有可达节点:
   - 从待处理节点列表中选择代价最低的节点,作为当前节点。
   - 如果当前节点为目标点,算法结束,可以通过节点存储表回溯找到最短路径。
   - 将当前节点从待处理节点列表中移除,放入已访问节点集合中。
   - 对当前节点的相邻节点进行处理:
   - 如果相邻节点已经在已访问节点集合中,跳过该节点。
   - 计算相邻节点的代价,包括从起点到该节点的代价和从该节点到目标点的启发式估计代价。
   - 如果相邻节点不在待处理节点列表中,将其加入,并更新节点存储表。
   - 如果相邻节点已经在待处理节点列表中,并且新的代价更小,则更新节点存储表中的信息。

3. 如果待处理节点列表为空,则表示无法从起点找到目标点,算法结束。

   A*算法的关键在于如何选择合适的启发式函数来估计代价。一个好的启发式函数应该满足以下条件:
   - 它应该是可计算的,并且能够对任意节点对进行估价。
   - 对于目标点,它的估价应该为0。
   - 它应该尽可能准确地估计节点到目标点的实际代价

这里使用曼哈顿距离

A*算法在寻路问题中具有较好的性能和效率,在很多实际应用中得到广泛使用。但需要注意的是,A*算法只能保证找到一条最短路径,而不能保证是全局最优的路径。同时,在大规模图形环境中,A*算法的效率可能会受到影响,可以采用一些优化策略来加快搜索速度。

路径规划A*算法实现实例

Node:定义每个结点的属性

using UnityEngine;
using System;
//寻路算法的一个节点
public class Node : IComparable
{
    public float nodeTotalCost;//总成本
    public float estimatedCost;//估算成本
    //estimatedCost=nodeTotalCost+estimatedCost
    //f            =       g     +      h
    public bool bObstacle;//障碍物
    public Node parent;//父节点
    public Vector3 position;//每个节点的位置
    public Node() { //结点信息
        this.estimatedCost = 0.0f;
        this.nodeTotalCost = 1.0f;
        this.bObstacle = false;
        this.parent = null;
    }
    public Node(Vector3 pos) {//结点位置
        this.estimatedCost = 0.0f;
        this.nodeTotalCost = 1.0f;
        this.bObstacle = false;
        this.parent = null;
        this.position = pos;
    }
    public void MarkAsObstacle() { //设置障碍物
        this.bObstacle= true;
    }
    public int CompareTo(object obj)//比较节点估算成本的大小
    {
        Node node = (Node)obj;
        if (this.estimatedCost < node.estimatedCost){ 
            return -1;
        }
        if (this.estimatedCost>node.estimatedCost){
            return 1;
        }
        return 0;
    }
}

 PriorityQueue:优先级队列

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//优先级队列
public class PriorityQueue 
{
    private ArrayList nodes= new ArrayList();//数组列表
    
    public int Length { //获取结点的数量
        get { return this.nodes.Count; }
    }

    public Node First()//获取优先级队列第一个结点
    {
        if (this.nodes.Count > 0)
        {
            return (Node)this.nodes[0];
        }
         return null;
    }

    public bool Contains(object node) { //检查队列里是否有该结点
        return this.nodes.Contains(node);
    }

    public void Push(Node node) { //存入优先级队列
        this.nodes.Add(node);
        this.nodes.Sort();//从小到大排序
    }

    public void Remove(Node node) {//从优先级队列删除
        this.nodes.Remove(node);
        this.nodes.Sort();
    }
}

 GirdManager:网格管理器,画出参考网格线

网格编号从原点开始,左为X正方向,上位Z轴正方向

a*算法路径规划,算法,数据结构

using System.Collections;
using UnityEngine;
//网格管理器
public class GirdManager : MonoBehaviour
{
    private static GirdManager s_Instance=null;

    public static GirdManager instance {//单例
        get 
        {
            if (s_Instance == null) {
                s_Instance = FindObjectOfType(typeof(GirdManager)) as GirdManager;
                if (s_Instance == null)
                {
                    Debug.Log("你在场景中必须要有一个网格管理器");
                }
            }
            return s_Instance;
        }

    }

    private void OnApplicationQuit()
    {
        s_Instance = null;
    }

    public int numOfRows;//网格行数
    public int numOfColumns;//网格列数
    public float gridCellSize;//每一个网格大小
    public bool showGrid = true;//画出网格

    private GameObject[] obstacleList;//障碍物数组
    private Node[,] nodes;//结点数组
    private Vector3 origin = new Vector3();

    public Vector3 Origin {
        get { return origin;}
    }

    void Awake() {//初始化时必须执行
        origin=this.transform.position;
        obstacleList = GameObject.FindGameObjectsWithTag("Obstacle");//查找障碍物,障碍物标签标识为Obstacle
        CalculateObstacles();
    }
    private void CalculateObstacles()//计算障碍物属于哪个网格
    {
        nodes = new Node[numOfColumns,numOfRows];
        int index = 0;
        for (int i = 0; i<numOfColumns; i++) 
        { 
            for (int j = 0; j<numOfRows; j++) 
            {
                Node node = new Node(GetGridCellCenter(index));
                nodes[i, j] = node;
                index++;
            }
        }
        if (obstacleList != null && obstacleList.Length > 0)
        {
            foreach (GameObject data in obstacleList)
            {
                int indexCell = GetGridIndex(data.transform.position);
                int col = GetColumn(indexCell);
                int row = GetRow(indexCell);
                nodes[row, col].MarkAsObstacle();
            }
        }
    }

    public int GetGridIndex(Vector3 pos) {//获取网格序号
        pos-= Origin;
        int col = (int)(pos.x / gridCellSize);
        int row = (int)(pos.z / gridCellSize);
        return (row * numOfColumns + col);
    }

    public Vector3 GetGridCellCenter(int index)//获取网格中心点
    {
        Vector3 cellPosition = GetGridCellPosition(index);
        cellPosition.x += (gridCellSize / 2.0f);
        cellPosition.z += (gridCellSize / 2.0f);
        return cellPosition;
    }

    public Vector3 GetGridCellPosition(int index) {//获取网格左位置点
        int row = GetRow(index);
        int col = GetColumn(index);
        float xPosInGrid = col * gridCellSize;
        float zPosInGrid = row * gridCellSize;
        return Origin + new Vector3(xPosInGrid, 0.0f,zPosInGrid);
    }

    public int GetColumn(int index) {//获取列数
        int col = index % numOfColumns;
        return col;
    }
    public int GetRow(int index) {//获取行数
        int row= index / numOfColumns;
        return row;
    }




    void OnDrawGizmos()//画出网格
    {
        if (showGrid) {
            DebugDrawGrid(transform.position, numOfRows, numOfColumns, gridCellSize, UnityEngine.Color.blue);
        }
        Gizmos.DrawSphere(transform.position, 0.5f);//在原点画出一个球,方便查看原点方位
    }

    private void DebugDrawGrid(Vector3 origin, int numRows,int numColumns,float cellSize, UnityEngine.Color color)
    {
        float width = numColumns * cellSize;//宽度
        float height = numRows * cellSize;//高度
        for (int i = 0; i < numRows + 1; i++)
        {
            Vector3 startPos = origin + i * cellSize * new Vector3(0.0f,0.0f,1.0f);
            Vector3 endPos = startPos + width * new Vector3(1.0f,0.0f, 0.0f);
            Debug.DrawLine(startPos,endPos, color);
        }
        for (int i = 0; i < numColumns+1; i++)
        {
            Vector3 startPos = origin + i * cellSize*new Vector3(1.0f, 0.0f,0.0f);
            Vector3 endPos = startPos + height * new Vector3(0.0f,0.0f,1.0f);
            Debug.DrawLine(startPos, endPos,color);
        }
    }


    public void GetNeighbors(Node node,ArrayList neighbors)//获取邻居
    {
        Vector3 neighborPos = node.position;
        int neighborIndex = GetGridIndex(neighborPos);

        int row=GetRow(neighborIndex);
        int column=GetColumn(neighborIndex);
        //下
        int leftNodeRow = row - 1;
        int rightNodeColumn = column;
        AssignNeighbor(leftNodeRow, rightNodeColumn, neighbors);
        //上
        leftNodeRow = row + 1;
        rightNodeColumn = column;
        AssignNeighbor(leftNodeRow, rightNodeColumn, neighbors);
        //右
        leftNodeRow = row;
        rightNodeColumn = column+1;
        AssignNeighbor(leftNodeRow, rightNodeColumn, neighbors);
        //左
        leftNodeRow = row ;
        rightNodeColumn = column-1;
        AssignNeighbor(leftNodeRow, rightNodeColumn, neighbors);
    }

    private void AssignNeighbor(int Row, int Column, ArrayList neighbors)//将结点的行列放入动态数组
    {
        if (Row != -1 && Column != -1 && Row < numOfRows && Column < numOfColumns)
        {
            Node nodeToAdd = nodes[Row, Column];
            if (!nodeToAdd.bObstacle) { 
                neighbors.Add(nodeToAdd);
            }
        }
    }
}

 AStar算法

using System.Collections;
using UnityEngine;
//AStar算法
public class AStar
{
    public static PriorityQueue closedList, openList;

    private static float NodeCost(Node a, Node b) {//返回两点之间的距离
        Vector3 vecCost = a.position - b.position;
        return vecCost.magnitude;
    }
    public static ArrayList FindPath(Node start, Node goal)//在起始点到终点间寻路
    {
        openList = new PriorityQueue();
        openList.Push(start);//起点存入openList
        start.nodeTotalCost = 0.0f;
        start.estimatedCost = NodeCost(start, goal);
        closedList = new PriorityQueue();
        Node node = null;
        while (openList.Length != 0)
        {
            node = openList.First();
            if (node.position == goal.position)
            {
                return CalculatePath(node);
            }
            ArrayList neighbours = new ArrayList();
            GirdManager.instance.GetNeighbors(node, neighbours);
            for (int i = 0; i < neighbours.Count; i++) {
                Node neighbourNode = (Node)neighbours[i];
                if (!closedList.Contains(neighbourNode))
                {
                    float cost = NodeCost(node, neighbourNode);
                    float totalCost = node.nodeTotalCost + cost;
                    float neighbourNodeEstCost = NodeCost(neighbourNode, goal);
                    neighbourNode.nodeTotalCost = totalCost;
                    neighbourNode.estimatedCost = totalCost + neighbourNodeEstCost;
                    neighbourNode.parent = node;

                    if (!openList.Contains(neighbourNode))
                    {
                        openList.Push(neighbourNode);
                    }
                }
            }
            closedList.Push(node);
            openList.Remove(node);
        }
        if (node.position != goal.position)
        {
            Debug.LogError(" Goal Not Found");
            return null;
        }
        return CalculatePath(node);
    }

    private static ArrayList CalculatePath(Node node)
    {
        ArrayList list = new ArrayList();
        while (node != null)
        {
            list.Add(node);
            node = node.parent;
        }
        list.Reverse();
        return list;
    }
    
}

 TestCode测试:定义一个起点和终点,到达终点时通过遍历返回父节点动态的画出路径

using System.Collections;
using UnityEngine;
//测试
public class TestCode : MonoBehaviour
{
    private Transform startPos, endPos;//起点和终点
    public Node startNode { get; set; }
    public Node goalNode { get; set; }

    GameObject objStartCube, objEndCube;
    public ArrayList pathArray;

    public float intervalTime = 1.0f;
    private float elapsedTime = 0.0f;

    void Start()
    {
        objStartCube = GameObject.FindGameObjectWithTag("Start");
        objEndCube = GameObject.FindGameObjectWithTag("End");

        FindPath();
    }

    private void FindPath()//查找路径
    {
        startPos = objStartCube.transform;
        endPos = objEndCube.transform;

        startNode = new Node(GirdManager.instance.GetGridCellCenter(GirdManager.instance.GetGridIndex(startPos.position)));
        goalNode = new Node(GirdManager.instance.GetGridCellCenter(GirdManager.instance.GetGridIndex(endPos.position)));

        pathArray = AStar.FindPath(startNode, goalNode);//返回父节点路径
    }

    void Update()
    {
        elapsedTime += Time.deltaTime;
        if (elapsedTime > intervalTime)
        {
            elapsedTime = 0.0f;
            FindPath();//每隔一秒事件更新一次路径
        }
    }

    void OnDrawGizmos()
    {
        if (pathArray == null) 
        {
            return;
        }
        if (pathArray.Count > 0) 
        {
            int index = 1;
            foreach (Node node in pathArray) 
            {
                if (index < pathArray.Count) 
                {
                    Node nextNode = (Node)pathArray[index];
                    Debug.DrawLine(node.position, nextNode.position, Color.green);
                    index++;
                }
            }
        }
    }
}

注意:设置每个cube的tag

路径实现结果展示

路径规划A*算法实例

学习参考:AStar_demo_1_哔哩哔哩_bilibili文章来源地址https://www.toymoban.com/news/detail-764390.html

到了这里,关于路径规划A*(A-Star)算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【多机器人】基于A_Star算法实现多机器人路径规划附Matlab代码

     ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进, 代码获取、论文复现及科研仿真合作可私信。 🍎个人主页:Matlab科研工作室 🍊个人信条:格物致知。 更多Matlab完整代码及仿真定制内容点击👇 智能优化算法       神经网络预测       雷达通信    

    2024年02月04日
    浏览(53)
  • 【算法与数据结构】62、LeetCode不同路径

    所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。    思路分析 :机器人只能向下或者向右移动,那么到达(i,j)位置的路径和(i-1,j)以及(i,j-1)有关。那么我们就得到的动态规划的表达式 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] dp[i][

    2024年01月18日
    浏览(68)
  • 【算法与数据结构】112、LeetCode路径总和

    所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。    思路分析 :本题通过计算根节点到叶子节点路径上节点的值之和,然后再对比目标值。利用文章【算法和数据结构】257、LeetCode二叉树的所有路径中的递归算法。 这里要注意,默认路径之和是

    2024年02月11日
    浏览(54)
  • 路径优化算法 | 基于A_Star算法实现复杂地形下无人机威胁概率地图最短路径避障三维航迹规划

    A* (A-Star) 算法是一种广泛使用的路径搜索和图形遍历算法,用于在给定起点和终点的情况下找到最短路径。对于无人机在复杂地形下的三维航迹规划,A* 算法可以与其他技术结合,例如威胁概率地图(Threat Probability Map),以实现避障和最短路径规划。 以下是一个基于 A* 算法

    2024年04月08日
    浏览(83)
  • 数据结构与算法-动态规划

    (我猜是做的多了背的题多了就自然懂了) 迭代法一般没有通用去重方式,因为已经相当于递归去重后了 这两个问题其实是一个问题,一般直接写出的没有去重的递归法,复杂度很高,此时需要使用备忘录去重,而备忘录去重时间复杂度和使用dp数组进行迭代求解时间复杂度相同

    2024年02月04日
    浏览(46)
  • 【算法与数据结构】63、LeetCode不同路径 II

    所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。    思路分析 :参考【算法与数据结构】62、LeetCode不同路径的题目,可以发现本题仅仅是多了障碍物。我们还是用动态规划来做。有障碍物的地方无法到达,因此路径数量为0,只需要将障碍物位

    2024年02月02日
    浏览(57)
  • python算法与数据结构---动态规划

    记不住过去的人,注定要重蹈覆辙。 对于一个模型为n的问题,将其分解为k个规模较小的子问题(阶段),按顺序求解子问题,前一子问题的解,为后一子问题提供有用的信息。在求解任一子问题时,通过决策求得局部最优解,依次解决各子问题。最后通过简单的判断,得到

    2024年02月20日
    浏览(76)
  • 数据结构与算法之贪心&动态规划

            一:思考         1.某天早上公司领导找你解决一个问题,明天公司有N个同等级的会议需要使用同一个会议室,现在给你这个N个会议的开始和结束 时间,你怎么样安排才能使会议室最大利用?即安排最多场次的会议?电影的话 那肯定是最多加票价最高的,入场

    2024年02月09日
    浏览(47)
  • 数据结构与算法 | 动态规划算法(Dynamic Programming)

    上一篇文末已经提到了记忆化搜索是动态规划(Dynamic Programming)的一种形式,是一种自顶向下(Top-Down)的思考方式,通常采用递归的编码形式;既然动态规划有自顶向下(Top-Down)的递归形式,自然想到对应的另外一种思考方式 自底向上( Bottom-Up ) ,也就是本篇要写的内

    2024年02月05日
    浏览(46)
  • Matlab无人机三维路径规划|基于A_Star算法实现复杂地形下无人机威胁概率地图最短路径避障三维航迹规划研究

     ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,代码获取、论文复现及科研仿真合作可私信。 🍎个人主页:Matlab科研工作室 🍊个人信条:格物致知。 更多Matlab完整代码及仿真定制内容点击👇 智能优化算法       神经网络预测       雷达通信       无

    2024年04月16日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包