游戏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)

g (n ) 是从起始节点到 n 的路径的成本,h (n) 是一个启发式函数,用于估计从 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

相关推荐
BuHuaX1 小时前
Lua 与 ToLua:运行机制及热更新原理
开发语言·unity·junit·c#·lua
Solange__1 天前
在线3D预览器、Blender和游戏引擎怎么选?按5类任务比较格式、隐私与编辑性
人工智能·游戏·3d·游戏引擎·blender·1024程序员节·关卡设计
peter67681 天前
unity2d游戏开发经验总结
unity
郝学胜-神的一滴1 天前
游戏设计:原型与开发 19:U3D工位布置与性格说明书
人工智能·算法·unity·unreal engine·游戏策划·游戏设计
Aman19842 天前
Claude Code做Unity项目移植(二): 自动执行只读操作,告别频繁的
unity·游戏开发·vibe coding·claude code
暴走约伯2 天前
【VFX工具链源码拆解 02】告别机械劳动(上):一键统改百个子粒子颜色与批量重命名
3d·unity·c#·材质
郝学胜-神的一滴2 天前
游戏设计:原型与开发 18:Unity入门的第一课
人工智能·程序人生·游戏·ui·unity·游戏引擎
淡海水2 天前
09-01-内存-Unity资源生命周期全景
unity·c#·游戏引擎·.netcore·gc
Solange__2 天前
AI世界模型、3D场景生成和游戏引擎怎么选?按5类任务比较交互、物理与导出
开发语言·人工智能·游戏·平面·3d·自然语言处理·游戏引擎
LF男男2 天前
Flower Defense—UIFacade
unity