游戏AI实现-寻路算法(A*)

A*(A-star)是一种图遍历和寻路算法,由于其完整性、最优性和最佳效率,它被用于计算机科学的许多领域。给定一个加权图、一个源节点和一个目标节点,该算法将找到从源到目标的最短路径(相对于给定的权重)。

算法过程:遍历方向为从竖直向上沿顺时针方向。

1.首先计算开始节点的G,H,F值,将开始节点放入检测列表中。

2.将检测列表中的所有点按到目标所需的成本的估计值F排序,选择F最小的节点作为当前节点。

3.将当前点从检测列表中移除,加入到已检测列表中。

4.计算当前点周围的八个点G,H,F值,将不包含在检测列表中的点加入到检测列表。

5.重复2,3,4,直到找到目标点。

注:

F = g (n)+ h(n)

gn ) 是从起始节点到 n 的路径的成本,hn) 是一个启发式函数,用于估计从 n 到目标的最便宜路径的成本。

代码实现:

改造路径点数据类:

cs 复制代码
public class DataNode
{
    public Vector2Int pos;
    public DataNode parent;

    //A*使用
    public int gCost = 999999999;
    public int hCost;
    public int fCost;

    public DataNode(Vector2Int pos, DataNode parent)
    {
        this.pos = pos;
        this.parent = parent;
    }
    
    //A*使用计算F
    public void CalculateFCost()
    {
        fCost = gCost + hCost;
    }
}

算法类:

cs 复制代码
public class AStar : FindPathAlgorithm
{
    public AStar(int[,] mapData, int xCount, int zCount) : base(mapData, xCount, zCount){}

    public override List<Vector2Int> FindPath(Vector2Int startPos, Vector2Int goalPos)
    {
        DataNode dataNode = this.AStarFind(startPos, goalPos);
        if (dataNode == null)
        {
            Debug.LogError("寻路有误,请检查参数是否正确");
            return null;
        }
        return Utils.GetPath(dataNode);
    }
    
    DataNode AStarFind(Vector2Int startPos, Vector2Int goalPos)
    {
        //存储要检测的点
        List<DataNode> frontier = new List<DataNode>();
        //存储已经检测的点
        List<Vector2Int> reached = new List<Vector2Int>();

        DataNode startNode = new DataNode(startPos,null);
        startNode.gCost = 0;
        startNode.hCost = CalculateDistanceCost(startPos, goalPos);
        startNode.CalculateFCost();
        frontier.Add(startNode);

        while (frontier.Count > 0)
        {
            DataNode currentNode = GetLowestFCostNode(frontier);
            if (currentNode.pos == goalPos)
            {
                return new DataNode(goalPos, currentNode.parent);
            }

            frontier.Remove(currentNode);
            reached.Add(currentNode.pos);

            List<DataNode> neighbors = GetNeighbors(currentNode.pos, reached);
            foreach (DataNode neighbourNode in neighbors)
            {
                int tentativeGCost = currentNode.gCost + CalculateDistanceCost(currentNode.pos, neighbourNode.pos);
                if (tentativeGCost < neighbourNode.gCost)
                {
                    neighbourNode.parent = currentNode;
                    neighbourNode.gCost = tentativeGCost;
                    neighbourNode.hCost = CalculateDistanceCost(neighbourNode.pos, goalPos);
                    neighbourNode.CalculateFCost();

                    if (!frontier.Contains(neighbourNode))
                    {
                        frontier.Add(neighbourNode);
                    }
                }
            }
        }
        return null;
    }

    List<DataNode> GetNeighbors(Vector2Int current, List<Vector2Int> reached)
    {
        List<DataNode> neighbors = new List<DataNode>();
        for (int i = 0; i < Utils.pointDir.Count; i++)
        {
            Vector2Int neighbor = current + Utils.pointDir[i];
            if (this.IsCanAdd(neighbor, reached))
            {
                neighbors.Add(new DataNode(neighbor,null));
            }
        }
        return neighbors;
    }

    bool IsCanAdd(Vector2Int current, List<Vector2Int> reached)
    {
        if (reached.Contains(current))
            return false;
        if (current.x >= 0 && current.y >= 0 && current.x < xCount && current.y < zCount)
        {
            //如果是障碍物,则不能被Add
            if (this.mapData[current.y, current.x] == 1)
            {
                return false;
            }
            return true;
        }
        return false;
    }

    private int CalculateDistanceCost(Vector2Int a, Vector2Int b)
    {
        return Mathf.Abs(a.x - b.x) + Mathf.Abs(a.y - b.y);
    }

    private DataNode GetLowestFCostNode(List<DataNode> pathNodeList)
    {
        DataNode lowestFCostNode = pathNodeList[0];
        for (int i = 1; i < pathNodeList.Count; i++)
        {
            if (pathNodeList[i].fCost < lowestFCostNode.fCost)
            {
                lowestFCostNode = pathNodeList[i];
            }
        }
        return lowestFCostNode;
    }
}

结果:

参考链接:

A* 算法简介 (redblobgames.com)

A* 搜索算法 - 维基百科,自由的百科全书 (wikipedia.org)

A* Pathfinding (E01: algorithm explanation) - YouTube

相关推荐
天人合一peng4 小时前
unity 生成标记根据背景色标记变色
unity·游戏引擎
天人合一peng8 小时前
unity 生成标记根据背景色变色为明显的颜色
unity·游戏引擎
魔士于安8 小时前
Unity 超市总动员 超市收银台 超市货架 超市购物手推车 超市常见商品
游戏·unity·游戏引擎·贴图·模型
CandyU29 小时前
Unity —— 数据持久化
unity·游戏引擎
zh路西法9 小时前
【Unity实现Oneshot胶卷显形】游戏窗口化与Win32API的使用
游戏·unity·游戏引擎
迪捷软件10 小时前
显控系统虚拟仿真的工程化路径
游戏引擎·cocos2d
凡情13 小时前
android隐私合规检测
android·unity
小贺儿开发13 小时前
Unity3D 本地 Stable Diffusion 文生图效果演示
人工智能·unity·stable diffusion·文生图·ai绘画·本地化
Swift社区14 小时前
传统游戏引擎 vs 鸿蒙 System 架构
架构·游戏引擎·harmonyos
mxwin1 天前
Unity Shader 半透明物体为什么不能写入深度缓冲?
unity·游戏引擎·shader